diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 36cb751b3..c170e06cf 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2199,6 +2199,57 @@ parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) { return } +is_expr_generic :: proc(expr : ^ast.Expr) -> bool { + is_generic := false + if expr != nil { + #partial switch e in expr.derived_expr { + case ^ast.Typeid_Type: + is_generic = e.specialization != nil + case ^ast.Poly_Type: + is_generic = true + case ^ast.Proc_Type: + is_generic = e.generic + case ^ast.Pointer_Type: + is_generic = is_expr_generic(e.elem) + case ^ast.Multi_Pointer_Type: + is_generic = is_expr_generic(e.elem) + case ^ast.Array_Type: + is_generic = is_expr_generic(e.len) || is_expr_generic(e.elem) + case ^ast.Dynamic_Array_Type: + is_generic = is_expr_generic(e.elem) + case ^ast.Fixed_Capacity_Dynamic_Array_Type: + is_generic = is_expr_generic(e.capacity) || is_expr_generic(e.elem) + case ^ast.Bit_Set_Type: + is_generic = is_expr_generic(e.elem) + case ^ast.Map_Type: + is_generic = is_expr_generic(e.key) || is_expr_generic(e.value) + case ^ast.Matrix_Type: + is_generic = is_expr_generic(e.row_count) || is_expr_generic(e.column_count) || is_expr_generic(e.elem) + } + } + return is_generic +} + +is_field_list_generic :: proc(field_list : ^ast.Field_List, check_names : bool) -> bool { + is_generic := false + loop: for param in field_list.list { + if is_expr_generic(param.type) { + is_generic = true + break loop + } + if !check_names || param.type == nil { + continue + } + for name in param.names { + if _, ok := name.derived.(^ast.Poly_Type); ok { + is_generic = true + break loop + } + } + } + return is_generic +} + parse_proc_type :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Proc_Type { cc: ast.Proc_Calling_Convention if p.curr_tok.kind == .String { @@ -2220,21 +2271,9 @@ parse_proc_type :: proc(p: ^Parser, tok: tokenizer.Token) -> ^ast.Proc_Type { expect_closing_parentheses_of_field_list(p) results, diverging := parse_results(p) - is_generic := false - - loop: for param in params.list { - if param.type != nil { - if _, ok := param.type.derived.(^ast.Poly_Type); ok { - is_generic = true - break loop - } - for name in param.names { - if _, ok := name.derived.(^ast.Poly_Type); ok { - is_generic = true - break loop - } - } - } + is_generic := is_field_list_generic(params, true) + if !is_generic && results != nil { + is_generic = is_field_list_generic(results, false) } end := end_pos(p.prev_tok) diff --git a/src/parser.cpp b/src/parser.cpp index 17ab5ccf1..6dac8914f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4106,6 +4106,71 @@ gb_internal ProcCallingConvention string_to_calling_convention(String const &s) return ProcCC_Invalid; } +gb_internal bool is_ast_generic(Ast *a) { + bool is_generic = false; + if (a != nullptr) { + switch (a->kind) { + case Ast_TypeidType: + is_generic = a->TypeidType.specialization != nullptr; + break; + case Ast_PolyType: + is_generic = true; + break; + case Ast_ProcType: + is_generic = a->ProcType.generic; + break; + case Ast_PointerType: + is_generic = is_ast_generic(a->PointerType.type); + break; + case Ast_MultiPointerType: + is_generic = is_ast_generic(a->MultiPointerType.type); + break; + case Ast_ArrayType: + is_generic = is_ast_generic(a->ArrayType.elem) || is_ast_generic(a->ArrayType.count); + break; + case Ast_DynamicArrayType: + is_generic = is_ast_generic(a->DynamicArrayType.elem); + break; + case Ast_FixedCapacityDynamicArrayType: + is_generic = is_ast_generic(a->FixedCapacityDynamicArrayType.elem) || is_ast_generic(a->FixedCapacityDynamicArrayType.capacity); + break; + case Ast_BitSetType: + is_generic = is_ast_generic(a->BitSetType.elem); + break; + case Ast_MapType: + is_generic = is_ast_generic(a->MapType.key) || is_ast_generic(a->MapType.value); + break; + case Ast_MatrixType: + is_generic = is_ast_generic(a->MatrixType.row_count) || is_ast_generic(a->MatrixType.column_count) || is_ast_generic(a->MatrixType.elem); + break; + } + } + return is_generic; +} + +gb_internal bool is_field_list_generic(AstFieldList *field_list, bool check_names) { + bool is_generic = false; + + for (Ast *param : field_list->list) { + ast_node(field, Field, param); + if (is_ast_generic(field->type)) { + is_generic = true; + goto end; + } + if (!check_names || field->type == nullptr) { + continue; + } + for (Ast *name : field->names) { + if (name->kind == Ast_PolyType) { + is_generic = true; + goto end; + } + } + } +end: + return is_generic; +} + gb_internal Ast *parse_proc_type(AstFile *f, Token proc_token) { Ast *params = nullptr; Ast *results = nullptr; @@ -4141,24 +4206,11 @@ gb_internal Ast *parse_proc_type(AstFile *f, Token proc_token) { results = parse_results(f, &diverging); u64 tags = 0; - bool is_generic = false; - - for (Ast *param : params->FieldList.list) { - ast_node(field, Field, param); - if (field->type != nullptr) { - if (field->type->kind == Ast_PolyType) { - is_generic = true; - goto end; - } - for (Ast *name : field->names) { - if (name->kind == Ast_PolyType) { - is_generic = true; - goto end; - } - } - } + bool is_generic = is_field_list_generic(¶ms->FieldList, true); + if (!is_generic && (results != nullptr)) { + is_generic = is_field_list_generic(&results->FieldList, false); } -end: + return ast_proc_type(f, proc_token, params, results, tags, cc, is_generic, diverging); }