authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-28 20:26:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-28 20:26:40-07:00
loga5c2de5fee67e35c8173b7051675d49648086cbb
treee6ee63d6daca6d6456e58f866d47e2c426cd9315
parent2bb2e61ee288a02e184e5b8422859a4afcbb4813

ability to specify function type

closes #14

5 files changed, 170 insertions(+), 70 deletions(-)

doc/langref.md+1-1
......@@ -141,7 +141,7 @@ StructLiteralField = "." "Symbol" "=" Expression
141141
142142PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%"
143143
144PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." "Symbol")
144PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." "Symbol")
145145
146146ArrayType = "[" option(Expression) "]" option("const") PrefixOpExpression
147147
src/all_types.hpp+2
......@@ -189,6 +189,7 @@ struct AstNodeFnProto {
189189 FnTableEntry *fn_table_entry;
190190 bool skip;
191191 TopLevelDecl top_level_decl;
192 Expr resolved_expr;
192193};
193194
194195struct AstNodeFnDef {
......@@ -828,6 +829,7 @@ struct TypeTableEntryFn {
828829 bool is_var_args;
829830 int gen_param_count;
830831 LLVMCallConv calling_convention;
832 bool is_extern;
831833 bool is_naked;
832834};
833835
src/analyze.cpp+114-50
......@@ -451,44 +451,20 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B
451451 return resolve_type(g, *node_ptr);
452452}
453453
454static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
455 ImportTableEntry *import)
454static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
455 TypeTableEntry *expected_type, AstNode *node, bool is_naked)
456456{
457457 assert(node->type == NodeTypeFnProto);
458458 AstNodeFnProto *fn_proto = &node->data.fn_proto;
459459
460460 if (fn_proto->skip) {
461 return;
461 return g->builtin_types.entry_invalid;
462462 }
463463
464464 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
465 fn_table_entry->type_entry = fn_type;
466 fn_type->data.fn.calling_convention = fn_table_entry->internal_linkage ? LLVMFastCallConv : LLVMCCallConv;
467
468 for (int i = 0; i < fn_proto->directives->length; i += 1) {
469 AstNode *directive_node = fn_proto->directives->at(i);
470 Buf *name = &directive_node->data.directive.name;
471
472 if (buf_eql_str(name, "attribute")) {
473 Buf *attr_name = &directive_node->data.directive.param;
474 if (fn_table_entry->fn_def_node) {
475 if (buf_eql_str(attr_name, "naked")) {
476 fn_type->data.fn.is_naked = true;
477 } else if (buf_eql_str(attr_name, "inline")) {
478 fn_table_entry->is_inline = true;
479 } else {
480 add_node_error(g, directive_node,
481 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
482 }
483 } else {
484 add_node_error(g, directive_node,
485 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
486 }
487 } else {
488 add_node_error(g, directive_node,
489 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
490 }
491 }
465 fn_type->data.fn.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);
466 fn_type->data.fn.is_naked = is_naked;
467 fn_type->data.fn.calling_convention = fn_proto->is_extern ? LLVMCCallConv : LLVMFastCallConv;
492468
493469 int src_param_count = node->data.fn_proto.params.length;
494470 fn_type->size_in_bits = g->pointer_size_bytes * 8;
......@@ -499,10 +475,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
499475 // first, analyze the parameters and return type in order they appear in
500476 // source code in order for error messages to be in the best order.
501477 buf_resize(&fn_type->name, 0);
502 const char *export_str = fn_table_entry->internal_linkage ? "" : "export ";
503 const char *inline_str = fn_table_entry->is_inline ? "inline " : "";
478 const char *extern_str = fn_type->data.fn.is_extern ? "extern " : "";
504479 const char *naked_str = fn_type->data.fn.is_naked ? "naked " : "";
505 buf_appendf(&fn_type->name, "%s%s%sfn(", export_str, inline_str, naked_str);
480 buf_appendf(&fn_type->name, "%s%sfn(", extern_str, naked_str);
506481 for (int i = 0; i < src_param_count; i += 1) {
507482 AstNode *child = node->data.fn_proto.params.at(i);
508483 assert(child->type == NodeTypeParamDecl);
......@@ -525,10 +500,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
525500 const char *comma = (src_param_count == 0) ? "" : ", ";
526501 buf_appendf(&fn_type->name, "%s...", comma);
527502 }
528
529503 buf_appendf(&fn_type->name, ")");
530504 if (return_type->id != TypeTableEntryIdVoid) {
531 buf_appendf(&fn_type->name, " %s", buf_ptr(&return_type->name));
505 buf_appendf(&fn_type->name, " -> %s", buf_ptr(&return_type->name));
532506 }
533507
534508
......@@ -593,13 +567,12 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
593567 fn_type->data.fn.gen_param_count = gen_param_index;
594568
595569 if (fn_proto->skip) {
596 return;
570 return g->builtin_types.entry_invalid;
597571 }
598572
599573 auto table_entry = import->fn_type_table.maybe_get(&fn_type->name);
600574 if (table_entry) {
601 fn_type = table_entry->value;
602 fn_table_entry->type_entry = fn_type;
575 return table_entry->value;
603576 } else {
604577 fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref,
605578 gen_param_types, gen_param_index, fn_type->data.fn.is_var_args);
......@@ -608,8 +581,56 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
608581 param_di_types, gen_param_index + 1, 0);
609582
610583 import->fn_type_table.put(&fn_type->name, fn_type);
584
585 return fn_type;
586 }
587}
588
589
590static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
591 ImportTableEntry *import)
592{
593 assert(node->type == NodeTypeFnProto);
594 AstNodeFnProto *fn_proto = &node->data.fn_proto;
595
596 if (fn_proto->skip) {
597 return;
611598 }
612599
600 bool is_naked = false;
601 for (int i = 0; i < fn_proto->directives->length; i += 1) {
602 AstNode *directive_node = fn_proto->directives->at(i);
603 Buf *name = &directive_node->data.directive.name;
604
605 if (buf_eql_str(name, "attribute")) {
606 Buf *attr_name = &directive_node->data.directive.param;
607 if (fn_table_entry->fn_def_node) {
608 if (buf_eql_str(attr_name, "naked")) {
609 is_naked = true;
610 } else if (buf_eql_str(attr_name, "inline")) {
611 fn_table_entry->is_inline = true;
612 } else {
613 add_node_error(g, directive_node,
614 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
615 }
616 } else {
617 add_node_error(g, directive_node,
618 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
619 }
620 } else {
621 add_node_error(g, directive_node,
622 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
623 }
624 }
625
626 TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, import->block_context, nullptr, node, is_naked);
627
628 if (fn_type->id == TypeTableEntryIdInvalid) {
629 fn_proto->skip = true;
630 return;
631 }
632
633 fn_table_entry->type_entry = fn_type;
613634
614635 fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(&fn_table_entry->symbol_name),
615636 fn_type->data.fn.raw_type_ref);
......@@ -624,7 +645,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
624645 LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ?
625646 LLVMInternalLinkage : LLVMExternalLinkage);
626647
627 if (return_type->id == TypeTableEntryIdUnreachable) {
648 if (fn_type->data.fn.src_return_type->id == TypeTableEntryIdUnreachable) {
628649 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);
629650 }
630651 LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention);
......@@ -1353,7 +1374,29 @@ static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTable
13531374 if (expected_type->id == TypeTableEntryIdFn &&
13541375 actual_type->id == TypeTableEntryIdFn)
13551376 {
1356 zig_panic("TODO types_match_const_cast_only for fns");
1377 if (expected_type->data.fn.is_extern != actual_type->data.fn.is_extern) {
1378 return false;
1379 }
1380 if (expected_type->data.fn.is_naked != actual_type->data.fn.is_naked) {
1381 return false;
1382 }
1383 if (!types_match_const_cast_only(expected_type->data.fn.src_return_type,
1384 actual_type->data.fn.src_return_type))
1385 {
1386 return false;
1387 }
1388 if (expected_type->data.fn.src_param_count != actual_type->data.fn.src_param_count) {
1389 return false;
1390 }
1391 for (int i = 0; i < expected_type->data.fn.src_param_count; i += 1) {
1392 // note it's reversed for parameters
1393 if (types_match_const_cast_only(actual_type->data.fn.param_types[i],
1394 expected_type->data.fn.param_types[i]))
1395 {
1396 return false;
1397 }
1398 }
1399 return true;
13571400 }
13581401
13591402
......@@ -2902,6 +2945,18 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,
29022945 }
29032946}
29042947
2948static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
2949 TypeTableEntry *expected_type, AstNode *node)
2950{
2951 TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node, false);
2952
2953 if (type_entry->id == TypeTableEntryIdInvalid) {
2954 return type_entry;
2955 }
2956
2957 return resolve_expr_const_val_as_type(g, node, type_entry);
2958}
2959
29052960static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
29062961 TypeTableEntry *expected_type, AstNode *node)
29072962{
......@@ -4240,6 +4295,9 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
42404295 case NodeTypeArrayType:
42414296 return_type = analyze_array_type(g, import, context, expected_type, node);
42424297 break;
4298 case NodeTypeFnProto:
4299 return_type = analyze_fn_proto_expr(g, import, context, expected_type, node);
4300 break;
42434301 case NodeTypeErrorType:
42444302 return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_pure_error);
42454303 break;
......@@ -4250,7 +4308,6 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
42504308 case NodeTypeSwitchRange:
42514309 case NodeTypeDirective:
42524310 case NodeTypeFnDecl:
4253 case NodeTypeFnProto:
42544311 case NodeTypeParamDecl:
42554312 case NodeTypeRoot:
42564313 case NodeTypeRootExportDecl:
......@@ -4555,13 +4612,23 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
45554612 collect_expr_decl_deps(g, import, node->data.switch_range.start, decl_node);
45564613 collect_expr_decl_deps(g, import, node->data.switch_range.end, decl_node);
45574614 break;
4558 case NodeTypeVariableDeclaration:
45594615 case NodeTypeFnProto:
4616 // remember that fn proto node is used for function definitions as well
4617 // as types
4618 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
4619 AstNode *param = node->data.fn_proto.params.at(i);
4620 collect_expr_decl_deps(g, import, param, decl_node);
4621 }
4622 collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node);
4623 break;
4624 case NodeTypeParamDecl:
4625 collect_expr_decl_deps(g, import, node->data.param_decl.type, decl_node);
4626 break;
4627 case NodeTypeVariableDeclaration:
45604628 case NodeTypeRootExportDecl:
45614629 case NodeTypeFnDef:
45624630 case NodeTypeRoot:
45634631 case NodeTypeFnDecl:
4564 case NodeTypeParamDecl:
45654632 case NodeTypeDirective:
45664633 case NodeTypeImport:
45674634 case NodeTypeCImport:
......@@ -4705,12 +4772,8 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
47054772 // determine which other top level declarations this function prototype depends on.
47064773 TopLevelDecl *decl_node = &node->data.fn_proto.top_level_decl;
47074774 decl_node->deps.init(1);
4708 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
4709 AstNode *param_node = node->data.fn_proto.params.at(i);
4710 assert(param_node->type == NodeTypeParamDecl);
4711 collect_expr_decl_deps(g, import, param_node->data.param_decl.type, decl_node);
4712 }
4713 collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node);
4775
4776 collect_expr_decl_deps(g, import, node, decl_node);
47144777
47154778 decl_node->name = name;
47164779 decl_node->import = import;
......@@ -4999,11 +5062,12 @@ Expr *get_resolved_expr(AstNode *node) {
49995062 return &node->data.error_type.resolved_expr;
50005063 case NodeTypeSwitchExpr:
50015064 return &node->data.switch_expr.resolved_expr;
5065 case NodeTypeFnProto:
5066 return &node->data.fn_proto.resolved_expr;
50025067 case NodeTypeSwitchProng:
50035068 case NodeTypeSwitchRange:
50045069 case NodeTypeRoot:
50055070 case NodeTypeRootExportDecl:
5006 case NodeTypeFnProto:
50075071 case NodeTypeFnDef:
50085072 case NodeTypeFnDecl:
50095073 case NodeTypeParamDecl:
src/parser.cpp+36-19
......@@ -503,6 +503,8 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
503503static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory);
504504static AstNode *ast_parse_unwrap_expr(ParseContext *pc, int *token_index, bool mandatory);
505505static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory);
506static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory,
507 ZigList<AstNode*> *directives, VisibMod visib_mod);
506508
507509static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
508510 if (token->id == token_id) {
......@@ -671,7 +673,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool
671673 Token *l_paren = &pc->tokens->at(*token_index);
672674 if (l_paren->id != TokenIdLParen) {
673675 if (mandatory) {
674 ast_invalid_token_error(pc, l_paren);
676 ast_expect_token(pc, l_paren, TokenIdLParen);
675677 } else {
676678 return nullptr;
677679 }
......@@ -695,7 +697,7 @@ static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bo
695697 Token *l_bracket = &pc->tokens->at(*token_index);
696698 if (l_bracket->id != TokenIdLBracket) {
697699 if (mandatory) {
698 ast_invalid_token_error(pc, l_bracket);
700 ast_expect_token(pc, l_bracket, TokenIdLBracket);
699701 } else {
700702 return nullptr;
701703 }
......@@ -865,7 +867,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
865867
866868 if (asm_token->id != TokenIdKeywordAsm) {
867869 if (mandatory) {
868 ast_invalid_token_error(pc, asm_token);
870 ast_expect_token(pc, asm_token, TokenIdKeywordAsm);
869871 } else {
870872 return nullptr;
871873 }
......@@ -905,7 +907,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
905907}
906908
907909/*
908PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("error" "." "Symbol")
910PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." "Symbol")
909911KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" | "error"
910912*/
911913static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
......@@ -956,6 +958,11 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
956958 AstNode *node = ast_create_node(pc, NodeTypeErrorType, token);
957959 *token_index += 1;
958960 return node;
961 } else if (token->id == TokenIdKeywordExtern) {
962 *token_index += 1;
963 AstNode *node = ast_parse_fn_proto(pc, token_index, true, nullptr, VisibModPrivate);
964 node->data.fn_proto.is_extern = true;
965 return node;
959966 } else if (token->id == TokenIdAtSign) {
960967 *token_index += 1;
961968 Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
......@@ -1002,6 +1009,11 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
10021009 return array_type_node;
10031010 }
10041011
1012 AstNode *fn_proto_node = ast_parse_fn_proto(pc, token_index, false, nullptr, VisibModPrivate);
1013 if (fn_proto_node) {
1014 return fn_proto_node;
1015 }
1016
10051017 AstNode *asm_expr = ast_parse_asm_expr(pc, token_index, false);
10061018 if (asm_expr) {
10071019 return asm_expr;
......@@ -1055,7 +1067,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, int *token_index,
10551067 token = &pc->tokens->at(*token_index);
10561068 continue;
10571069 } else if (comma_tok->id != TokenIdRBrace) {
1058 ast_invalid_token_error(pc, comma_tok);
1070 ast_expect_token(pc, comma_tok, TokenIdRBrace);
10591071 } else {
10601072 *token_index += 1;
10611073 break;
......@@ -1084,7 +1096,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, int *token_index,
10841096 token = &pc->tokens->at(*token_index);
10851097 continue;
10861098 } else if (comma_tok->id != TokenIdRBrace) {
1087 ast_invalid_token_error(pc, comma_tok);
1099 ast_expect_token(pc, comma_tok, TokenIdRBrace);
10881100 } else {
10891101 *token_index += 1;
10901102 break;
......@@ -1555,7 +1567,7 @@ static AstNode *ast_parse_else(ParseContext *pc, int *token_index, bool mandator
15551567
15561568 if (else_token->id != TokenIdKeywordElse) {
15571569 if (mandatory) {
1558 ast_invalid_token_error(pc, else_token);
1570 ast_expect_token(pc, else_token, TokenIdKeywordElse);
15591571 } else {
15601572 return nullptr;
15611573 }
......@@ -1574,7 +1586,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
15741586 Token *if_tok = &pc->tokens->at(*token_index);
15751587 if (if_tok->id != TokenIdKeywordIf) {
15761588 if (mandatory) {
1577 ast_invalid_token_error(pc, if_tok);
1589 ast_expect_token(pc, if_tok, TokenIdKeywordIf);
15781590 } else {
15791591 return nullptr;
15801592 }
......@@ -1637,7 +1649,8 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
16371649 kind = ReturnKindError;
16381650 *token_index += 2;
16391651 } else if (mandatory) {
1640 ast_invalid_token_error(pc, token);
1652 ast_expect_token(pc, next_token, TokenIdKeywordReturn);
1653 zig_unreachable();
16411654 } else {
16421655 return nullptr;
16431656 }
......@@ -1647,7 +1660,8 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
16471660 kind = ReturnKindMaybe;
16481661 *token_index += 2;
16491662 } else if (mandatory) {
1650 ast_invalid_token_error(pc, token);
1663 ast_expect_token(pc, next_token, TokenIdKeywordReturn);
1664 zig_unreachable();
16511665 } else {
16521666 return nullptr;
16531667 }
......@@ -1655,7 +1669,8 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
16551669 kind = ReturnKindUnconditional;
16561670 *token_index += 1;
16571671 } else if (mandatory) {
1658 ast_invalid_token_error(pc, token);
1672 ast_expect_token(pc, token, TokenIdKeywordReturn);
1673 zig_unreachable();
16591674 } else {
16601675 return nullptr;
16611676 }
......@@ -1756,7 +1771,7 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma
17561771
17571772 if (token->id != TokenIdKeywordWhile) {
17581773 if (mandatory) {
1759 ast_invalid_token_error(pc, token);
1774 ast_expect_token(pc, token, TokenIdKeywordWhile);
17601775 } else {
17611776 return nullptr;
17621777 }
......@@ -1791,7 +1806,7 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mand
17911806
17921807 if (token->id != TokenIdKeywordFor) {
17931808 if (mandatory) {
1794 ast_invalid_token_error(pc, token);
1809 ast_expect_token(pc, token, TokenIdKeywordFor);
17951810 } else {
17961811 return nullptr;
17971812 }
......@@ -1829,7 +1844,7 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool m
18291844
18301845 if (token->id != TokenIdKeywordSwitch) {
18311846 if (mandatory) {
1832 ast_invalid_token_error(pc, token);
1847 ast_expect_token(pc, token, TokenIdKeywordSwitch);
18331848 } else {
18341849 return nullptr;
18351850 }
......@@ -2082,7 +2097,7 @@ static AstNode *ast_parse_label(ParseContext *pc, int *token_index, bool mandato
20822097 Token *symbol_token = &pc->tokens->at(*token_index);
20832098 if (symbol_token->id != TokenIdSymbol) {
20842099 if (mandatory) {
2085 ast_invalid_token_error(pc, symbol_token);
2100 ast_expect_token(pc, symbol_token, TokenIdSymbol);
20862101 } else {
20872102 return nullptr;
20882103 }
......@@ -2091,7 +2106,7 @@ static AstNode *ast_parse_label(ParseContext *pc, int *token_index, bool mandato
20912106 Token *colon_token = &pc->tokens->at(*token_index + 1);
20922107 if (colon_token->id != TokenIdColon) {
20932108 if (mandatory) {
2094 ast_invalid_token_error(pc, colon_token);
2109 ast_expect_token(pc, colon_token, TokenIdColon);
20952110 } else {
20962111 return nullptr;
20972112 }
......@@ -2122,7 +2137,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
21222137
21232138 if (last_token->id != TokenIdLBrace) {
21242139 if (mandatory) {
2125 ast_invalid_token_error(pc, last_token);
2140 ast_expect_token(pc, last_token, TokenIdLBrace);
21262141 } else {
21272142 return nullptr;
21282143 }
......@@ -2245,7 +2260,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, int *token_index, bool m
22452260 Token *extern_kw = &pc->tokens->at(*token_index);
22462261 if (extern_kw->id != TokenIdKeywordExtern) {
22472262 if (mandatory) {
2248 ast_invalid_token_error(pc, extern_kw);
2263 ast_expect_token(pc, extern_kw, TokenIdKeywordExtern);
22492264 } else {
22502265 return nullptr;
22512266 }
......@@ -2591,7 +2606,9 @@ void normalize_parent_ptrs(AstNode *node) {
25912606 break;
25922607 case NodeTypeFnProto:
25932608 set_field(&node->data.fn_proto.return_type);
2594 set_list_fields(node->data.fn_proto.directives);
2609 if (node->data.fn_proto.directives) {
2610 set_list_fields(node->data.fn_proto.directives);
2611 }
25952612 set_list_fields(&node->data.fn_proto.params);
25962613 break;
25972614 case NodeTypeFnDef:
test/run_tests.cpp+17
......@@ -1866,6 +1866,23 @@ fn f(i32) {}
18661866 )SOURCE", 2,
18671867 ".tmp_source.zig:2:1: error: missing function name",
18681868 ".tmp_source.zig:3:6: error: missing parameter name");
1869
1870 add_compile_fail_case("wrong function type", R"SOURCE(
1871const fns = []fn(){ a, b, c };
1872fn a() -> i32 {0}
1873fn b() -> i32 {1}
1874fn c() -> i32 {2}
1875 )SOURCE", 3,
1876 ".tmp_source.zig:2:21: error: expected type 'fn()', got 'fn() -> i32'",
1877 ".tmp_source.zig:2:24: error: expected type 'fn()', got 'fn() -> i32'",
1878 ".tmp_source.zig:2:27: error: expected type 'fn()', got 'fn() -> i32'");
1879
1880 add_compile_fail_case("extern function pointer mismatch", R"SOURCE(
1881const fns = [](fn(i32)->i32){ a, b, c };
1882pub fn a(x: i32) -> i32 {x + 0}
1883pub fn b(x: i32) -> i32 {x + 1}
1884export fn c(x: i32) -> i32 {x + 2}
1885 )SOURCE", 1, ".tmp_source.zig:2:37: error: expected type 'fn(i32) -> i32', got 'extern fn(i32) -> i32'");
18691886}
18701887
18711888//////////////////////////////////////////////////////////////////////////////