aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanielGavin <danielgavin5@hotmail.com>2023-09-01 20:17:57 +0200
committerDanielGavin <danielgavin5@hotmail.com>2023-09-01 20:17:57 +0200
commitc967c9be431cc22b60ed6a100bc3c6beeef6edd7 (patch)
tree16bd0e5c1bab6a73286b8b7ef76ee5c89459c9f0
parenta72ac2941a1a54e05b4051a00ca25b0b3822b1c6 (diff)
Add support for generics in struct that use arrays
-rw-r--r--src/server/analysis.odin76
-rw-r--r--tests/completions_test.odin27
2 files changed, 84 insertions, 19 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin
index d28e7ae..a114b92 100644
--- a/src/server/analysis.odin
+++ b/src/server/analysis.odin
@@ -2271,21 +2271,27 @@ resolve_symbol_return :: proc(
}
case SymbolUnionValue:
if v.poly != nil {
- //Todo(daniel): Maybe change the function to return a new symbol instead of referencing it.
- //resolving the poly union means changing the type, so we do a copy of it.
types := make([dynamic]^ast.Expr, ast_context.allocator)
- append_elems(&types, ..v.types)
+
+ for type in v.types {
+ append(&types, clone_expr(type, context.temp_allocator, nil))
+ }
+
v.types = types[:]
+
resolve_poly_union(ast_context, v.poly, &symbol)
}
return symbol, ok
case SymbolStructValue:
if v.poly != nil {
- //Todo(daniel): Maybe change the function to return a new symbol instead of referencing it.
- //resolving the struct union means changing the type, so we do a copy of it.
types := make([dynamic]^ast.Expr, ast_context.allocator)
- append_elems(&types, ..v.types)
+
+ for type in v.types {
+ append(&types, clone_expr(type, context.temp_allocator, nil))
+ }
+
v.types = types[:]
+
resolve_poly_struct(ast_context, v.poly, &symbol)
}
@@ -3214,24 +3220,56 @@ resolve_poly_struct :: proc(
}
}
- for type, i in symbol_value.types {
- if ident, ok := type.derived.(^ast.Ident); ok {
- if expr, ok := poly_map[ident.name]; ok {
- symbol_value.types[i] = expr
- }
- } else if call_expr, ok := type.derived.(^ast.Call_Expr); ok {
- if call_expr.args == nil {
- continue
- }
+ Visit_Data :: struct {
+ poly_map: map[string]^ast.Expr,
+ symbol_value: ^SymbolStructValue,
+ parent: ^ast.Node,
+ i: int,
+ }
- for arg, i in call_expr.args {
- if ident, ok := arg.derived.(^ast.Ident); ok {
- if expr, ok := poly_map[ident.name]; ok {
- symbol_value.types[i] = expr
+ visit :: proc(visitor: ^ast.Visitor, node: ^ast.Node) -> ^ast.Visitor {
+ if node == nil || visitor == nil {
+ return nil
+ }
+
+ data := cast(^Visit_Data)visitor.data
+
+ if ident, ok := node.derived.(^ast.Ident); ok {
+ if expr, ok := data.poly_map[ident.name]; ok {
+ if data.parent != nil {
+ #partial switch &v in data.parent.derived {
+ case ^ast.Array_Type:
+ v.elem = expr
+ case ^ast.Dynamic_Array_Type:
+ v.elem = expr
}
+ } else {
+ data.symbol_value.types[data.i] = expr
}
}
}
+
+ #partial switch v in node.derived {
+ case ^ast.Array_Type, ^ast.Dynamic_Array_Type, ^ast.Selector_Expr:
+ data.parent = node
+ }
+
+ return visitor
+ }
+
+ for type, i in symbol_value.types {
+ data := Visit_Data {
+ poly_map = poly_map,
+ symbol_value = symbol_value,
+ i = i,
+ }
+
+ visitor := ast.Visitor {
+ data = &data,
+ visit = visit,
+ }
+
+ ast.walk(&visitor, type)
}
}
diff --git a/tests/completions_test.odin b/tests/completions_test.odin
index eba8623..a0f198c 100644
--- a/tests/completions_test.odin
+++ b/tests/completions_test.odin
@@ -2362,3 +2362,30 @@ ast_local_global_function :: proc(t: ^testing.T) {
{"test.my_function_two: proc(one: int)"},
)
}
+
+@(test)
+ast_generic_struct_with_array :: proc(t: ^testing.T) {
+ packages := make([dynamic]test.Package)
+
+ source := test.Source {
+ main = `package main
+ Test :: struct($T: typeid) {
+ values: [32]T,
+ }
+
+ Test_Inner :: struct {
+ a, b, c: int,
+ }
+
+ main :: proc() {
+ test := Test(Test_Inner) {}
+ a := test.values[0]
+ a.{*}
+ }
+
+ `,
+ packages = packages[:],
+ }
+
+ test.expect_completion_details(t, &source, ".", {"Test_Inner.b: int"})
+}