aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/analysis.odin49
-rw-r--r--tests/hover_test.odin116
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