diff options
| -rw-r--r-- | src/server/analysis.odin | 49 | ||||
| -rw-r--r-- | tests/hover_test.odin | 116 |
2 files changed, 150 insertions, 15 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 1a7e4a7..9311328 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -322,45 +322,54 @@ resolve_type_comp_literal :: proc( return current_symbol, current_comp_lit, true } - -is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: Symbol, flags: ast.Field_Flags = {}) -> bool { - //relying on the fact that a is the call argument to avoid checking both sides for untyped. +// NOTE: This function is not commutative +are_symbol_untyped_basic_same_typed :: proc(a, b: Symbol) -> (bool, bool) { if untyped, ok := a.value.(SymbolUntypedValue); ok { if basic, ok := b.value.(SymbolBasicValue); ok { switch untyped.type { case .Integer: switch basic.ident.name { case "int", "uint", "u32", "i32", "u8", "i8", "u64", "u16", "i16": - return true + return true, true case: - return false + return false, true } case .Bool: switch basic.ident.name { case "bool", "b32", "b64": - return true + return true, true case: - return false + return false, true } case .String: switch basic.ident.name { case "string", "cstring": - return true + return true, true case: - return false + return false, true } case .Float: switch basic.ident.name { case "f32", "f64": - return true + return true, true case: - return false + return false, true } } } else if untyped_b, ok := b.value.(SymbolUntypedValue); ok { - return untyped.type == untyped_b.type + return untyped.type == untyped_b.type, true } } + return false, 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 { + return same + } else if same, ok := are_symbol_untyped_basic_same_typed(b, a); ok { + return same + } a_id := reflect.union_variant_typeid(a.value) b_id := reflect.union_variant_typeid(b.value) @@ -649,7 +658,7 @@ 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_type_expression(ast_context, field.value) + call_symbol, ok = resolve_call_arg_type_expression(ast_context, field.value) if !ok { break next_fn } @@ -667,7 +676,7 @@ 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_type_expression(ast_context, call_arg) + call_symbol, ok = resolve_call_arg_type_expression(ast_context, call_arg) } if !ok { @@ -678,7 +687,7 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou if len(p.return_types) != 1 { break next_fn } - if s, ok := resolve_type_expression(ast_context, p.return_types[0].type); ok { + if s, ok := resolve_call_arg_type_expression(ast_context, p.return_types[0].type); ok { call_symbol = s } } @@ -729,6 +738,16 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou return Symbol{}, false } +resolve_call_arg_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (Symbol, bool) { + old_current_package := ast_context.current_package + ast_context.current_package = ast_context.document_package + defer { + ast_context.current_package = old_current_package + } + + return resolve_type_expression(ast_context, node) +} + resolve_basic_lit :: proc(ast_context: ^AstContext, basic_lit: ast.Basic_Lit) -> (Symbol, bool) { symbol := Symbol { type = .Constant, diff --git a/tests/hover_test.odin b/tests/hover_test.odin index cb46473..fa5127c 100644 --- a/tests/hover_test.odin +++ b/tests/hover_test.odin @@ -946,6 +946,122 @@ ast_hover_empty_line_at_top_of_file :: proc(t: ^testing.T) { test.expect_hover(t, &source, "test.Foo: struct {\n\tbar: int,\n}") } + +@(test) +ast_hover_proc_overloading_arg_with_selector_expr :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + + Foo :: struct { + bar: int, + } + + foo_int :: proc(i: int) {} + foo_string :: proc(s: string) {} + + foo :: proc { + foo_int, + foo_string, + } + + main :: proc(f: Foo) { + fo{*}o(f.bar) + } + ` + } + + test.expect_hover(t, &source, "test.foo: proc(i: int)") +} + +@(test) +ast_hover_proc_overloading_named_arg_with_selector_expr_with_another_package :: proc(t: ^testing.T) { + packages := make([dynamic]test.Package, context.temp_allocator) + + append( + &packages, + test.Package { + pkg = "my_package", + source = `package my_package + foo_none :: proc(x := 1) -> (int, bool) { + return 1, false + } + foo_string :: proc(s: string, x := 1) -> (int, bool) { + return 2, true + } + foo :: proc { + foo_none, + foo_string, + } + ` + }, + ) + source := test.Source { + main = `package test + import "my_package" + + Foo :: struct { + i: int, + } + + main :: proc(f: ^Foo) { + result, ok := my_package.f{*}oo(f.i) + } + `, + packages = packages[:] + } + + test.expect_hover(t, &source, "my_package.foo: proc(x := 1) -> (_: int, _: bool)") +} + +@(test) +ast_hover_proc_overloading_named_arg_with_selector_expr_multiple_packages :: proc(t: ^testing.T) { + packages := make([dynamic]test.Package, context.temp_allocator) + + append( + &packages, + test.Package { + pkg = "my_package", + source = `package my_package + foo_none :: proc(x := 1) -> (int, bool) { + return 1, false + } + foo_string :: proc(s: string, x := 1) -> (int, bool) { + return 2, true + } + foo :: proc { + foo_none, + foo_string, + } + ` + }, + test.Package { + pkg = "my_package2", + source = `package my_package2 + + Bar :: struct { + my_int: int + } + ` + }, + ) + source := test.Source { + main = `package test + import "my_package" + import "my_package2" + + Foo :: struct { + i: int, + } + + main :: proc(bar: ^my_package2.Bar) { + result, ok := my_package.f{*}oo(bar.my_int) + } + `, + packages = packages[:] + } + + test.expect_hover(t, &source, "my_package.foo: proc(x := 1) -> (_: int, _: bool)") +} /* Waiting for odin fix |