| ... | ... | @@ -861,12 +861,121 @@ pub fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inn |
| 861 | 861 | => return structInitExpr(gz, scope, rl, node, tree.structInit(node)), |
| 862 | 862 | |
| 863 | 863 | .@"anytype" => return astgen.failNode(node, "TODO implement astgen.expr for .anytype", .{}), |
| 864 | | .fn_proto_simple, |
| 865 | | .fn_proto_multi, |
| 866 | | .fn_proto_one, |
| 867 | | .fn_proto, |
| 868 | | => return astgen.failNode(node, "TODO implement astgen.expr for function prototypes", .{}), |
| 864 | |
| 865 | .fn_proto_simple => { |
| 866 | var params: [1]ast.Node.Index = undefined; |
| 867 | return fnProtoExpr(gz, scope, rl, tree.fnProtoSimple(&params, node)); |
| 868 | }, |
| 869 | .fn_proto_multi => { |
| 870 | return fnProtoExpr(gz, scope, rl, tree.fnProtoMulti(node)); |
| 871 | }, |
| 872 | .fn_proto_one => { |
| 873 | var params: [1]ast.Node.Index = undefined; |
| 874 | return fnProtoExpr(gz, scope, rl, tree.fnProtoOne(&params, node)); |
| 875 | }, |
| 876 | .fn_proto => { |
| 877 | return fnProtoExpr(gz, scope, rl, tree.fnProto(node)); |
| 878 | }, |
| 879 | } |
| 880 | } |
| 881 | |
| 882 | pub fn fnProtoExpr( |
| 883 | gz: *GenZir, |
| 884 | scope: *Scope, |
| 885 | rl: ResultLoc, |
| 886 | fn_proto: ast.full.FnProto, |
| 887 | ) InnerError!Zir.Inst.Ref { |
| 888 | const astgen = gz.astgen; |
| 889 | const gpa = astgen.gpa; |
| 890 | const tree = &astgen.file.tree; |
| 891 | const token_tags = tree.tokens.items(.tag); |
| 892 | |
| 893 | const is_extern = blk: { |
| 894 | const maybe_extern_token = fn_proto.extern_export_token orelse break :blk false; |
| 895 | break :blk token_tags[maybe_extern_token] == .keyword_extern; |
| 896 | }; |
| 897 | assert(!is_extern); |
| 898 | |
| 899 | // The AST params array does not contain anytype and ... parameters. |
| 900 | // We must iterate to count how many param types to allocate. |
| 901 | const param_count = blk: { |
| 902 | var count: usize = 0; |
| 903 | var it = fn_proto.iterate(tree.*); |
| 904 | while (it.next()) |param| { |
| 905 | if (param.anytype_ellipsis3) |token| switch (token_tags[token]) { |
| 906 | .ellipsis3 => break, |
| 907 | .keyword_anytype => {}, |
| 908 | else => unreachable, |
| 909 | }; |
| 910 | count += 1; |
| 911 | } |
| 912 | break :blk count; |
| 913 | }; |
| 914 | const param_types = try gpa.alloc(Zir.Inst.Ref, param_count); |
| 915 | defer gpa.free(param_types); |
| 916 | |
| 917 | var is_var_args = false; |
| 918 | { |
| 919 | var param_type_i: usize = 0; |
| 920 | var it = fn_proto.iterate(tree.*); |
| 921 | while (it.next()) |param| : (param_type_i += 1) { |
| 922 | if (param.anytype_ellipsis3) |token| { |
| 923 | switch (token_tags[token]) { |
| 924 | .keyword_anytype => { |
| 925 | param_types[param_type_i] = .none; |
| 926 | continue; |
| 927 | }, |
| 928 | .ellipsis3 => { |
| 929 | is_var_args = true; |
| 930 | break; |
| 931 | }, |
| 932 | else => unreachable, |
| 933 | } |
| 934 | } |
| 935 | const param_type_node = param.type_expr; |
| 936 | assert(param_type_node != 0); |
| 937 | param_types[param_type_i] = |
| 938 | try expr(gz, scope, .{ .ty = .type_type }, param_type_node); |
| 939 | } |
| 940 | assert(param_type_i == param_count); |
| 941 | } |
| 942 | |
| 943 | assert(fn_proto.ast.align_expr == 0); // caught by the parser |
| 944 | assert(fn_proto.ast.section_expr == 0); // caught by the parser |
| 945 | |
| 946 | const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; |
| 947 | const is_inferred_error = token_tags[maybe_bang] == .bang; |
| 948 | if (is_inferred_error) { |
| 949 | return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); |
| 869 | 950 | } |
| 951 | const return_type_inst = try AstGen.expr( |
| 952 | gz, |
| 953 | scope, |
| 954 | .{ .ty = .type_type }, |
| 955 | fn_proto.ast.return_type, |
| 956 | ); |
| 957 | |
| 958 | const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) |
| 959 | try AstGen.expr( |
| 960 | gz, |
| 961 | scope, |
| 962 | .{ .ty = .calling_convention_type }, |
| 963 | fn_proto.ast.callconv_expr, |
| 964 | ) |
| 965 | else |
| 966 | Zir.Inst.Ref.none; |
| 967 | |
| 968 | const result = try gz.addFunc(.{ |
| 969 | .src_node = fn_proto.ast.proto_node, |
| 970 | .ret_ty = return_type_inst, |
| 971 | .param_types = param_types, |
| 972 | .body = &[0]Zir.Inst.Index{}, |
| 973 | .cc = cc, |
| 974 | .lib_name = 0, |
| 975 | .is_var_args = is_var_args, |
| 976 | .is_inferred_error = false, |
| 977 | }); |
| 978 | return rvalue(gz, scope, rl, result, fn_proto.ast.proto_node); |
| 870 | 979 | } |
| 871 | 980 | |
| 872 | 981 | pub fn arrayInitExpr( |
| ... | ... | @@ -2506,11 +2615,11 @@ fn fnDecl( |
| 2506 | 2615 | Zir.Inst.Ref.none; |
| 2507 | 2616 | |
| 2508 | 2617 | const func_inst: Zir.Inst.Ref = if (body_node == 0) func: { |
| 2509 | | if (is_extern) { |
| 2618 | if (!is_extern) { |
| 2510 | 2619 | return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{}); |
| 2511 | 2620 | } |
| 2512 | 2621 | if (is_inferred_error) { |
| 2513 | | return astgen.failTok(maybe_bang, "function prototype requires explicit error set", .{}); |
| 2622 | return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); |
| 2514 | 2623 | } |
| 2515 | 2624 | break :func try decl_gz.addFunc(.{ |
| 2516 | 2625 | .src_node = fn_proto.ast.proto_node, |