diff options
| author | Bradley Lewis <22850972+BradLewis@users.noreply.github.com> | 2025-08-02 12:34:25 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-02 12:34:25 -0400 |
| commit | 9f72598068b5dfb2f70cfccc935ec56f537230d2 (patch) | |
| tree | 7d05917f1e5c856044a9f04e07e7236daee676c7 /src/server | |
| parent | 5d1bf18bb5e0494759fce01490fe02b802c26561 (diff) | |
| parent | f770f22960041c74347d2f96247c6d8bf8194d57 (diff) | |
Merge pull request #817 from BradLewis/fix/resolve-procs-that-return-procs-called-immediately
Fix/resolve procs that return procs called immediately
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/analysis.odin | 679 |
1 files changed, 377 insertions, 302 deletions
diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 6464d2b..5949077 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -1102,39 +1102,7 @@ internal_resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Ex ident.name = v.tok.text return internal_resolve_type_identifier(ast_context, ident^) case ^Type_Assertion: - if unary, ok := v.type.derived.(^ast.Unary_Expr); ok { - if unary.op.kind == .Question { - if symbol, ok := internal_resolve_type_expression(ast_context, v.expr); ok { - //To handle type assertions for unions, i.e. my_maybe_variable.? - if union_value, ok := symbol.value.(SymbolUnionValue); ok { - if len(union_value.types) != 1 { - return {}, false - } - return internal_resolve_type_expression(ast_context, union_value.types[0]) - } else if proc_value, ok := symbol.value.(SymbolProcedureValue); ok { - //To handle type assertions for unions returned from procedures, i.e: my_function().? - if len(proc_value.return_types) != 1 || proc_value.return_types[0].type == nil { - return {}, false - } - - if symbol, ok := internal_resolve_type_expression( - ast_context, - proc_value.return_types[0].type, - ); ok { - if union_value, ok := symbol.value.(SymbolUnionValue); ok { - if len(union_value.types) != 1 { - return {}, false - } - return internal_resolve_type_expression(ast_context, union_value.types[0]) - } - } - } - - } - } - } else { - return internal_resolve_type_expression(ast_context, v.type) - } + return resolve_type_assertion_expr(ast_context, v) case ^Proc_Lit: if v.type.results != nil { if len(v.type.results.list) > 0 { @@ -1152,33 +1120,7 @@ internal_resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Ex } } case ^Index_Expr: - indexed, ok := internal_resolve_type_expression(ast_context, v.expr) - - if !ok { - return {}, false - } - - set_ast_package_set_scoped(ast_context, indexed.pkg) - - symbol: Symbol - - #partial switch v2 in indexed.value { - case SymbolDynamicArrayValue: - symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) - case SymbolSliceValue: - symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) - case SymbolFixedArrayValue: - symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) - case SymbolMapValue: - symbol, ok = internal_resolve_type_expression(ast_context, v2.value) - case SymbolMultiPointerValue: - symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) - } - - - symbol.type = indexed.type - - return symbol, ok + return resolve_index_expr(ast_context, v) case ^Call_Expr: old_call := ast_context.call ast_context.call = cast(^Call_Expr)node @@ -1186,31 +1128,9 @@ internal_resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Ex defer { ast_context.call = old_call } - - if ident, ok := v.expr.derived.(^ast.Ident); ok && len(v.args) >= 1 { - switch ident.name { - case "type_of": - ast_context.call = nil - return internal_resolve_type_expression(ast_context, v.args[0]) - } - } - - return internal_resolve_type_expression(ast_context, v.expr) + return resolve_call_expr(ast_context, v) case ^Selector_Call_Expr: - if selector, ok := internal_resolve_type_expression(ast_context, v.expr); ok { - ast_context.use_locals = false - - set_ast_package_from_symbol_scoped(ast_context, selector) - - #partial switch s in selector.value { - case SymbolProcedureValue: - if len(s.return_types) == 1 { - return internal_resolve_type_expression(ast_context, s.return_types[0].type) - } - } - - return selector, true - } + return resolve_selector_call_expr(ast_context, v) case ^Selector_Expr: return resolve_selector_expression(ast_context, v) case ^ast.Poly_Type: @@ -1225,6 +1145,113 @@ internal_resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Ex return Symbol{}, false } +resolve_call_expr :: proc(ast_context: ^AstContext, v: ^ast.Call_Expr) -> (Symbol, bool) { + if ident, ok := v.expr.derived.(^ast.Ident); ok && len(v.args) >= 1 { + switch ident.name { + case "type_of": + ast_context.call = nil + return internal_resolve_type_expression(ast_context, v.args[0]) + } + } else if call, ok := v.expr.derived.(^ast.Call_Expr); ok { + // handle the case where we immediately call a proc returned by another proc + if symbol, ok := internal_resolve_type_expression(ast_context, v.expr); ok { + if value, ok := symbol.value.(SymbolProcedureValue); ok { + if len(value.return_types) == 1 { + return internal_resolve_type_expression(ast_context, value.return_types[0].type) + } + } + return symbol, ok + } else { + return {}, false + } + } + + return internal_resolve_type_expression(ast_context, v.expr) +} + +resolve_index_expr :: proc(ast_context: ^AstContext, v: ^ast.Index_Expr) -> (Symbol, bool) { + indexed, ok := internal_resolve_type_expression(ast_context, v.expr) + + if !ok { + return {}, false + } + + set_ast_package_set_scoped(ast_context, indexed.pkg) + + symbol: Symbol + + #partial switch v2 in indexed.value { + case SymbolDynamicArrayValue: + symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) + case SymbolSliceValue: + symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) + case SymbolFixedArrayValue: + symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) + case SymbolMapValue: + symbol, ok = internal_resolve_type_expression(ast_context, v2.value) + case SymbolMultiPointerValue: + symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) + } + + + symbol.type = indexed.type + + return symbol, ok +} + +resolve_selector_call_expr :: proc(ast_context: ^AstContext, v: ^ast.Selector_Call_Expr) -> (Symbol, bool) { + if selector, ok := internal_resolve_type_expression(ast_context, v.expr); ok { + ast_context.use_locals = false + + set_ast_package_from_symbol_scoped(ast_context, selector) + + #partial switch s in selector.value { + case SymbolProcedureValue: + if len(s.return_types) == 1 { + return internal_resolve_type_expression(ast_context, s.return_types[0].type) + } + } + + return selector, true + } + return {}, false +} + +resolve_type_assertion_expr :: proc(ast_context: ^AstContext, v: ^ast.Type_Assertion) -> (Symbol, bool) { + if unary, ok := v.type.derived.(^ast.Unary_Expr); ok { + if unary.op.kind == .Question { + if symbol, ok := internal_resolve_type_expression(ast_context, v.expr); ok { + //To handle type assertions for unions, i.e. my_maybe_variable.? + if union_value, ok := symbol.value.(SymbolUnionValue); ok { + if len(union_value.types) != 1 { + return {}, false + } + return internal_resolve_type_expression(ast_context, union_value.types[0]) + } else if proc_value, ok := symbol.value.(SymbolProcedureValue); ok { + //To handle type assertions for unions returned from procedures, i.e: my_function().? + if len(proc_value.return_types) != 1 || proc_value.return_types[0].type == nil { + return {}, false + } + + if symbol, ok := internal_resolve_type_expression( + ast_context, + proc_value.return_types[0].type, + ); ok { + if union_value, ok := symbol.value.(SymbolUnionValue); ok { + if len(union_value.types) != 1 { + return {}, false + } + return internal_resolve_type_expression(ast_context, union_value.types[0]) + } + } + } + + } + } + } + return internal_resolve_type_expression(ast_context, v.type) +} + resolve_selector_expression :: proc(ast_context: ^AstContext, node: ^ast.Selector_Expr) -> (Symbol, bool) { if selector, ok := internal_resolve_type_expression(ast_context, node.expr); ok { ast_context.use_locals = false @@ -1430,7 +1457,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S return internal_resolve_type_identifier(ast_context, node) } -internal_resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (_symbol: Symbol, _ok: bool) { +internal_resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (Symbol, bool) { using ast if check_node_recursion(ast_context, node.derived.(^ast.Ident)) { @@ -1478,109 +1505,7 @@ internal_resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ide } if local, ok := get_local(ast_context^, node); ok && (ast_context.use_locals || local.local_global) { - is_distinct := false - - if local.parameter { - for imp in ast_context.imports { - if strings.compare(imp.base, node.name) == 0 { - symbol := Symbol { - type = .Package, - pkg = imp.name, - value = SymbolPackageValue{}, - } - - return symbol, true - } - } - } - - if local.pkg != "" { - ast_context.current_package = local.pkg - } - - //Sometimes the locals are semi resolved and can no longer use the locals - if local.resolved_global { - ast_context.use_locals = false - } - - if dist, ok := local.rhs.derived.(^ast.Distinct_Type); ok { - if dist.type != nil { - local.rhs = dist.type - is_distinct = true - } - } - - return_symbol: Symbol - ok: bool - - #partial switch v in local.rhs.derived { - case ^Ident: - return_symbol, ok = internal_resolve_type_identifier(ast_context, v^) - case ^Union_Type: - return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true - return_symbol.name = node.name - case ^Enum_Type: - return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true - return_symbol.name = node.name - case ^Struct_Type: - return_symbol, ok = make_symbol_struct_from_ast(ast_context, v, node, {}), true - return_symbol.name = node.name - case ^Bit_Set_Type: - return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true - return_symbol.name = node.name - case ^Bit_Field_Type: - return_symbol, ok = make_symbol_bit_field_from_ast(ast_context, v, node), true - return_symbol.name = node.name - case ^Proc_Lit: - if is_procedure_generic(v.type) { - return_symbol, ok = resolve_generic_function(ast_context, v^) - - if !ok && !ast_context.overloading { - return_symbol, ok = - make_symbol_procedure_from_ast(ast_context, local.rhs, v.type^, node, {}, false, v.inlining), - true - } - } else { - return_symbol, ok = - make_symbol_procedure_from_ast(ast_context, local.rhs, v.type^, node, {}, false, v.inlining), true - } - case ^Proc_Group: - return_symbol, ok = resolve_function_overload(ast_context, v^) - case ^Array_Type: - return_symbol, ok = make_symbol_array_from_ast(ast_context, v^, node), true - case ^Dynamic_Array_Type: - return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node), true - case ^Matrix_Type: - return_symbol, ok = make_symbol_matrix_from_ast(ast_context, v^, node), true - case ^Map_Type: - return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node), true - case ^Basic_Lit: - return_symbol, ok = resolve_basic_lit(ast_context, v^) - return_symbol.name = node.name - return_symbol.type = local.variable ? .Variable : .Constant - case ^ast.Binary_Expr: - return_symbol, ok = resolve_binary_expression(ast_context, v) - case: - return_symbol, ok = internal_resolve_type_expression(ast_context, local.rhs) - } - - if is_distinct { - return_symbol.name = node.name - return_symbol.flags |= {.Distinct} - } - - if local.parameter { - return_symbol.flags |= {.Parameter} - } - - if local.variable { - return_symbol.type = .Variable - } - - return_symbol.flags |= {.Local} - - return return_symbol, ok - + return resolve_local_identifier(ast_context, node, &local) } for imp in ast_context.imports { @@ -1614,120 +1539,7 @@ internal_resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ide if global, ok := ast_context.globals[node.name]; ast_context.current_package == ast_context.document_package && ok { - is_distinct := false - ast_context.use_locals = false - - if dist, ok := global.expr.derived.(^ast.Distinct_Type); ok { - if dist.type != nil { - global.expr = dist.type - is_distinct = true - } - } - - return_symbol: Symbol - ok: bool - - #partial switch v in global.expr.derived { - case ^Ident: - return_symbol, ok = internal_resolve_type_identifier(ast_context, v^) - case ^ast.Call_Expr: - old_call := ast_context.call - ast_context.call = cast(^Call_Expr)global.expr - - defer { - ast_context.call = old_call - } - - if return_symbol, ok = internal_resolve_type_expression(ast_context, v.expr); ok { - return_types := get_proc_return_types(ast_context, return_symbol, v, global.mutable) - if len(return_types) > 0 { - return_symbol, ok = internal_resolve_type_expression(ast_context, return_types[0]) - } - // Otherwise should be a parapoly style - } - - case ^Struct_Type: - return_symbol, ok = make_symbol_struct_from_ast(ast_context, v, node, global.attributes), true - return_symbol.name = node.name - case ^Bit_Set_Type: - return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true - return_symbol.name = node.name - case ^Union_Type: - return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true - return_symbol.name = node.name - case ^Enum_Type: - return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true - return_symbol.name = node.name - case ^Bit_Field_Type: - return_symbol, ok = make_symbol_bit_field_from_ast(ast_context, v, node), true - return_symbol.name = node.name - case ^Proc_Lit: - if is_procedure_generic(v.type) { - return_symbol, ok = resolve_generic_function(ast_context, v^) - - //If we are not overloading just show the unresolved generic function - if !ok && !ast_context.overloading { - return_symbol, ok = - make_symbol_procedure_from_ast( - ast_context, - global.expr, - v.type^, - node, - global.attributes, - false, - v.inlining, - ), - true - } - } else { - return_symbol, ok = - make_symbol_procedure_from_ast( - ast_context, - global.expr, - v.type^, - node, - global.attributes, - false, - v.inlining, - ), - true - } - case ^Proc_Group: - return_symbol, ok = resolve_function_overload(ast_context, v^) - case ^Array_Type: - return_symbol, ok = make_symbol_array_from_ast(ast_context, v^, node), true - case ^Dynamic_Array_Type: - return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node), true - case ^Matrix_Type: - return_symbol, ok = make_symbol_matrix_from_ast(ast_context, v^, node), true - case ^Map_Type: - return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node), true - case ^Basic_Lit: - return_symbol, ok = resolve_basic_lit(ast_context, v^) - return_symbol.name = node.name - return_symbol.type = global.mutable ? .Variable : .Constant - case: - return_symbol, ok = internal_resolve_type_expression(ast_context, global.expr) - } - - if is_distinct { - return_symbol.name = node.name - return_symbol.flags |= {.Distinct} - } - - if global.mutable { - return_symbol.type = .Variable - } - - if global.docs != nil { - return_symbol.doc = get_doc(global.docs, ast_context.allocator) - } - - if global.comment != nil { - return_symbol.comment = get_comment(global.comment) - } - - return return_symbol, ok + return resolve_global_identifier(ast_context, node, &global) } else { switch node.name { case "context": @@ -1792,6 +1604,228 @@ internal_resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ide return Symbol{}, false } +resolve_local_identifier :: proc(ast_context: ^AstContext, node: ast.Ident, local: ^DocumentLocal) -> (Symbol, bool) { + is_distinct := false + + if local.parameter { + for imp in ast_context.imports { + if strings.compare(imp.base, node.name) == 0 { + symbol := Symbol { + type = .Package, + pkg = imp.name, + value = SymbolPackageValue{}, + } + + return symbol, true + } + } + } + + if local.pkg != "" { + ast_context.current_package = local.pkg + } + + //Sometimes the locals are semi resolved and can no longer use the locals + if local.resolved_global { + ast_context.use_locals = false + } + + if dist, ok := local.rhs.derived.(^ast.Distinct_Type); ok { + if dist.type != nil { + local.rhs = dist.type + is_distinct = true + } + } + + return_symbol: Symbol + ok: bool + + #partial switch v in local.rhs.derived { + case ^ast.Ident: + return_symbol, ok = internal_resolve_type_identifier(ast_context, v^) + case ^ast.Union_Type: + return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true + return_symbol.name = node.name + case ^ast.Enum_Type: + return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true + return_symbol.name = node.name + case ^ast.Struct_Type: + return_symbol, ok = make_symbol_struct_from_ast(ast_context, v, node, {}), true + return_symbol.name = node.name + case ^ast.Bit_Set_Type: + return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true + return_symbol.name = node.name + case ^ast.Bit_Field_Type: + return_symbol, ok = make_symbol_bit_field_from_ast(ast_context, v, node), true + return_symbol.name = node.name + case ^ast.Proc_Lit: + if is_procedure_generic(v.type) { + return_symbol, ok = resolve_generic_function(ast_context, v^) + + if !ok && !ast_context.overloading { + return_symbol, ok = + make_symbol_procedure_from_ast(ast_context, local.rhs, v.type^, node, {}, false, v.inlining), + true + } + } else { + return_symbol, ok = + make_symbol_procedure_from_ast(ast_context, local.rhs, v.type^, node, {}, false, v.inlining), true + } + case ^ast.Proc_Group: + return_symbol, ok = resolve_function_overload(ast_context, v^) + case ^ast.Array_Type: + return_symbol, ok = make_symbol_array_from_ast(ast_context, v^, node), true + case ^ast.Dynamic_Array_Type: + return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node), true + case ^ast.Matrix_Type: + return_symbol, ok = make_symbol_matrix_from_ast(ast_context, v^, node), true + case ^ast.Map_Type: + return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node), true + case ^ast.Basic_Lit: + return_symbol, ok = resolve_basic_lit(ast_context, v^) + return_symbol.name = node.name + return_symbol.type = local.variable ? .Variable : .Constant + case ^ast.Binary_Expr: + return_symbol, ok = resolve_binary_expression(ast_context, v) + case: + return_symbol, ok = internal_resolve_type_expression(ast_context, local.rhs) + } + + if is_distinct { + return_symbol.name = node.name + return_symbol.flags |= {.Distinct} + } + + if local.parameter { + return_symbol.flags |= {.Parameter} + } + + if local.variable { + return_symbol.type = .Variable + } + + return_symbol.flags |= {.Local} + + return return_symbol, ok +} + +resolve_global_identifier :: proc(ast_context: ^AstContext, node: ast.Ident, global: ^GlobalExpr) -> (Symbol, bool) { + is_distinct := false + ast_context.use_locals = false + + if dist, ok := global.expr.derived.(^ast.Distinct_Type); ok { + if dist.type != nil { + global.expr = dist.type + is_distinct = true + } + } + + return_symbol: Symbol + ok: bool + + #partial switch v in global.expr.derived { + case ^ast.Ident: + return_symbol, ok = internal_resolve_type_identifier(ast_context, v^) + case ^ast.Call_Expr: + old_call := ast_context.call + ast_context.call = cast(^ast.Call_Expr)global.expr + + defer { + ast_context.call = old_call + } + + if return_symbol, ok = internal_resolve_type_expression(ast_context, v.expr); ok { + return_types := get_proc_return_types(ast_context, return_symbol, v, global.mutable) + if len(return_types) > 0 { + return_symbol, ok = internal_resolve_type_expression(ast_context, return_types[0]) + } + // Otherwise should be a parapoly style + } + + case ^ast.Struct_Type: + return_symbol, ok = make_symbol_struct_from_ast(ast_context, v, node, global.attributes), true + return_symbol.name = node.name + case ^ast.Bit_Set_Type: + return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true + return_symbol.name = node.name + case ^ast.Union_Type: + return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true + return_symbol.name = node.name + case ^ast.Enum_Type: + return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true + return_symbol.name = node.name + case ^ast.Bit_Field_Type: + return_symbol, ok = make_symbol_bit_field_from_ast(ast_context, v, node), true + return_symbol.name = node.name + case ^ast.Proc_Lit: + if is_procedure_generic(v.type) { + return_symbol, ok = resolve_generic_function(ast_context, v^) + + //If we are not overloading just show the unresolved generic function + if !ok && !ast_context.overloading { + return_symbol, ok = + make_symbol_procedure_from_ast( + ast_context, + global.expr, + v.type^, + node, + global.attributes, + false, + v.inlining, + ), + true + } + } else { + return_symbol, ok = + make_symbol_procedure_from_ast( + ast_context, + global.expr, + v.type^, + node, + global.attributes, + false, + v.inlining, + ), + true + } + case ^ast.Proc_Group: + return_symbol, ok = resolve_function_overload(ast_context, v^) + case ^ast.Array_Type: + return_symbol, ok = make_symbol_array_from_ast(ast_context, v^, node), true + case ^ast.Dynamic_Array_Type: + return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node), true + case ^ast.Matrix_Type: + return_symbol, ok = make_symbol_matrix_from_ast(ast_context, v^, node), true + case ^ast.Map_Type: + return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node), true + case ^ast.Basic_Lit: + return_symbol, ok = resolve_basic_lit(ast_context, v^) + return_symbol.name = node.name + return_symbol.type = global.mutable ? .Variable : .Constant + case: + return_symbol, ok = internal_resolve_type_expression(ast_context, global.expr) + } + + if is_distinct { + return_symbol.name = node.name + return_symbol.flags |= {.Distinct} + } + + if global.mutable { + return_symbol.type = .Variable + } + + if global.docs != nil { + return_symbol.doc = get_doc(global.docs, ast_context.allocator) + } + + if global.comment != nil { + return_symbol.comment = get_comment(global.comment) + } + + return return_symbol, ok +} + struct_type_from_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (^ast.Struct_Type, bool) { if check_node_recursion(ast_context, node.derived.(^ast.Ident)) { return {}, false @@ -3255,6 +3289,47 @@ get_generic_assignment :: proc( } } + // If we have a call expr followed immediately by another call expr, we want to return value + // of the second call. Eg a := foo()() + if _, ok := v.expr.derived.(^Call_Expr); ok { + if symbol, ok := internal_resolve_type_expression(ast_context, v.expr); ok { + if value, ok := symbol.value.(SymbolProcedureValue); ok { + if len(value.return_types) == 1 { + if proc_type, ok := value.return_types[0].type.derived.(^Proc_Type); ok { + for return_item in proc_type.results.list { + get_generic_assignment( + file, + return_item.type, + ast_context, + results, + calls, + flags, + is_mutable, + ) + } + return + } else if ident, ok := value.return_types[0].type.derived.(^ast.Ident); ok { + if symbol, ok := internal_resolve_type_expression(ast_context, ident); ok { + if value, ok := symbol.value.(SymbolProcedureValue); ok { + for return_item in value.return_types { + get_generic_assignment( + file, + return_item.type, + ast_context, + results, + calls, + flags, + is_mutable, + ) + } + } + } + } + } + } + } + } + //We have to resolve early and can't rely on lazy evalutation because it can have multiple returns. if symbol, ok := resolve_type_expression(ast_context, v.expr); ok { #partial switch symbol_value in symbol.value { |