aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Lewis <22850972+BradLewis@users.noreply.github.com>2025-08-02 22:05:23 -0400
committerBrad Lewis <22850972+BradLewis@users.noreply.github.com>2025-08-02 22:12:52 -0400
commitc18c06ff176fb4e2188b7aeff53120dd533e7ab3 (patch)
treef4b1f09be7e8566da19bee119a1e103aadc53945
parentd86b093c6e0623ec7ced3bbd6cf5970926a8a0ab (diff)
Correctly resolve comp lit implicit values when using nested structs and not naming the fields
-rw-r--r--src/server/completion.odin73
-rw-r--r--tests/completions_test.odin36
2 files changed, 86 insertions, 23 deletions
diff --git a/src/server/completion.odin b/src/server/completion.odin
index 16662fe..4c39d04 100644
--- a/src/server/completion.odin
+++ b/src/server/completion.odin
@@ -1054,29 +1054,7 @@ get_implicit_completion :: proc(
if s, ok := comp_symbol.value.(SymbolStructValue); ok {
set_ast_package_set_scoped(ast_context, comp_symbol.pkg)
- //We can either have the final
- elem_index := -1
-
- for elem, i in comp_lit.elems {
- if position_in_node(elem, position_context.position) {
- elem_index = i
- }
- }
-
- type: ^ast.Expr
-
- for name, i in s.names {
- if name != field_name {
- continue
- }
-
- type = s.types[i]
- break
- }
-
- if type == nil && len(s.types) > elem_index && elem_index != -1 {
- type = s.types[elem_index]
- }
+ type := get_struct_comp_lit_type(position_context, comp_lit, s, field_name)
if enum_value, ok := unwrap_enum(ast_context, type); ok {
for enum_name in enum_value.names {
@@ -1359,6 +1337,55 @@ get_implicit_completion :: proc(
return is_incomplete
}
+get_struct_comp_lit_type :: proc(
+ position_context: ^DocumentPositionContext,
+ comp_lit: ^ast.Comp_Lit,
+ s: SymbolStructValue,
+ field_name: string,
+) -> ^ast.Expr {
+ elem_index := -1
+
+ for elem, i in comp_lit.elems {
+ if position_in_node(elem, position_context.position) {
+ elem_index = i
+ if field_value, ok := elem.derived.(^ast.Field_Value); ok {
+ // If our field is another comp_lit, check to see if we're actually in that one
+ if cl, ok := field_value.value.derived.(^ast.Comp_Lit); ok {
+ if type := get_struct_comp_lit_type(
+ position_context,
+ cl,
+ s,
+ field_name,
+ ); type != nil {
+ return type
+ }
+ }
+ }
+ }
+ }
+
+ if elem_index == -1 {
+ return nil
+ }
+
+ type: ^ast.Expr
+
+ for name, i in s.names {
+ if name != field_name {
+ continue
+ }
+
+ type = s.types[i]
+ break
+ }
+
+ if type == nil && len(s.types) > elem_index && elem_index != -1 {
+ type = s.types[elem_index]
+ }
+
+ return type
+}
+
get_identifier_completion :: proc(
ast_context: ^AstContext,
position_context: ^DocumentPositionContext,
diff --git a/tests/completions_test.odin b/tests/completions_test.odin
index a984cb5..148252d 100644
--- a/tests/completions_test.odin
+++ b/tests/completions_test.odin
@@ -4223,3 +4223,39 @@ ast_completion_multiple_chained_call_expr :: proc(t: ^testing.T) {
}
test.expect_completion_docs( t, &source, "", {"Bazz.bazz: string"})
}
+
+@(test)
+ast_completion_nested_struct_with_enum_fields_unnamed :: proc(t: ^testing.T) {
+ source := test.Source {
+ main = `package test
+ Foo1 :: enum {
+ A, B,
+ }
+
+ Foo2 :: enum {
+ C, D,
+ }
+
+ Foo3 :: struct {
+ foo3: string,
+ }
+
+ Bar :: struct {
+ foo1: Foo1,
+ foo2: Foo2,
+ foo3: Foo3,
+ }
+
+ Bazz :: struct {
+ bar: Bar,
+ }
+
+ main :: proc() {
+ bazz := Bazz {
+ bar = {.A, .{*}, {}}
+ }
+ }
+ `,
+ }
+ test.expect_completion_docs( t, &source, "", {"C", "D"}, {"A", "B"})
+}