diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2024-11-17 13:48:59 +0100 |
|---|---|---|
| committer | DanielGavin <danielgavin5@hotmail.com> | 2024-11-17 13:48:59 +0100 |
| commit | c5d22e5e4a703f8e19770862cf4c52a4140bf801 (patch) | |
| tree | 2acfcfbf158cc81c59cbde297661ebf483fad843 | |
| parent | cfe49c86af90dc4ce7d1e78bec82961521ad29af (diff) | |
Add support for call expression "range" loops with custom iterators and non
| -rw-r--r-- | src/server/analysis.odin | 94 | ||||
| -rw-r--r-- | tests/completions_test.odin | 25 |
2 files changed, 118 insertions, 1 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 630f4a1..189bf95 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -3112,8 +3112,100 @@ get_locals_for_range_stmt :: proc( } } - if symbol, ok := resolve_type_expression(ast_context, stmt.expr); ok { + symbol, ok := resolve_type_expression(ast_context, stmt.expr) + + if v, ok := symbol.value.(SymbolProcedureValue); ok { + //Not quite sure how the custom iterator is defined, but it seems that it's three arguments. So temporarily just assume three arguments are iterators. + if len(v.return_types) != 3 && len(v.return_types) != 0 { + if v.return_types[0].type != nil { + symbol, ok = resolve_type_expression(ast_context, v.return_types[0].type) + } else if v.return_types[0].default_value != nil { + symbol, ok = resolve_type_expression(ast_context, v.return_types[0].default_value) + } + } + } + + if ok { #partial switch v in symbol.value { + case SymbolProcedureValue: + //This can only be custom iterators + if len(stmt.vals) >= 1 { + if ident, ok := unwrap_ident(stmt.vals[0]); ok { + expr: ^ast.Expr + + if v.return_types[0].type != nil { + expr = v.return_types[0].type + } else if v.return_types[0].default_value != nil { + expr = v.return_types[0].default_value + } + + store_local( + ast_context, + ident, + expr, + ident.pos.offset, + ident.name, + ast_context.local_id, + ast_context.non_mutable_only, + false, + true, + symbol.pkg, + false, + ) + } + } + + if len(stmt.vals) >= 2 { + if ident, ok := unwrap_ident(stmt.vals[1]); ok { + expr: ^ast.Expr + + if v.return_types[1].type != nil { + expr = v.return_types[1].type + } else if v.return_types[1].default_value != nil { + expr = v.return_types[1].default_value + } + + store_local( + ast_context, + ident, + expr, + ident.pos.offset, + ident.name, + ast_context.local_id, + ast_context.non_mutable_only, + false, + true, + symbol.pkg, + false, + ) + } + } + + if len(stmt.vals) >= 3 { + if ident, ok := unwrap_ident(stmt.vals[2]); ok { + expr: ^ast.Expr + + if v.return_types[2].type != nil { + expr = v.return_types[2].type + } else if v.return_types[2].default_value != nil { + expr = v.return_types[2].default_value + } + + store_local( + ast_context, + ident, + expr, + ident.pos.offset, + ident.name, + ast_context.local_id, + ast_context.non_mutable_only, + false, + true, + symbol.pkg, + false, + ) + } + } case SymbolUntypedValue: if len(stmt.vals) == 1 { if ident, ok := unwrap_ident(stmt.vals[0]); ok { diff --git a/tests/completions_test.odin b/tests/completions_test.odin index f25fba5..e523592 100644 --- a/tests/completions_test.odin +++ b/tests/completions_test.odin @@ -655,6 +655,31 @@ ast_for_in_identifier_completion :: proc(t: ^testing.T) { } @(test) +ast_for_in_call_expr_completion :: proc(t: ^testing.T) { + source := test.Source { + main = `package test + Step :: struct { + data: int, + } + + main :: proc() { + list :: proc() -> []Step { + return nil + } + for zstep in list() { + zst{*} + } + } + `, + packages = {}, + } + + + test.expect_completion_details(t, &source, ".", {"test.zstep: Step"}) +} + + +@(test) ast_completion_poly_struct_proc :: proc(t: ^testing.T) { source := test.Source { main = `package test |