diff options
| -rw-r--r-- | src/server/analysis.odin | 56 | ||||
| -rw-r--r-- | src/server/ast.odin | 6 | ||||
| -rw-r--r-- | src/server/build.odin | 55 | ||||
| -rw-r--r-- | src/server/collector.odin | 1 | ||||
| -rw-r--r-- | src/server/completion.odin | 8 | ||||
| -rw-r--r-- | src/server/generics.odin | 11 | ||||
| -rw-r--r-- | src/server/symbol.odin | 6 | ||||
| -rw-r--r-- | tests/hover_test.odin | 69 |
8 files changed, 193 insertions, 19 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 1e570b4..8e1d7f0 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -340,25 +340,43 @@ are_symbol_basic_same_keywords :: proc(a, b: Symbol) -> bool { if are_keyword_aliases(a.name, b.name) { return true } - if a.name != b.name { + a_value, a_ok := a.value.(SymbolBasicValue) + if !a_ok { return false } - if _, ok := a.value.(SymbolBasicValue); !ok { + + b_value, b_ok := b.value.(SymbolBasicValue) + if !b_ok { return false } - if _, ok := b.value.(SymbolBasicValue); !ok { + if a_value.ident.name != b_value.ident.name { return false } - if _, ok := keyword_map[a.name]; !ok { + if _, ok := keyword_map[a_value.ident.name]; !ok { return false } - if _, ok := keyword_map[b.name]; !ok { + if _, ok := keyword_map[b_value.ident.name]; !ok { return false } return true } +is_valid_nil_symbol :: proc(symbol: Symbol) -> bool { + if symbol.pointers > 0 { + return true + } + + #partial switch v in symbol.value { + case SymbolMapValue, SymbolSliceValue, SymbolProcedureValue, SymbolDynamicArrayValue: + return true + case SymbolUnionValue: + return v.kind != .no_nil + } + + return false +} + is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: Symbol, flags: ast.Field_Flags = {}) -> bool { // In order to correctly equate the symbols for overloaded functions, we need to check both directions if same, ok := are_symbol_untyped_basic_same_typed(a, b); ok { @@ -718,6 +736,7 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou call_symbol: Symbol arg_symbol: Symbol ok: bool + is_call_arg_nil: bool if _, ok = call_arg.derived.(^ast.Bad_Expr); ok { continue @@ -726,9 +745,14 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou //named parameter if field, is_field := call_arg.derived.(^ast.Field_Value); is_field { named = true - call_symbol, ok = resolve_call_arg_type_expression(ast_context, field.value) - if !ok { - break next_fn + if ident, is_ident := field.field.derived.(^ast.Ident); is_ident && ident.name == "nil" { + is_call_arg_nil = true + ok = true + } else { + call_symbol, ok = resolve_call_arg_type_expression(ast_context, field.value) + if !ok { + break next_fn + } } if ident, is_ident := field.field.derived.(^ast.Ident); is_ident { @@ -744,7 +768,12 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou log.error("Expected name parameter after starting named parmeter phase") return {}, false } - call_symbol, ok = resolve_call_arg_type_expression(ast_context, call_arg) + if ident, is_ident := call_arg.derived.(^ast.Ident); is_ident && ident.name == "nil" { + is_call_arg_nil = true + ok = true + } else { + call_symbol, ok = resolve_call_arg_type_expression(ast_context, call_arg) + } } if !ok { @@ -783,6 +812,15 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou break next_fn } + if is_call_arg_nil { + if is_valid_nil_symbol(arg_symbol) { + continue + } else { + break next_fn + } + + } + if !is_symbol_same_typed(ast_context, call_symbol, arg_symbol, proc_arg.flags) { found := false // Are we a union variant diff --git a/src/server/ast.odin b/src/server/ast.odin index edb9007..5548c23 100644 --- a/src/server/ast.odin +++ b/src/server/ast.odin @@ -527,11 +527,13 @@ collect_when_body :: proc( } collect_globals :: proc(file: ast.File) -> []GlobalExpr { + file_tags := parser.parse_file_tags(file, context.temp_allocator) + if !should_collect_file(file_tags) { + return {} + } exprs := make([dynamic]GlobalExpr, context.temp_allocator) defer shrink(&exprs) - file_tags := parser.parse_file_tags(file, context.temp_allocator) - for decl in file.decls { if value_decl, ok := decl.derived.(^ast.Value_Decl); ok { collect_value_decl(&exprs, file, file_tags, decl, {}) diff --git a/src/server/build.odin b/src/server/build.odin index 24e109d..a0ba276 100644 --- a/src/server/build.odin +++ b/src/server/build.odin @@ -34,7 +34,7 @@ platform_os: map[string]struct{} = { } -os_enum_to_string: map[runtime.Odin_OS_Type]string = { +os_enum_to_string: [runtime.Odin_OS_Type]string = { .Windows = "windows", .Darwin = "darwin", .Linux = "linux", @@ -43,11 +43,28 @@ os_enum_to_string: map[runtime.Odin_OS_Type]string = { .WASI = "wasi", .JS = "js", .Freestanding = "freestanding", - .JS = "wasm", .Haiku = "haiku", .OpenBSD = "openbsd", .NetBSD = "netbsd", - .FreeBSD = "freebsd", + .Orca = "orca", + .Unknown = "unknown", +} + +os_string_to_enum: map[string]runtime.Odin_OS_Type = { + "Windows" = .Windows, + "Darwin" = .Darwin, + "Linux" = .Linux, + "Essence" = .Essence, + "Freebsd" = .FreeBSD, + "Wasi" = .WASI, + "Js" = .JS, + "Freestanding" = .Freestanding, + "Wasm" = .JS, + "Haiku" = .Haiku, + "Openbsd" = .OpenBSD, + "Netbsd" = .NetBSD, + "Orca" = .Orca, + "Unknown" = .Unknown, } @(private = "file") @@ -90,6 +107,38 @@ skip_file :: proc(filename: string) -> bool { return false } +should_collect_file :: proc(file_tags: parser.File_Tags) -> bool { + if file_tags.ignore { + return false + } + + if len(file_tags.build) > 0 { + when_expr_map := make(map[string]When_Expr, context.temp_allocator) + + for key, value in common.config.profile.defines { + when_expr_map[key] = resolve_when_ident(when_expr_map, value) or_continue + } + + if when_expr, ok := resolve_when_ident(when_expr_map, "ODIN_OS"); ok { + if s, ok := when_expr.(string); ok { + if used_os, ok := os_string_to_enum[when_expr.(string)]; ok { + found := false + for tag in file_tags.build { + if used_os in tag.os { + found = true + break + } + } + if !found { + return false + } + } + } + } + } + return true +} + try_build_package :: proc(pkg_name: string) { if pkg, ok := build_cache.loaded_pkgs[pkg_name]; ok { return diff --git a/src/server/collector.odin b/src/server/collector.odin index 607521e..bd6d040 100644 --- a/src/server/collector.odin +++ b/src/server/collector.odin @@ -666,6 +666,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri case ^ast.Basic_Lit: token = v^ symbol.value = collect_generic(collection, col_expr, package_map, uri) + token_type = .Unresolved case ^ast.Ident: token = v^ symbol.value = collect_generic(collection, col_expr, package_map, uri) diff --git a/src/server/completion.odin b/src/server/completion.odin index 38b5cbe..75bec86 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -2271,14 +2271,14 @@ get_expression_string_from_position_context :: proc(position_context: ^DocumentP } - if position_context.field != nil { - return src[position_context.field.pos.offset:position_context.field.end.offset] - } - if position_context.selector != nil { return src[position_context.selector.pos.offset:position_context.selector.end.offset] } + if position_context.field != nil { + return src[position_context.field.pos.offset:position_context.field.end.offset] + } + return "" } diff --git a/src/server/generics.odin b/src/server/generics.odin index 374ffc9..6f0be73 100644 --- a/src/server/generics.odin +++ b/src/server/generics.odin @@ -452,6 +452,17 @@ find_and_replace_poly_type :: proc(expr: ^ast.Expr, poly_map: ^map[string]^ast.E v.pos.file = expr.pos.file v.end.file = expr.end.file } + case ^ast.Map_Type: + if expr, ok := get_poly_map(v.key, poly_map); ok { + v.key = expr + v.pos.file = expr.pos.file + v.end.file = expr.end.file + } + if expr, ok := get_poly_map(v.value, poly_map); ok { + v.value = expr + v.pos.file = expr.pos.file + v.end.file = expr.end.file + } } return visitor diff --git a/src/server/symbol.odin b/src/server/symbol.odin index 4e6b19f..42e5447 100644 --- a/src/server/symbol.odin +++ b/src/server/symbol.odin @@ -780,7 +780,7 @@ symbol_type_to_completion_kind :: proc(type: SymbolType) -> CompletionItemKind { symbol_kind_to_type :: proc(type: SymbolType) -> SymbolKind { #partial switch type { - case .Function: + case .Function, .Type_Function: return .Function case .Constant: return .Constant @@ -796,6 +796,10 @@ symbol_kind_to_type :: proc(type: SymbolType) -> SymbolKind { return .Key case .Field: return .Field + case .Unresolved: + return .Constant + case .Type: + return .Class case: return .Null } diff --git a/tests/hover_test.odin b/tests/hover_test.odin index 562a2d6..b2af26a 100644 --- a/tests/hover_test.odin +++ b/tests/hover_test.odin @@ -4980,6 +4980,75 @@ ast_hover_proc_impl :: proc(t: ^testing.T) { } test.expect_hover(t, &source, "test.foo :: proc(a: int) -> int") } + +@(test) +ast_hover_proc_overload_generic_map :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {} + clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {} + clear :: proc{ + clear_dynamic_array, + clear_map, + } + main :: proc() { + foo: map[int]string + c{*}lear(&foo) + } + `, + } + test.expect_hover(t, &source, "test.clear :: proc(m: ^$T/map[$K]$V)") +} + +@(test) +ast_hover_proc_overload_basic_type_alias :: proc(t: ^testing.T) { + packages := make([dynamic]test.Package, context.temp_allocator) + + append(&packages, test.Package{pkg = "my_package", source = `package my_package + Bar :: int + `}) + + source := test.Source { + main = `package test + import "my_package" + + foo_int :: proc(i: int) {} + foo_string :: proc(s: string) {} + foo :: proc { + foo_int, + foo_string, + } + + main :: proc() { + bar: my_package.Bar + f{*}oo(bar) + } + `, + packages = packages[:], + } + test.expect_hover(t, &source, "test.foo :: proc(i: int)") +} + +@(test) +ast_hover_proc_overload_nil_pointer :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + import "my_package" + + foo_int :: proc(i: int) {} + foo_ptr :: proc(s: ^string) {} + foo :: proc { + foo_int, + foo_ptr, + } + + main :: proc() { + f{*}oo(nil) + } + `, + } + test.expect_hover(t, &source, "test.foo :: proc(s: ^string)") +} /* Waiting for odin fix |