aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBradley Lewis <22850972+BradLewis@users.noreply.github.com>2025-09-16 18:13:03 -0400
committerGitHub <noreply@github.com>2025-09-16 18:13:03 -0400
commitc3195c07d4756219bb01f5815bd5e76285f959d9 (patch)
treeac608f57e916ab461cc3c3334b76b9b53cf98ee0
parentc188c31e0eb9d4465346e337e9c8813b2cea6fd4 (diff)
parenta31f9f0a97f543f51ca49a268f94c5078c9b9661 (diff)
Merge pull request #1020 from BradLewis/feat/variadic-arg-improvements
Feat/variadic arg improvements
-rw-r--r--src/server/analysis.odin10
-rw-r--r--src/server/generics.odin32
-rw-r--r--src/server/position_context.odin31
-rw-r--r--src/server/type_definition.odin2
-rw-r--r--tests/hover_test.odin64
5 files changed, 120 insertions, 19 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin
index 570a035..856f0ae 100644
--- a/src/server/analysis.odin
+++ b/src/server/analysis.odin
@@ -1124,7 +1124,15 @@ internal_resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Ex
case ^Helper_Type:
return internal_resolve_type_expression(ast_context, v.type, out)
case ^Ellipsis:
- return internal_resolve_type_expression(ast_context, v.expr, out)
+ out.range = common.get_token_range(v.node, ast_context.file.src)
+ out.type = .Type
+ out.pkg = get_package_from_node(v.node)
+ out.name = ast_context.field_name.name
+ out.uri = common.create_uri(v.pos.file, ast_context.allocator).uri
+ out.value = SymbolSliceValue {
+ expr = v.expr,
+ }
+ return true
case ^Implicit:
ident := new_type(Ident, v.node.pos, v.node.end, ast_context.allocator)
ident.name = v.tok.text
diff --git a/src/server/generics.odin b/src/server/generics.odin
index cec9926..374ffc9 100644
--- a/src/server/generics.odin
+++ b/src/server/generics.odin
@@ -63,7 +63,8 @@ resolve_poly :: proc(
if ident, ok := unwrap_ident(type); ok {
call_node_id := reflect.union_variant_typeid(call_node.derived)
specialization_id := reflect.union_variant_typeid(specialization.derived)
- if call_node_id == specialization_id {
+ if ast_context.position_hint == .TypeDefinition && call_node_id == specialization_id {
+ // TODO: Fix this so it doesn't need to be aware that we're in a type definition
// if the specialization type matches the type of the parameter passed to the proc
// we store that rather than the specialization so we can follow it correctly
// for things like `textDocument/typeDefinition`
@@ -207,6 +208,26 @@ resolve_poly :: proc(
return found
}
+ case ^ast.Ellipsis:
+ if call_array, ok := call_node.derived.(^ast.Array_Type); ok {
+ found := false
+
+ if array_is_soa(call_array^) {
+ return false
+ }
+
+ if poly_type, ok := p.expr.derived.(^ast.Poly_Type); ok {
+ if ident, ok := unwrap_ident(poly_type.type); ok {
+ save_poly_map(ident, call_array.elem, poly_map)
+ }
+
+ if poly_type.specialization != nil {
+ return resolve_poly(ast_context, call_array.elem, call_symbol, p.expr, poly_map)
+ }
+ found |= true
+ }
+ return found
+ }
case ^ast.Map_Type:
if call_map, ok := call_node.derived.(^ast.Map_Type); ok {
found := false
@@ -425,6 +446,12 @@ find_and_replace_poly_type :: proc(expr: ^ast.Expr, poly_map: ^map[string]^ast.E
}
}
}
+ case ^ast.Ellipsis:
+ if expr, ok := get_poly_map(v.expr, poly_map); ok {
+ v.expr = expr
+ v.pos.file = expr.pos.file
+ v.end.file = expr.end.file
+ }
}
return visitor
@@ -500,6 +527,9 @@ resolve_generic_function_symbol :: proc(
ast_context.current_package = ast_context.document_package
if symbol, ok := resolve_type_expression(ast_context, call_expr.args[i]); ok {
+ if ident, ok := call_expr.args[i].derived.(^ast.Ident); ok && symbol.name == "" {
+ symbol.name = ident.name
+ }
file := strings.trim_prefix(symbol.uri, "file://")
if file == "" {
diff --git a/src/server/position_context.odin b/src/server/position_context.odin
index d5e7d33..f3f2f68 100644
--- a/src/server/position_context.odin
+++ b/src/server/position_context.odin
@@ -14,6 +14,7 @@ DocumentPositionContextHint :: enum {
SignatureHelp,
Definition,
Hover,
+ TypeDefinition,
}
DocumentPositionContext :: struct {
@@ -629,27 +630,25 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP
get_document_position(n.expr, position_context)
get_document_position(n.args, position_context)
case ^Selector_Call_Expr:
- if position_context.hint == .Definition ||
- position_context.hint == .Hover ||
- position_context.hint == .SignatureHelp ||
- position_context.hint == .Completion {
- position_context.selector = n.expr
- position_context.field = n.call
- position_context.selector_expr = node
+ position_context.selector = n.expr
+ position_context.field = n.call
+ position_context.selector_expr = node
- if _, ok := n.call.derived.(^ast.Call_Expr); ok {
- position_context.call = n.call
- }
+ if _, ok := n.call.derived.(^ast.Call_Expr); ok {
+ position_context.call = n.call
+ }
- get_document_position(n.expr, position_context)
- get_document_position(n.call, position_context)
+ get_document_position(n.expr, position_context)
+ get_document_position(n.call, position_context)
- if position_context.hint == .SignatureHelp {
- position_context.arrow = true
- }
+ if position_context.hint == .SignatureHelp {
+ position_context.arrow = true
}
case ^Selector_Expr:
- if position_context.hint == .Definition || position_context.hint == .Hover && n.field != nil {
+ if (position_context.hint == .Definition ||
+ position_context.hint == .Hover ||
+ position_context.hint == .TypeDefinition) &&
+ n.field != nil {
position_context.selector = n.expr
position_context.field = n.field
position_context.selector_expr = node
diff --git a/src/server/type_definition.odin b/src/server/type_definition.odin
index 84d1f1a..532bfe9 100644
--- a/src/server/type_definition.odin
+++ b/src/server/type_definition.odin
@@ -27,7 +27,7 @@ get_type_definition_locations :: proc(document: ^Document, position: common.Posi
uri: string
locations := make([dynamic]common.Location, context.temp_allocator)
- position_context, ok := get_document_position_context(document, position, .Definition)
+ position_context, ok := get_document_position_context(document, position, .TypeDefinition)
if !ok {
log.warn("Failed to get position context")
diff --git a/tests/hover_test.odin b/tests/hover_test.odin
index 37d0362..3f6bb3b 100644
--- a/tests/hover_test.odin
+++ b/tests/hover_test.odin
@@ -4738,6 +4738,70 @@ ast_hover_proc_group_parapoly_matrix :: proc(t: ^testing.T) {
}
test.expect_hover(t, &source, "test.c: matrix[3,2]int")
}
+
+@(test)
+ast_hover_proc_group_variadic_args :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package test
+ append_elems :: proc(array: ^$T/[dynamic]string, args: ..string) {}
+ append_elem :: proc(array: ^$T/[dynamic]string, arg: string) {}
+
+ append :: proc {
+ append_elem,
+ append_elems,
+ }
+
+ main :: proc() {
+ foos: [dynamic]string
+ bars: [dynamic]string
+ app{*}end(&bars, ..foos[:])
+ }
+ `,
+ }
+ test.expect_hover(t, &source, "test.append: proc(array: ^$T/[dynamic]string, args: ..string)")
+}
+
+@(test)
+ast_hover_proc_group_variadic_args_with_generic_type :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package test
+ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E) {}
+ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E) {}
+
+ append :: proc {
+ append_elem,
+ append_elems,
+ }
+
+ main :: proc() {
+ foos: [dynamic]string
+ bars: [dynamic]string
+ app{*}end(&bars, ..foos[:])
+ }
+ `,
+ }
+ test.expect_hover(t, &source, "test.append: proc(array: ^$T/[dynamic]$E, args: ..E)")
+}
+
+@(test)
+ast_hover_proc_group_with_generic_type_from_proc_param :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package test
+ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E) {}
+ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E) {}
+
+ append :: proc {
+ append_elem,
+ append_elems,
+ }
+
+ foo :: proc(bars: ^[dynamic]string) {
+ app{*}end(bars, "test")
+ }
+ `,
+ }
+ test.expect_hover(t, &source, "test.append: proc(array: ^$T/[dynamic]$E, arg: E)")
+}
/*
Waiting for odin fix