authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-02 20:35:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-02 21:56:10-07:00
log1472dc3ddb6fd7932ff530e7a2fd3f0185c7353f
tree77c6cae8dbc822e9fc5ec069b9d61d6e769694f8
parentb465037a65dd6a31c5865086ec4392a1d3a372bc

stage2: update ZIR for generic functions

ZIR encoding for functions is changed in preparation for generic function support. As an example: ```zig const std = @import("std"); const expect = std.testing.expect; test "example" { var x: usize = 0; x += checkSize(i32, 1); x += checkSize(bool, true); try expect(x == 5); } fn checkSize(comptime T: type, x: T) usize { _ = x; return @sizeOf(T); } ``` Previous ZIR for the `checkSize` function: ```zir [165] checkSize line(10) hash(0226f62e189fd0b1c5fca02cf4617562): %55 = block_inline({ %56 = decl_val("T") token_offset:11:35 %57 = as_node(@Ref.type_type, %56) node_offset:11:35 %69 = extended(func([comptime @Ref.type_type, %57], @Ref.usize_type, { %58 = arg("T") token_offset:11:23 %59 = as_node(@Ref.type_type, %58) node_offset:11:35 %60 = arg("x") token_offset:11:32 %61 = dbg_stmt(11, 4) ``` ZIR for the `checkSize` function after this commit: ```zir [157] checkSize line(10) hash(0226f62e189fd0b1c5fca02cf4617562): %55 = block_inline({ %56 = param_comptime("T", @Ref.type_type) token_offset:11:23 %57 = as_node(@Ref.type_type, %56) node_offset:11:35 %58 = param("x", %57) token_offset:11:32 %67 = func(@Ref.usize_type, { %59 = dbg_stmt(11, 4) ``` Noted differences: * Previously the type expression was redundantly repeated. * Previously the parameter names were redundantly stored in the ZIR extra array. * Instead of `arg` ZIR instructions as the first instructions within a function body, they are now outside the function body, in the same block as the `func` instruction. There are variants: - param - param_comptime - param_anytype - param_anytype_comptime * The param instructions additionally encode the type. * Because of the param instructions, the `func` instruction no longer encodes the list of parameter types or the comptime bits. It's implied that Sema will collect the parameters so that when a `func` instruction is encountered, they will be implicitly used to construct the function's type. This is so that we can satisfy all 3 ways of performing semantic analysis on a function: 1. runtime: Sema will insert AIR arg instructions for each parameter, and insert into the Sema inst_map ZIR param => AIR arg. 2. comptime/inline: Sema will insert into the inst_map ZIR param => callsite arguments. 3. generic: Sema will map *only the comptime* ZIR param instructions to the AIR instructions for the comptime arguments at the callsite, and then re-run Sema for the function's Decl. This will produce a new function which is the monomorphized function. Additionally: * AstGen: Update usage of deprecated `ensureCapacity` to `ensureUnusedCapacity` or `ensureTotalCapacity`. * Introduce `Type.fnInfo` for getting a bunch of data about a function type at once, and use it in `analyzeCall`. This commit starts a branch to implement generic functions in stage2. Test regressions have not been addressed yet.

6 files changed, 431 insertions(+), 378 deletions(-)

BRANCH_TODO created+9
...@@ -0,0 +1,9 @@
1* update arg instructions:
2 - runtime function call inserts AIR arg instructions and Sema map items for them
3 - comptime/inline function call inserts Sema map items for the args
4 - generic instantiation inserts Sema map items for the comptime args only, re-runs the
5 Decl ZIR to get the new Fn.
6* generic function call where it makes a new function
7* memoize the instantiation in a table
8* anytype with next parameter expression using it
9* comptime anytype
src/AstGen.zig+182-242
...@@ -42,7 +42,7 @@ const InnerError = error{ OutOfMemory, AnalysisFail };...@@ -42,7 +42,7 @@ const InnerError = error{ OutOfMemory, AnalysisFail };
4242
43fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 {43fn addExtra(astgen: *AstGen, extra: anytype) Allocator.Error!u32 {
44 const fields = std.meta.fields(@TypeOf(extra));44 const fields = std.meta.fields(@TypeOf(extra));
45 try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len + fields.len);45 try astgen.extra.ensureUnusedCapacity(astgen.gpa, fields.len);
46 return addExtraAssumeCapacity(astgen, extra);46 return addExtraAssumeCapacity(astgen, extra);
47}47}
4848
...@@ -259,6 +259,7 @@ pub const ResultLoc = union(enum) {...@@ -259,6 +259,7 @@ pub const ResultLoc = union(enum) {
259259
260pub const align_rl: ResultLoc = .{ .ty = .u16_type };260pub const align_rl: ResultLoc = .{ .ty = .u16_type };
261pub const bool_rl: ResultLoc = .{ .ty = .bool_type };261pub const bool_rl: ResultLoc = .{ .ty = .bool_type };
262pub const type_rl: ResultLoc = .{ .ty = .type_type };
262263
263fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref {264fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref {
264 const prev_force_comptime = gz.force_comptime;265 const prev_force_comptime = gz.force_comptime;
...@@ -1036,7 +1037,6 @@ fn fnProtoExpr(...@@ -1036,7 +1037,6 @@ fn fnProtoExpr(
1036 fn_proto: ast.full.FnProto,1037 fn_proto: ast.full.FnProto,
1037) InnerError!Zir.Inst.Ref {1038) InnerError!Zir.Inst.Ref {
1038 const astgen = gz.astgen;1039 const astgen = gz.astgen;
1039 const gpa = astgen.gpa;
1040 const tree = astgen.tree;1040 const tree = astgen.tree;
1041 const token_tags = tree.tokens.items(.tag);1041 const token_tags = tree.tokens.items(.tag);
10421042
...@@ -1046,71 +1046,53 @@ fn fnProtoExpr(...@@ -1046,71 +1046,53 @@ fn fnProtoExpr(
1046 };1046 };
1047 assert(!is_extern);1047 assert(!is_extern);
10481048
1049 // The AST params array does not contain anytype and ... parameters.1049 const is_var_args = is_var_args: {
1050 // We must iterate to count how many param types to allocate.
1051 const param_count = blk: {
1052 var count: usize = 0;
1053 var it = fn_proto.iterate(tree.*);
1054 while (it.next()) |param| {
1055 if (param.anytype_ellipsis3) |token| switch (token_tags[token]) {
1056 .ellipsis3 => break,
1057 .keyword_anytype => {},
1058 else => unreachable,
1059 };
1060 count += 1;
1061 }
1062 break :blk count;
1063 };
1064 const param_types = try gpa.alloc(Zir.Inst.Ref, param_count);
1065 defer gpa.free(param_types);
1066
1067 const bits_per_param = 1;
1068 const params_per_u32 = 32 / bits_per_param;
1069 // We only need this if there are greater than params_per_u32 fields.
1070 var bit_bag = ArrayListUnmanaged(u32){};
1071 defer bit_bag.deinit(gpa);
1072 var cur_bit_bag: u32 = 0;
1073 var is_var_args = false;
1074 {
1075 var param_type_i: usize = 0;1050 var param_type_i: usize = 0;
1076 var it = fn_proto.iterate(tree.*);1051 var it = fn_proto.iterate(tree.*);
1077 while (it.next()) |param| : (param_type_i += 1) {1052 while (it.next()) |param| : (param_type_i += 1) {
1078 if (param_type_i % params_per_u32 == 0 and param_type_i != 0) {
1079 try bit_bag.append(gpa, cur_bit_bag);
1080 cur_bit_bag = 0;
1081 }
1082 const is_comptime = if (param.comptime_noalias) |token|1053 const is_comptime = if (param.comptime_noalias) |token|
1083 token_tags[token] == .keyword_comptime1054 token_tags[token] == .keyword_comptime
1084 else1055 else
1085 false;1056 false;
1086 cur_bit_bag = (cur_bit_bag >> bits_per_param) |
1087 (@as(u32, @boolToInt(is_comptime)) << 31);
10881057
1089 if (param.anytype_ellipsis3) |token| {1058 const is_anytype = if (param.anytype_ellipsis3) |token| blk: {
1090 switch (token_tags[token]) {1059 switch (token_tags[token]) {
1091 .keyword_anytype => {1060 .keyword_anytype => break :blk true,
1092 param_types[param_type_i] = .none;1061 .ellipsis3 => break :is_var_args true,
1093 continue;
1094 },
1095 .ellipsis3 => {
1096 is_var_args = true;
1097 break;
1098 },
1099 else => unreachable,1062 else => unreachable,
1100 }1063 }
1101 }1064 } else false;
1102 const param_type_node = param.type_expr;1065
1103 assert(param_type_node != 0);1066 const param_name: u32 = if (param.name_token) |name_token| blk: {
1104 param_types[param_type_i] =1067 if (mem.eql(u8, "_", tree.tokenSlice(name_token)))
1105 try expr(gz, scope, .{ .ty = .type_type }, param_type_node);1068 break :blk 0;
1106 }1069
1107 assert(param_type_i == param_count);1070 break :blk try astgen.identAsString(name_token);
1071 } else 0;
11081072
1109 const empty_slot_count = params_per_u32 - (param_type_i % params_per_u32);1073 if (is_anytype) {
1110 if (empty_slot_count < params_per_u32) {1074 const name_token = param.name_token orelse param.anytype_ellipsis3.?;
1111 cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_param);1075
1076 const tag: Zir.Inst.Tag = if (is_comptime)
1077 .param_anytype_comptime
1078 else
1079 .param_anytype;
1080 _ = try gz.addStrTok(tag, param_name, name_token);
1081 } else {
1082 const param_type_node = param.type_expr;
1083 assert(param_type_node != 0);
1084 const param_type = try expr(gz, scope, type_rl, param_type_node);
1085 const main_tokens = tree.nodes.items(.main_token);
1086 const name_token = param.name_token orelse main_tokens[param_type_node];
1087 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
1088 _ = try gz.addPlTok(tag, name_token, Zir.Inst.Param{
1089 .name = param_name,
1090 .ty = param_type,
1091 });
1092 }
1112 }1093 }
1113 }1094 break :is_var_args false;
1095 };
11141096
1115 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {1097 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
1116 break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr);1098 break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr);
...@@ -1144,7 +1126,6 @@ fn fnProtoExpr(...@@ -1144,7 +1126,6 @@ fn fnProtoExpr(
1144 const result = try gz.addFunc(.{1126 const result = try gz.addFunc(.{
1145 .src_node = fn_proto.ast.proto_node,1127 .src_node = fn_proto.ast.proto_node,
1146 .ret_ty = return_type_inst,1128 .ret_ty = return_type_inst,
1147 .param_types = param_types,
1148 .body = &[0]Zir.Inst.Index{},1129 .body = &[0]Zir.Inst.Index{},
1149 .cc = cc,1130 .cc = cc,
1150 .align_inst = align_inst,1131 .align_inst = align_inst,
...@@ -1153,8 +1134,6 @@ fn fnProtoExpr(...@@ -1153,8 +1134,6 @@ fn fnProtoExpr(
1153 .is_inferred_error = false,1134 .is_inferred_error = false,
1154 .is_test = false,1135 .is_test = false,
1155 .is_extern = false,1136 .is_extern = false,
1156 .cur_bit_bag = cur_bit_bag,
1157 .bit_bag = bit_bag.items,
1158 });1137 });
1159 return rvalue(gz, rl, result, fn_proto.ast.proto_node);1138 return rvalue(gz, rl, result, fn_proto.ast.proto_node);
1160}1139}
...@@ -1447,8 +1426,8 @@ fn structInitExprRlNone(...@@ -1447,8 +1426,8 @@ fn structInitExprRlNone(
1447 const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInitAnon{1426 const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInitAnon{
1448 .fields_len = @intCast(u32, fields_list.len),1427 .fields_len = @intCast(u32, fields_list.len),
1449 });1428 });
1450 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +1429 try astgen.extra.ensureUnusedCapacity(gpa, fields_list.len *
1451 fields_list.len * @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len);1430 @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len);
1452 for (fields_list) |field| {1431 for (fields_list) |field| {
1453 _ = gz.astgen.addExtraAssumeCapacity(field);1432 _ = gz.astgen.addExtraAssumeCapacity(field);
1454 }1433 }
...@@ -1520,8 +1499,8 @@ fn structInitExprRlTy(...@@ -1520,8 +1499,8 @@ fn structInitExprRlTy(
1520 const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInit{1499 const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInit{
1521 .fields_len = @intCast(u32, fields_list.len),1500 .fields_len = @intCast(u32, fields_list.len),
1522 });1501 });
1523 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +1502 try astgen.extra.ensureUnusedCapacity(gpa, fields_list.len *
1524 fields_list.len * @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len);1503 @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len);
1525 for (fields_list) |field| {1504 for (fields_list) |field| {
1526 _ = gz.astgen.addExtraAssumeCapacity(field);1505 _ = gz.astgen.addExtraAssumeCapacity(field);
1527 }1506 }
...@@ -1918,7 +1897,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner...@@ -1918,7 +1897,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner
1918 // ZIR instructions that might be a type other than `noreturn` or `void`.1897 // ZIR instructions that might be a type other than `noreturn` or `void`.
1919 .add,1898 .add,
1920 .addwrap,1899 .addwrap,
1921 .arg,1900 .param,
1901 .param_comptime,
1902 .param_anytype,
1903 .param_anytype_comptime,
1922 .alloc,1904 .alloc,
1923 .alloc_mut,1905 .alloc_mut,
1924 .alloc_comptime,1906 .alloc_comptime,
...@@ -2488,7 +2470,7 @@ fn varDecl(...@@ -2488,7 +2470,7 @@ fn varDecl(
2488 // Move the init_scope instructions into the parent scope, swapping2470 // Move the init_scope instructions into the parent scope, swapping
2489 // store_to_block_ptr for store_to_inferred_ptr.2471 // store_to_block_ptr for store_to_inferred_ptr.
2490 const expected_len = parent_zir.items.len + init_scope.instructions.items.len;2472 const expected_len = parent_zir.items.len + init_scope.instructions.items.len;
2491 try parent_zir.ensureCapacity(gpa, expected_len);2473 try parent_zir.ensureTotalCapacity(gpa, expected_len);
2492 for (init_scope.instructions.items) |src_inst| {2474 for (init_scope.instructions.items) |src_inst| {
2493 if (zir_tags[src_inst] == .store_to_block_ptr) {2475 if (zir_tags[src_inst] == .store_to_block_ptr) {
2494 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) {2476 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) {
...@@ -2750,10 +2732,10 @@ fn ptrType(...@@ -2750,10 +2732,10 @@ fn ptrType(
2750 }2732 }
27512733
2752 const gpa = gz.astgen.gpa;2734 const gpa = gz.astgen.gpa;
2753 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);2735 try gz.instructions.ensureUnusedCapacity(gpa, 1);
2754 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);2736 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
2755 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +2737 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.PtrType).Struct.fields.len +
2756 @typeInfo(Zir.Inst.PtrType).Struct.fields.len + trailing_count);2738 trailing_count);
27572739
2758 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.PtrType{ .elem_type = elem_type });2740 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.PtrType{ .elem_type = elem_type });
2759 if (sentinel_ref != .none) {2741 if (sentinel_ref != .none) {
...@@ -2899,6 +2881,16 @@ fn fnDecl(...@@ -2899,6 +2881,16 @@ fn fnDecl(
2899 };2881 };
2900 defer decl_gz.instructions.deinit(gpa);2882 defer decl_gz.instructions.deinit(gpa);
29012883
2884 var fn_gz: GenZir = .{
2885 .force_comptime = false,
2886 .in_defer = false,
2887 .decl_node_index = fn_proto.ast.proto_node,
2888 .decl_line = decl_gz.decl_line,
2889 .parent = &decl_gz.base,
2890 .astgen = astgen,
2891 };
2892 defer fn_gz.instructions.deinit(gpa);
2893
2902 // TODO: support noinline2894 // TODO: support noinline
2903 const is_pub = fn_proto.visib_token != null;2895 const is_pub = fn_proto.visib_token != null;
2904 const is_export = blk: {2896 const is_export = blk: {
...@@ -2922,71 +2914,76 @@ fn fnDecl(...@@ -2922,71 +2914,76 @@ fn fnDecl(
29222914
2923 try wip_decls.next(gpa, is_pub, is_export, align_inst != .none, section_inst != .none);2915 try wip_decls.next(gpa, is_pub, is_export, align_inst != .none, section_inst != .none);
29242916
2925 // The AST params array does not contain anytype and ... parameters.2917 var params_scope = &fn_gz.base;
2926 // We must iterate to count how many param types to allocate.2918 const is_var_args = is_var_args: {
2927 const param_count = blk: {
2928 var count: usize = 0;
2929 var it = fn_proto.iterate(tree.*);
2930 while (it.next()) |param| {
2931 if (param.anytype_ellipsis3) |token| switch (token_tags[token]) {
2932 .ellipsis3 => break,
2933 .keyword_anytype => {},
2934 else => unreachable,
2935 };
2936 count += 1;
2937 }
2938 break :blk count;
2939 };
2940 const param_types = try gpa.alloc(Zir.Inst.Ref, param_count);
2941 defer gpa.free(param_types);
2942
2943 const bits_per_param = 1;
2944 const params_per_u32 = 32 / bits_per_param;
2945 // We only need this if there are greater than params_per_u32 fields.
2946 var bit_bag = ArrayListUnmanaged(u32){};
2947 defer bit_bag.deinit(gpa);
2948 var cur_bit_bag: u32 = 0;
2949 var is_var_args = false;
2950 {
2951 var param_type_i: usize = 0;2919 var param_type_i: usize = 0;
2952 var it = fn_proto.iterate(tree.*);2920 var it = fn_proto.iterate(tree.*);
2953 while (it.next()) |param| : (param_type_i += 1) {2921 while (it.next()) |param| : (param_type_i += 1) {
2954 if (param_type_i % params_per_u32 == 0 and param_type_i != 0) {
2955 try bit_bag.append(gpa, cur_bit_bag);
2956 cur_bit_bag = 0;
2957 }
2958 const is_comptime = if (param.comptime_noalias) |token|2922 const is_comptime = if (param.comptime_noalias) |token|
2959 token_tags[token] == .keyword_comptime2923 token_tags[token] == .keyword_comptime
2960 else2924 else
2961 false;2925 false;
2962 cur_bit_bag = (cur_bit_bag >> bits_per_param) |
2963 (@as(u32, @boolToInt(is_comptime)) << 31);
29642926
2965 if (param.anytype_ellipsis3) |token| {2927 const is_anytype = if (param.anytype_ellipsis3) |token| blk: {
2966 switch (token_tags[token]) {2928 switch (token_tags[token]) {
2967 .keyword_anytype => {2929 .keyword_anytype => break :blk true,
2968 param_types[param_type_i] = .none;2930 .ellipsis3 => break :is_var_args true,
2969 continue;
2970 },
2971 .ellipsis3 => {
2972 is_var_args = true;
2973 break;
2974 },
2975 else => unreachable,2931 else => unreachable,
2976 }2932 }
2977 }2933 } else false;
2978 const param_type_node = param.type_expr;2934
2979 assert(param_type_node != 0);2935 const param_name: u32 = if (param.name_token) |name_token| blk: {
2980 param_types[param_type_i] =2936 if (mem.eql(u8, "_", tree.tokenSlice(name_token)))
2981 try expr(&decl_gz, &decl_gz.base, .{ .ty = .type_type }, param_type_node);2937 break :blk 0;
2982 }2938
2983 assert(param_type_i == param_count);2939 const param_name = try astgen.identAsString(name_token);
2940 if (!is_extern) {
2941 try astgen.detectLocalShadowing(params_scope, param_name, name_token);
2942 }
2943 break :blk param_name;
2944 } else if (!is_extern) {
2945 if (param.anytype_ellipsis3) |tok| {
2946 return astgen.failTok(tok, "missing parameter name", .{});
2947 } else {
2948 return astgen.failNode(param.type_expr, "missing parameter name", .{});
2949 }
2950 } else 0;
2951
2952 const param_inst = if (is_anytype) param: {
2953 const name_token = param.name_token orelse param.anytype_ellipsis3.?;
2954 const tag: Zir.Inst.Tag = if (is_comptime)
2955 .param_anytype_comptime
2956 else
2957 .param_anytype;
2958 break :param try decl_gz.addStrTok(tag, param_name, name_token);
2959 } else param: {
2960 const param_type_node = param.type_expr;
2961 assert(param_type_node != 0);
2962 const param_type = try expr(&decl_gz, params_scope, type_rl, param_type_node);
2963 const main_tokens = tree.nodes.items(.main_token);
2964 const name_token = param.name_token orelse main_tokens[param_type_node];
2965 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
2966 break :param try decl_gz.addPlTok(tag, name_token, Zir.Inst.Param{
2967 .name = param_name,
2968 .ty = param_type,
2969 });
2970 };
2971
2972 if (param_name == 0) continue;
29842973
2985 const empty_slot_count = params_per_u32 - (param_type_i % params_per_u32);2974 const sub_scope = try astgen.arena.create(Scope.LocalVal);
2986 if (empty_slot_count < params_per_u32) {2975 sub_scope.* = .{
2987 cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_param);2976 .parent = params_scope,
2977 .gen_zir = &decl_gz,
2978 .name = param_name,
2979 .inst = param_inst,
2980 .token_src = param.name_token.?,
2981 .id_cat = .@"function parameter",
2982 };
2983 params_scope = &sub_scope.base;
2988 }2984 }
2989 }2985 break :is_var_args false;
2986 };
29902987
2991 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: {2988 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: {
2992 const lib_name_str = try astgen.strLitAsString(lib_name_token);2989 const lib_name_str = try astgen.strLitAsString(lib_name_token);
...@@ -2998,7 +2995,7 @@ fn fnDecl(...@@ -2998,7 +2995,7 @@ fn fnDecl(
29982995
2999 const return_type_inst = try AstGen.expr(2996 const return_type_inst = try AstGen.expr(
3000 &decl_gz,2997 &decl_gz,
3001 &decl_gz.base,2998 params_scope,
3002 .{ .ty = .type_type },2999 .{ .ty = .type_type },
3003 fn_proto.ast.return_type,3000 fn_proto.ast.return_type,
3004 );3001 );
...@@ -3014,7 +3011,7 @@ fn fnDecl(...@@ -3014,7 +3011,7 @@ fn fnDecl(
3014 }3011 }
3015 break :blk try AstGen.expr(3012 break :blk try AstGen.expr(
3016 &decl_gz,3013 &decl_gz,
3017 &decl_gz.base,3014 params_scope,
3018 .{ .ty = .calling_convention_type },3015 .{ .ty = .calling_convention_type },
3019 fn_proto.ast.callconv_expr,3016 fn_proto.ast.callconv_expr,
3020 );3017 );
...@@ -3038,7 +3035,6 @@ fn fnDecl(...@@ -3038,7 +3035,6 @@ fn fnDecl(
3038 break :func try decl_gz.addFunc(.{3035 break :func try decl_gz.addFunc(.{
3039 .src_node = decl_node,3036 .src_node = decl_node,
3040 .ret_ty = return_type_inst,3037 .ret_ty = return_type_inst,
3041 .param_types = param_types,
3042 .body = &[0]Zir.Inst.Index{},3038 .body = &[0]Zir.Inst.Index{},
3043 .cc = cc,3039 .cc = cc,
3044 .align_inst = .none, // passed in the per-decl data3040 .align_inst = .none, // passed in the per-decl data
...@@ -3047,75 +3043,18 @@ fn fnDecl(...@@ -3047,75 +3043,18 @@ fn fnDecl(
3047 .is_inferred_error = false,3043 .is_inferred_error = false,
3048 .is_test = false,3044 .is_test = false,
3049 .is_extern = true,3045 .is_extern = true,
3050 .cur_bit_bag = cur_bit_bag,
3051 .bit_bag = bit_bag.items,
3052 });3046 });
3053 } else func: {3047 } else func: {
3054 if (is_var_args) {3048 if (is_var_args) {
3055 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{});3049 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{});
3056 }3050 }
30573051
3058 var fn_gz: GenZir = .{
3059 .force_comptime = false,
3060 .in_defer = false,
3061 .decl_node_index = fn_proto.ast.proto_node,
3062 .decl_line = decl_gz.decl_line,
3063 .parent = &decl_gz.base,
3064 .astgen = astgen,
3065 };
3066 defer fn_gz.instructions.deinit(gpa);
3067
3068 const prev_fn_block = astgen.fn_block;3052 const prev_fn_block = astgen.fn_block;
3069 astgen.fn_block = &fn_gz;3053 astgen.fn_block = &fn_gz;
3070 defer astgen.fn_block = prev_fn_block;3054 defer astgen.fn_block = prev_fn_block;
30713055
3072 // Iterate over the parameters. We put the param names as the first N3056 _ = try expr(&fn_gz, params_scope, .none, body_node);
3073 // items inside `extra` so that debug info later can refer to the parameter names3057 try checkUsed(gz, &fn_gz.base, params_scope);
3074 // even while the respective source code is unloaded.
3075 try astgen.extra.ensureUnusedCapacity(gpa, param_count);
3076
3077 {
3078 var params_scope = &fn_gz.base;
3079 var i: usize = 0;
3080 var it = fn_proto.iterate(tree.*);
3081 while (it.next()) |param| : (i += 1) {
3082 const name_token = param.name_token orelse {
3083 if (param.anytype_ellipsis3) |tok| {
3084 return astgen.failTok(tok, "missing parameter name", .{});
3085 } else {
3086 return astgen.failNode(param.type_expr, "missing parameter name", .{});
3087 }
3088 };
3089 if (param.type_expr != 0)
3090 _ = try typeExpr(&fn_gz, params_scope, param.type_expr);
3091 if (mem.eql(u8, "_", tree.tokenSlice(name_token)))
3092 continue;
3093 const param_name = try astgen.identAsString(name_token);
3094 // Create an arg instruction. This is needed to emit a semantic analysis
3095 // error for shadowing decls.
3096 try astgen.detectLocalShadowing(params_scope, param_name, name_token);
3097 const arg_inst = try fn_gz.addStrTok(.arg, param_name, name_token);
3098 const sub_scope = try astgen.arena.create(Scope.LocalVal);
3099 sub_scope.* = .{
3100 .parent = params_scope,
3101 .gen_zir = &fn_gz,
3102 .name = param_name,
3103 .inst = arg_inst,
3104 .token_src = name_token,
3105 .id_cat = .@"function parameter",
3106 };
3107 params_scope = &sub_scope.base;
3108
3109 // Additionally put the param name into `string_bytes` and reference it with
3110 // `extra` so that we have access to the data in codegen, for debug info.
3111 const str_index = try astgen.identAsString(name_token);
3112 try astgen.extra.append(astgen.gpa, str_index);
3113 }
3114 _ = try typeExpr(&fn_gz, params_scope, fn_proto.ast.return_type);
3115
3116 _ = try expr(&fn_gz, params_scope, .none, body_node);
3117 try checkUsed(gz, &fn_gz.base, params_scope);
3118 }
31193058
3120 const need_implicit_ret = blk: {3059 const need_implicit_ret = blk: {
3121 if (fn_gz.instructions.items.len == 0)3060 if (fn_gz.instructions.items.len == 0)
...@@ -3133,7 +3072,6 @@ fn fnDecl(...@@ -3133,7 +3072,6 @@ fn fnDecl(
3133 break :func try decl_gz.addFunc(.{3072 break :func try decl_gz.addFunc(.{
3134 .src_node = decl_node,3073 .src_node = decl_node,
3135 .ret_ty = return_type_inst,3074 .ret_ty = return_type_inst,
3136 .param_types = param_types,
3137 .body = fn_gz.instructions.items,3075 .body = fn_gz.instructions.items,
3138 .cc = cc,3076 .cc = cc,
3139 .align_inst = .none, // passed in the per-decl data3077 .align_inst = .none, // passed in the per-decl data
...@@ -3142,8 +3080,6 @@ fn fnDecl(...@@ -3142,8 +3080,6 @@ fn fnDecl(
3142 .is_inferred_error = is_inferred_error,3080 .is_inferred_error = is_inferred_error,
3143 .is_test = false,3081 .is_test = false,
3144 .is_extern = false,3082 .is_extern = false,
3145 .cur_bit_bag = cur_bit_bag,
3146 .bit_bag = bit_bag.items,
3147 });3083 });
3148 };3084 };
31493085
...@@ -3480,7 +3416,6 @@ fn testDecl(...@@ -3480,7 +3416,6 @@ fn testDecl(
3480 const func_inst = try decl_block.addFunc(.{3416 const func_inst = try decl_block.addFunc(.{
3481 .src_node = node,3417 .src_node = node,
3482 .ret_ty = .void_type,3418 .ret_ty = .void_type,
3483 .param_types = &[0]Zir.Inst.Ref{},
3484 .body = fn_block.instructions.items,3419 .body = fn_block.instructions.items,
3485 .cc = .none,3420 .cc = .none,
3486 .align_inst = .none,3421 .align_inst = .none,
...@@ -3489,8 +3424,6 @@ fn testDecl(...@@ -3489,8 +3424,6 @@ fn testDecl(
3489 .is_inferred_error = true,3424 .is_inferred_error = true,
3490 .is_test = true,3425 .is_test = true,
3491 .is_extern = false,3426 .is_extern = false,
3492 .cur_bit_bag = 0,
3493 .bit_bag = &.{},
3494 });3427 });
34953428
3496 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst);3429 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst);
...@@ -4238,7 +4171,7 @@ fn containerDecl(...@@ -4238,7 +4171,7 @@ fn containerDecl(
4238 var fields_data = ArrayListUnmanaged(u32){};4171 var fields_data = ArrayListUnmanaged(u32){};
4239 defer fields_data.deinit(gpa);4172 defer fields_data.deinit(gpa);
42404173
4241 try fields_data.ensureCapacity(gpa, counts.total_fields + counts.values);4174 try fields_data.ensureTotalCapacity(gpa, counts.total_fields + counts.values);
42424175
4243 // We only need this if there are greater than 32 fields.4176 // We only need this if there are greater than 32 fields.
4244 var bit_bag = ArrayListUnmanaged(u32){};4177 var bit_bag = ArrayListUnmanaged(u32){};
...@@ -5184,8 +5117,7 @@ fn setCondBrPayload(...@@ -5184,8 +5117,7 @@ fn setCondBrPayload(
5184) !void {5117) !void {
5185 const astgen = then_scope.astgen;5118 const astgen = then_scope.astgen;
51865119
5187 try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len +5120 try astgen.extra.ensureUnusedCapacity(astgen.gpa, @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
5188 @typeInfo(Zir.Inst.CondBr).Struct.fields.len +
5189 then_scope.instructions.items.len + else_scope.instructions.items.len);5121 then_scope.instructions.items.len + else_scope.instructions.items.len);
51905122
5191 const zir_datas = astgen.instructions.items(.data);5123 const zir_datas = astgen.instructions.items(.data);
...@@ -5839,10 +5771,9 @@ fn switchExpr(...@@ -5839,10 +5771,9 @@ fn switchExpr(
5839 _ = try case_scope.addBreak(.@"break", switch_block, case_result);5771 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
5840 }5772 }
5841 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.5773 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.
5842 try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len +5774 try scalar_cases_payload.ensureUnusedCapacity(gpa, case_scope.instructions.items.len +
5843 3 + // operand, scalar_cases_len, else body len5775 3 + // operand, scalar_cases_len, else body len
5844 @boolToInt(multi_cases_len != 0) +5776 @boolToInt(multi_cases_len != 0));
5845 case_scope.instructions.items.len);
5846 scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand));5777 scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand));
5847 scalar_cases_payload.appendAssumeCapacity(scalar_cases_len);5778 scalar_cases_payload.appendAssumeCapacity(scalar_cases_len);
5848 if (multi_cases_len != 0) {5779 if (multi_cases_len != 0) {
...@@ -5852,9 +5783,11 @@ fn switchExpr(...@@ -5852,9 +5783,11 @@ fn switchExpr(
5852 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);5783 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);
5853 } else {5784 } else {
5854 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.5785 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.
5855 try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len +5786 try scalar_cases_payload.ensureUnusedCapacity(
5856 2 + // operand, scalar_cases_len5787 gpa,
5857 @boolToInt(multi_cases_len != 0));5788 @as(usize, 2) + // operand, scalar_cases_len
5789 @boolToInt(multi_cases_len != 0),
5790 );
5858 scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand));5791 scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand));
5859 scalar_cases_payload.appendAssumeCapacity(scalar_cases_len);5792 scalar_cases_payload.appendAssumeCapacity(scalar_cases_len);
5860 if (multi_cases_len != 0) {5793 if (multi_cases_len != 0) {
...@@ -5975,8 +5908,8 @@ fn switchExpr(...@@ -5975,8 +5908,8 @@ fn switchExpr(
5975 block_scope.break_count += 1;5908 block_scope.break_count += 1;
5976 _ = try case_scope.addBreak(.@"break", switch_block, case_result);5909 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
5977 }5910 }
5978 try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len +5911 try scalar_cases_payload.ensureUnusedCapacity(gpa, 2 +
5979 2 + case_scope.instructions.items.len);5912 case_scope.instructions.items.len);
5980 scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst));5913 scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst));
5981 scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));5914 scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));
5982 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);5915 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);
...@@ -6012,8 +5945,8 @@ fn switchExpr(...@@ -6012,8 +5945,8 @@ fn switchExpr(
6012 const payload_index = astgen.extra.items.len;5945 const payload_index = astgen.extra.items.len;
6013 const zir_datas = astgen.instructions.items(.data);5946 const zir_datas = astgen.instructions.items(.data);
6014 zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index);5947 zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index);
6015 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +5948 try astgen.extra.ensureUnusedCapacity(gpa, scalar_cases_payload.items.len +
6016 scalar_cases_payload.items.len + multi_cases_payload.items.len);5949 multi_cases_payload.items.len);
6017 const strat = rl.strategy(&block_scope);5950 const strat = rl.strategy(&block_scope);
6018 switch (strat.tag) {5951 switch (strat.tag) {
6019 .break_operand => {5952 .break_operand => {
...@@ -8659,7 +8592,7 @@ fn failNodeNotes(...@@ -8659,7 +8592,7 @@ fn failNodeNotes(
8659 }8592 }
8660 const notes_index: u32 = if (notes.len != 0) blk: {8593 const notes_index: u32 = if (notes.len != 0) blk: {
8661 const notes_start = astgen.extra.items.len;8594 const notes_start = astgen.extra.items.len;
8662 try astgen.extra.ensureCapacity(astgen.gpa, notes_start + 1 + notes.len);8595 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len);
8663 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));8596 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));
8664 astgen.extra.appendSliceAssumeCapacity(notes);8597 astgen.extra.appendSliceAssumeCapacity(notes);
8665 break :blk @intCast(u32, notes_start);8598 break :blk @intCast(u32, notes_start);
...@@ -8700,7 +8633,7 @@ fn failTokNotes(...@@ -8700,7 +8633,7 @@ fn failTokNotes(
8700 }8633 }
8701 const notes_index: u32 = if (notes.len != 0) blk: {8634 const notes_index: u32 = if (notes.len != 0) blk: {
8702 const notes_start = astgen.extra.items.len;8635 const notes_start = astgen.extra.items.len;
8703 try astgen.extra.ensureCapacity(astgen.gpa, notes_start + 1 + notes.len);8636 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len);
8704 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));8637 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));
8705 astgen.extra.appendSliceAssumeCapacity(notes);8638 astgen.extra.appendSliceAssumeCapacity(notes);
8706 break :blk @intCast(u32, notes_start);8639 break :blk @intCast(u32, notes_start);
...@@ -8864,7 +8797,7 @@ fn strLitNodeAsString(astgen: *AstGen, node: ast.Node.Index) !IndexSlice {...@@ -8864,7 +8797,7 @@ fn strLitNodeAsString(astgen: *AstGen, node: ast.Node.Index) !IndexSlice {
8864 while (tok_i <= end) : (tok_i += 1) {8797 while (tok_i <= end) : (tok_i += 1) {
8865 const slice = tree.tokenSlice(tok_i);8798 const slice = tree.tokenSlice(tok_i);
8866 const line_bytes = slice[2 .. slice.len - 1];8799 const line_bytes = slice[2 .. slice.len - 1];
8867 try string_bytes.ensureCapacity(gpa, string_bytes.items.len + line_bytes.len + 1);8800 try string_bytes.ensureUnusedCapacity(gpa, line_bytes.len + 1);
8868 string_bytes.appendAssumeCapacity('\n');8801 string_bytes.appendAssumeCapacity('\n');
8869 string_bytes.appendSliceAssumeCapacity(line_bytes);8802 string_bytes.appendSliceAssumeCapacity(line_bytes);
8870 }8803 }
...@@ -9131,8 +9064,8 @@ const GenZir = struct {...@@ -9131,8 +9064,8 @@ const GenZir = struct {
91319064
9132 fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void {9065 fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void {
9133 const gpa = gz.astgen.gpa;9066 const gpa = gz.astgen.gpa;
9134 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +9067 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len +
9135 @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);9068 gz.instructions.items.len);
9136 const zir_datas = gz.astgen.instructions.items(.data);9069 const zir_datas = gz.astgen.instructions.items(.data);
9137 zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity(9070 zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity(
9138 Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },9071 Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },
...@@ -9142,8 +9075,8 @@ const GenZir = struct {...@@ -9142,8 +9075,8 @@ const GenZir = struct {
91429075
9143 fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void {9076 fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void {
9144 const gpa = gz.astgen.gpa;9077 const gpa = gz.astgen.gpa;
9145 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +9078 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len +
9146 @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);9079 gz.instructions.items.len);
9147 const zir_datas = gz.astgen.instructions.items(.data);9080 const zir_datas = gz.astgen.instructions.items(.data);
9148 zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity(9081 zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity(
9149 Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },9082 Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },
...@@ -9155,8 +9088,8 @@ const GenZir = struct {...@@ -9155,8 +9088,8 @@ const GenZir = struct {
9155 /// `store_to_block_ptr` instructions with lhs set to .none.9088 /// `store_to_block_ptr` instructions with lhs set to .none.
9156 fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void {9089 fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void {
9157 const gpa = gz.astgen.gpa;9090 const gpa = gz.astgen.gpa;
9158 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +9091 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Block).Struct.fields.len +
9159 @typeInfo(Zir.Inst.Block).Struct.fields.len + gz.instructions.items.len);9092 gz.instructions.items.len);
9160 const zir_datas = gz.astgen.instructions.items(.data);9093 const zir_datas = gz.astgen.instructions.items(.data);
9161 const zir_tags = gz.astgen.instructions.items(.tag);9094 const zir_tags = gz.astgen.instructions.items(.tag);
9162 const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{9095 const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{
...@@ -9177,7 +9110,6 @@ const GenZir = struct {...@@ -9177,7 +9110,6 @@ const GenZir = struct {
91779110
9178 fn addFunc(gz: *GenZir, args: struct {9111 fn addFunc(gz: *GenZir, args: struct {
9179 src_node: ast.Node.Index,9112 src_node: ast.Node.Index,
9180 param_types: []const Zir.Inst.Ref,
9181 body: []const Zir.Inst.Index,9113 body: []const Zir.Inst.Index,
9182 ret_ty: Zir.Inst.Ref,9114 ret_ty: Zir.Inst.Ref,
9183 cc: Zir.Inst.Ref,9115 cc: Zir.Inst.Ref,
...@@ -9187,8 +9119,6 @@ const GenZir = struct {...@@ -9187,8 +9119,6 @@ const GenZir = struct {
9187 is_inferred_error: bool,9119 is_inferred_error: bool,
9188 is_test: bool,9120 is_test: bool,
9189 is_extern: bool,9121 is_extern: bool,
9190 cur_bit_bag: u32,
9191 bit_bag: []const u32,
9192 }) !Zir.Inst.Ref {9122 }) !Zir.Inst.Ref {
9193 assert(args.src_node != 0);9123 assert(args.src_node != 0);
9194 assert(args.ret_ty != .none);9124 assert(args.ret_ty != .none);
...@@ -9226,19 +9156,14 @@ const GenZir = struct {...@@ -9226,19 +9156,14 @@ const GenZir = struct {
9226 src_locs = &src_locs_buffer;9156 src_locs = &src_locs_buffer;
9227 }9157 }
92289158
9229 const any_are_comptime = args.cur_bit_bag != 0 or for (args.bit_bag) |x| {
9230 if (x != 0) break true;
9231 } else false;
9232
9233 if (args.cc != .none or args.lib_name != 0 or9159 if (args.cc != .none or args.lib_name != 0 or
9234 args.is_var_args or args.is_test or args.align_inst != .none or9160 args.is_var_args or args.is_test or args.align_inst != .none or
9235 args.is_extern or any_are_comptime)9161 args.is_extern)
9236 {9162 {
9237 try astgen.extra.ensureUnusedCapacity(9163 try astgen.extra.ensureUnusedCapacity(
9238 gpa,9164 gpa,
9239 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +9165 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +
9240 @boolToInt(any_are_comptime) + args.bit_bag.len +9166 args.body.len + src_locs.len +
9241 args.param_types.len + args.body.len + src_locs.len +
9242 @boolToInt(args.lib_name != 0) +9167 @boolToInt(args.lib_name != 0) +
9243 @boolToInt(args.align_inst != .none) +9168 @boolToInt(args.align_inst != .none) +
9244 @boolToInt(args.cc != .none),9169 @boolToInt(args.cc != .none),
...@@ -9246,7 +9171,6 @@ const GenZir = struct {...@@ -9246,7 +9171,6 @@ const GenZir = struct {
9246 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{9171 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{
9247 .src_node = gz.nodeIndexToRelative(args.src_node),9172 .src_node = gz.nodeIndexToRelative(args.src_node),
9248 .return_type = args.ret_ty,9173 .return_type = args.ret_ty,
9249 .param_types_len = @intCast(u32, args.param_types.len),
9250 .body_len = @intCast(u32, args.body.len),9174 .body_len = @intCast(u32, args.body.len),
9251 });9175 });
9252 if (args.lib_name != 0) {9176 if (args.lib_name != 0) {
...@@ -9258,11 +9182,6 @@ const GenZir = struct {...@@ -9258,11 +9182,6 @@ const GenZir = struct {
9258 if (args.align_inst != .none) {9182 if (args.align_inst != .none) {
9259 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));9183 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
9260 }9184 }
9261 if (any_are_comptime) {
9262 astgen.extra.appendSliceAssumeCapacity(args.bit_bag); // Likely empty.
9263 astgen.extra.appendAssumeCapacity(args.cur_bit_bag);
9264 }
9265 astgen.appendRefsAssumeCapacity(args.param_types);
9266 astgen.extra.appendSliceAssumeCapacity(args.body);9185 astgen.extra.appendSliceAssumeCapacity(args.body);
9267 astgen.extra.appendSliceAssumeCapacity(src_locs);9186 astgen.extra.appendSliceAssumeCapacity(src_locs);
92689187
...@@ -9279,7 +9198,6 @@ const GenZir = struct {...@@ -9279,7 +9198,6 @@ const GenZir = struct {
9279 .has_align = args.align_inst != .none,9198 .has_align = args.align_inst != .none,
9280 .is_test = args.is_test,9199 .is_test = args.is_test,
9281 .is_extern = args.is_extern,9200 .is_extern = args.is_extern,
9282 .has_comptime_bits = any_are_comptime,
9283 }),9201 }),
9284 .operand = payload_index,9202 .operand = payload_index,
9285 } },9203 } },
...@@ -9290,15 +9208,13 @@ const GenZir = struct {...@@ -9290,15 +9208,13 @@ const GenZir = struct {
9290 try gz.astgen.extra.ensureUnusedCapacity(9208 try gz.astgen.extra.ensureUnusedCapacity(
9291 gpa,9209 gpa,
9292 @typeInfo(Zir.Inst.Func).Struct.fields.len +9210 @typeInfo(Zir.Inst.Func).Struct.fields.len +
9293 args.param_types.len + args.body.len + src_locs.len,9211 args.body.len + src_locs.len,
9294 );9212 );
92959213
9296 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{9214 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{
9297 .return_type = args.ret_ty,9215 .return_type = args.ret_ty,
9298 .param_types_len = @intCast(u32, args.param_types.len),
9299 .body_len = @intCast(u32, args.body.len),9216 .body_len = @intCast(u32, args.body.len),
9300 });9217 });
9301 gz.astgen.appendRefsAssumeCapacity(args.param_types);
9302 gz.astgen.extra.appendSliceAssumeCapacity(args.body);9218 gz.astgen.extra.appendSliceAssumeCapacity(args.body);
9303 gz.astgen.extra.appendSliceAssumeCapacity(src_locs);9219 gz.astgen.extra.appendSliceAssumeCapacity(src_locs);
93049220
...@@ -9380,10 +9296,10 @@ const GenZir = struct {...@@ -9380,10 +9296,10 @@ const GenZir = struct {
9380 assert(callee != .none);9296 assert(callee != .none);
9381 assert(src_node != 0);9297 assert(src_node != 0);
9382 const gpa = gz.astgen.gpa;9298 const gpa = gz.astgen.gpa;
9383 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);9299 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9384 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);9300 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
9385 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +9301 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Call).Struct.fields.len +
9386 @typeInfo(Zir.Inst.Call).Struct.fields.len + args.len);9302 args.len);
93879303
9388 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Call{9304 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Call{
9389 .callee = callee,9305 .callee = callee,
...@@ -9412,8 +9328,8 @@ const GenZir = struct {...@@ -9412,8 +9328,8 @@ const GenZir = struct {
9412 ) !Zir.Inst.Index {9328 ) !Zir.Inst.Index {
9413 assert(lhs != .none);9329 assert(lhs != .none);
9414 const gpa = gz.astgen.gpa;9330 const gpa = gz.astgen.gpa;
9415 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);9331 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9416 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);9332 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
94179333
9418 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9334 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
9419 gz.astgen.instructions.appendAssumeCapacity(.{9335 gz.astgen.instructions.appendAssumeCapacity(.{
...@@ -9486,8 +9402,8 @@ const GenZir = struct {...@@ -9486,8 +9402,8 @@ const GenZir = struct {
9486 extra: anytype,9402 extra: anytype,
9487 ) !Zir.Inst.Ref {9403 ) !Zir.Inst.Ref {
9488 const gpa = gz.astgen.gpa;9404 const gpa = gz.astgen.gpa;
9489 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);9405 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9490 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);9406 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
94919407
9492 const payload_index = try gz.astgen.addExtra(extra);9408 const payload_index = try gz.astgen.addExtra(extra);
9493 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9409 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
...@@ -9502,6 +9418,30 @@ const GenZir = struct {...@@ -9502,6 +9418,30 @@ const GenZir = struct {
9502 return indexToRef(new_index);9418 return indexToRef(new_index);
9503 }9419 }
95049420
9421 fn addPlTok(
9422 gz: *GenZir,
9423 tag: Zir.Inst.Tag,
9424 /// Absolute token index. This function does the conversion to Decl offset.
9425 abs_tok_index: ast.TokenIndex,
9426 extra: anytype,
9427 ) !Zir.Inst.Ref {
9428 const gpa = gz.astgen.gpa;
9429 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9430 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
9431
9432 const payload_index = try gz.astgen.addExtra(extra);
9433 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
9434 gz.astgen.instructions.appendAssumeCapacity(.{
9435 .tag = tag,
9436 .data = .{ .pl_tok = .{
9437 .src_tok = gz.tokenIndexToRelative(abs_tok_index),
9438 .payload_index = payload_index,
9439 } },
9440 });
9441 gz.instructions.appendAssumeCapacity(new_index);
9442 return indexToRef(new_index);
9443 }
9444
9505 fn addExtendedPayload(9445 fn addExtendedPayload(
9506 gz: *GenZir,9446 gz: *GenZir,
9507 opcode: Zir.Inst.Extended,9447 opcode: Zir.Inst.Extended,
...@@ -9509,8 +9449,8 @@ const GenZir = struct {...@@ -9509,8 +9449,8 @@ const GenZir = struct {
9509 ) !Zir.Inst.Ref {9449 ) !Zir.Inst.Ref {
9510 const gpa = gz.astgen.gpa;9450 const gpa = gz.astgen.gpa;
95119451
9512 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);9452 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9513 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);9453 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
95149454
9515 const payload_index = try gz.astgen.addExtra(extra);9455 const payload_index = try gz.astgen.addExtra(extra);
9516 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9456 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
...@@ -9566,8 +9506,8 @@ const GenZir = struct {...@@ -9566,8 +9506,8 @@ const GenZir = struct {
9566 elem_type: Zir.Inst.Ref,9506 elem_type: Zir.Inst.Ref,
9567 ) !Zir.Inst.Ref {9507 ) !Zir.Inst.Ref {
9568 const gpa = gz.astgen.gpa;9508 const gpa = gz.astgen.gpa;
9569 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);9509 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9570 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);9510 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
95719511
9572 const payload_index = try gz.astgen.addExtra(Zir.Inst.ArrayTypeSentinel{9512 const payload_index = try gz.astgen.addExtra(Zir.Inst.ArrayTypeSentinel{
9573 .sentinel = sentinel,9513 .sentinel = sentinel,
...@@ -9822,7 +9762,7 @@ const GenZir = struct {...@@ -9822,7 +9762,7 @@ const GenZir = struct {
9822 /// Leaves the `payload_index` field undefined.9762 /// Leaves the `payload_index` field undefined.
9823 fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {9763 fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {
9824 const gpa = gz.astgen.gpa;9764 const gpa = gz.astgen.gpa;
9825 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);9765 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9826 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9766 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
9827 try gz.astgen.instructions.append(gpa, .{9767 try gz.astgen.instructions.append(gpa, .{
9828 .tag = tag,9768 .tag = tag,
src/Module.zig+1-1
...@@ -3714,7 +3714,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {...@@ -3714,7 +3714,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
3714 decl.analysis = .outdated;3714 decl.analysis = .outdated;
3715}3715}
37163716
3717fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node.Index) !*Decl {3717pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node.Index) !*Decl {
3718 // If we have emit-h then we must allocate a bigger structure to store the emit-h state.3718 // If we have emit-h then we must allocate a bigger structure to store the emit-h state.
3719 const new_decl: *Decl = if (mod.emit_h != null) blk: {3719 const new_decl: *Decl = if (mod.emit_h != null) blk: {
3720 const parent_struct = try mod.gpa.create(DeclPlusEmitH);3720 const parent_struct = try mod.gpa.create(DeclPlusEmitH);
src/Sema.zig+124-69
...@@ -44,6 +44,7 @@ branch_count: u32 = 0,...@@ -44,6 +44,7 @@ branch_count: u32 = 0,
44/// contain a mapped source location.44/// contain a mapped source location.
45src: LazySrcLoc = .{ .token_offset = 0 },45src: LazySrcLoc = .{ .token_offset = 0 },
46next_arg_index: usize = 0,46next_arg_index: usize = 0,
47params: std.ArrayListUnmanaged(Param) = .{},
47decl_val_table: std.AutoHashMapUnmanaged(*Decl, Air.Inst.Ref) = .{},48decl_val_table: std.AutoHashMapUnmanaged(*Decl, Air.Inst.Ref) = .{},
4849
49const std = @import("std");50const std = @import("std");
...@@ -68,6 +69,13 @@ const LazySrcLoc = Module.LazySrcLoc;...@@ -68,6 +69,13 @@ const LazySrcLoc = Module.LazySrcLoc;
68const RangeSet = @import("RangeSet.zig");69const RangeSet = @import("RangeSet.zig");
69const target_util = @import("target.zig");70const target_util = @import("target.zig");
7071
72const Param = struct {
73 name: [:0]const u8,
74 /// `none` means `anytype`.
75 ty: Air.Inst.Ref,
76 is_comptime: bool,
77};
78
71pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);79pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);
7280
73pub fn deinit(sema: *Sema) void {81pub fn deinit(sema: *Sema) void {
...@@ -91,8 +99,7 @@ pub fn analyzeFnBody(...@@ -91,8 +99,7 @@ pub fn analyzeFnBody(
91 .func, .func_inferred => blk: {99 .func, .func_inferred => blk: {
92 const inst_data = datas[fn_body_inst].pl_node;100 const inst_data = datas[fn_body_inst].pl_node;
93 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);101 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
94 const param_types_len = extra.data.param_types_len;102 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
95 const body = sema.code.extra[extra.end + param_types_len ..][0..extra.data.body_len];
96 break :blk body;103 break :blk body;
97 },104 },
98 .extended => blk: {105 .extended => blk: {
...@@ -104,10 +111,6 @@ pub fn analyzeFnBody(...@@ -104,10 +111,6 @@ pub fn analyzeFnBody(
104 extra_index += @boolToInt(small.has_lib_name);111 extra_index += @boolToInt(small.has_lib_name);
105 extra_index += @boolToInt(small.has_cc);112 extra_index += @boolToInt(small.has_cc);
106 extra_index += @boolToInt(small.has_align);113 extra_index += @boolToInt(small.has_align);
107 if (small.has_comptime_bits) {
108 extra_index += (extra.data.param_types_len + 31) / 32;
109 }
110 extra_index += extra.data.param_types_len;
111 const body = sema.code.extra[extra_index..][0..extra.data.body_len];114 const body = sema.code.extra[extra_index..][0..extra.data.body_len];
112 break :blk body;115 break :blk body;
113 },116 },
...@@ -162,7 +165,6 @@ pub fn analyzeBody(...@@ -162,7 +165,6 @@ pub fn analyzeBody(
162 const inst = body[i];165 const inst = body[i];
163 const air_inst: Air.Inst.Ref = switch (tags[inst]) {166 const air_inst: Air.Inst.Ref = switch (tags[inst]) {
164 // zig fmt: off167 // zig fmt: off
165 .arg => try sema.zirArg(block, inst),
166 .alloc => try sema.zirAlloc(block, inst),168 .alloc => try sema.zirAlloc(block, inst),
167 .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),169 .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
168 .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),170 .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
...@@ -404,6 +406,26 @@ pub fn analyzeBody(...@@ -404,6 +406,26 @@ pub fn analyzeBody(
404 // continue the loop.406 // continue the loop.
405 // We also know that they cannot be referenced later, so we avoid407 // We also know that they cannot be referenced later, so we avoid
406 // putting them into the map.408 // putting them into the map.
409 .param => {
410 try sema.zirParam(inst, false);
411 i += 1;
412 continue;
413 },
414 .param_comptime => {
415 try sema.zirParam(inst, true);
416 i += 1;
417 continue;
418 },
419 .param_anytype => {
420 try sema.zirParamAnytype(inst, false);
421 i += 1;
422 continue;
423 },
424 .param_anytype_comptime => {
425 try sema.zirParamAnytype(inst, true);
426 i += 1;
427 continue;
428 },
407 .breakpoint => {429 .breakpoint => {
408 try sema.zirBreakpoint(block, inst);430 try sema.zirBreakpoint(block, inst);
409 i += 1;431 i += 1;
...@@ -1358,23 +1380,34 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co...@@ -1358,23 +1380,34 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co
1358 return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);1380 return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);
1359}1381}
13601382
1361fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {1383fn zirParam(sema: *Sema, inst: Zir.Inst.Index, is_comptime: bool) CompileError!void {
1362 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;1384 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
1363 const arg_name = inst_data.get(sema.code);1385 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index).data;
1364 const arg_index = sema.next_arg_index;1386 const param_name = sema.code.nullTerminatedString(extra.name);
1365 sema.next_arg_index += 1;
13661387
1367 // TODO check if arg_name shadows a Decl1388 // TODO check if param_name shadows a Decl. This only needs to be done if
1368 _ = arg_name;1389 // usingnamespace is implemented.
13691390
1370 if (block.inlining) |_| {1391 const param_ty = sema.resolveInst(extra.ty);
1371 return sema.param_inst_list[arg_index];1392 try sema.params.append(sema.gpa, .{
1372 }1393 .name = param_name,
1394 .ty = param_ty,
1395 .is_comptime = is_comptime,
1396 });
1397}
1398
1399fn zirParamAnytype(sema: *Sema, inst: Zir.Inst.Index, is_comptime: bool) CompileError!void {
1400 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
1401 const param_name = inst_data.get(sema.code);
13731402
1374 // Set the name of the Air.Arg instruction for use by codegen debug info.1403 // TODO check if param_name shadows a Decl. This only needs to be done if
1375 const air_arg = sema.param_inst_list[arg_index];1404 // usingnamespace is implemented.
1376 sema.air_instructions.items(.data)[Air.refToIndex(air_arg).?].ty_str.str = inst_data.start;1405
1377 return air_arg;1406 try sema.params.append(sema.gpa, .{
1407 .name = param_name,
1408 .ty = .none,
1409 .is_comptime = is_comptime,
1410 });
1378}1411}
13791412
1380fn zirAllocExtended(1413fn zirAllocExtended(
...@@ -2395,26 +2428,29 @@ fn analyzeCall(...@@ -2395,26 +2428,29 @@ fn analyzeCall(
2395 ensure_result_used: bool,2428 ensure_result_used: bool,
2396 args: []const Air.Inst.Ref,2429 args: []const Air.Inst.Ref,
2397) CompileError!Air.Inst.Ref {2430) CompileError!Air.Inst.Ref {
2431 const mod = sema.mod;
2432
2398 const func_ty = sema.typeOf(func);2433 const func_ty = sema.typeOf(func);
2399 if (func_ty.zigTypeTag() != .Fn)2434 if (func_ty.zigTypeTag() != .Fn)
2400 return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func_ty});2435 return mod.fail(&block.base, func_src, "type '{}' not a function", .{func_ty});
24012436
2402 const cc = func_ty.fnCallingConvention();2437 const func_ty_info = func_ty.fnInfo();
2438 const cc = func_ty_info.cc;
2403 if (cc == .Naked) {2439 if (cc == .Naked) {
2404 // TODO add error note: declared here2440 // TODO add error note: declared here
2405 return sema.mod.fail(2441 return mod.fail(
2406 &block.base,2442 &block.base,
2407 func_src,2443 func_src,
2408 "unable to call function with naked calling convention",2444 "unable to call function with naked calling convention",
2409 .{},2445 .{},
2410 );2446 );
2411 }2447 }
2412 const fn_params_len = func_ty.fnParamLen();2448 const fn_params_len = func_ty_info.param_types.len;
2413 if (func_ty.fnIsVarArgs()) {2449 if (func_ty_info.is_var_args) {
2414 assert(cc == .C);2450 assert(cc == .C);
2415 if (args.len < fn_params_len) {2451 if (args.len < fn_params_len) {
2416 // TODO add error note: declared here2452 // TODO add error note: declared here
2417 return sema.mod.fail(2453 return mod.fail(
2418 &block.base,2454 &block.base,
2419 func_src,2455 func_src,
2420 "expected at least {d} argument(s), found {d}",2456 "expected at least {d} argument(s), found {d}",
...@@ -2423,7 +2459,7 @@ fn analyzeCall(...@@ -2423,7 +2459,7 @@ fn analyzeCall(
2423 }2459 }
2424 } else if (fn_params_len != args.len) {2460 } else if (fn_params_len != args.len) {
2425 // TODO add error note: declared here2461 // TODO add error note: declared here
2426 return sema.mod.fail(2462 return mod.fail(
2427 &block.base,2463 &block.base,
2428 func_src,2464 func_src,
2429 "expected {d} argument(s), found {d}",2465 "expected {d} argument(s), found {d}",
...@@ -2442,7 +2478,7 @@ fn analyzeCall(...@@ -2442,7 +2478,7 @@ fn analyzeCall(
2442 .never_inline,2478 .never_inline,
2443 .no_async,2479 .no_async,
2444 .always_tail,2480 .always_tail,
2445 => return sema.mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{2481 => return mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{
2446 modifier,2482 modifier,
2447 }),2483 }),
2448 }2484 }
...@@ -2451,12 +2487,12 @@ fn analyzeCall(...@@ -2451,12 +2487,12 @@ fn analyzeCall(
24512487
2452 const is_comptime_call = block.is_comptime or modifier == .compile_time;2488 const is_comptime_call = block.is_comptime or modifier == .compile_time;
2453 const is_inline_call = is_comptime_call or modifier == .always_inline or2489 const is_inline_call = is_comptime_call or modifier == .always_inline or
2454 func_ty.fnCallingConvention() == .Inline;2490 func_ty_info.cc == .Inline;
2455 const result: Air.Inst.Ref = if (is_inline_call) res: {2491 const result: Air.Inst.Ref = if (is_inline_call) res: {
2456 const func_val = try sema.resolveConstValue(block, func_src, func);2492 const func_val = try sema.resolveConstValue(block, func_src, func);
2457 const module_fn = switch (func_val.tag()) {2493 const module_fn = switch (func_val.tag()) {
2458 .function => func_val.castTag(.function).?.data,2494 .function => func_val.castTag(.function).?.data,
2459 .extern_fn => return sema.mod.fail(&block.base, call_src, "{s} call of extern function", .{2495 .extern_fn => return mod.fail(&block.base, call_src, "{s} call of extern function", .{
2460 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),2496 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
2461 }),2497 }),
2462 else => unreachable,2498 else => unreachable,
...@@ -2535,10 +2571,46 @@ fn analyzeCall(...@@ -2535,10 +2571,46 @@ fn analyzeCall(
2535 const result = try sema.analyzeBlockBody(block, call_src, &child_block, merges);2571 const result = try sema.analyzeBlockBody(block, call_src, &child_block, merges);
25362572
2537 break :res result;2573 break :res result;
2574 } else if (func_ty_info.is_generic) {
2575 const func_val = try sema.resolveConstValue(block, func_src, func);
2576 const module_fn = func_val.castTag(.function).?.data;
2577 // Check the Module's generic function map with an adapted context, so that we
2578 // can match against `args` rather than doing the work below to create a generic Scope
2579 // only to junk it if it matches an existing instantiation.
2580 // TODO
2581
2582 // Create a Decl for the new function.
2583 const generic_namespace = try sema.arena.create(Module.Scope.Namespace);
2584 generic_namespace.* = .{
2585 .parent = block.src_decl.namespace,
2586 .file_scope = block.src_decl.namespace.file_scope,
2587 .ty = func_ty,
2588 };
2589 const new_decl = try mod.allocateNewDecl(generic_namespace, module_fn.owner_decl.src_node);
2590 _ = new_decl;
2591
2592 // Iterate over the parameters that are comptime, evaluating their type expressions
2593 // inside a Scope which contains the previous parameters.
2594 //for (args) |arg, arg_i| {
2595 //}
2596
2597 // Create a new Fn with only the runtime-known parameters.
2598 // TODO
2599
2600 // Populate the Decl ty/val with the function and its type.
2601 // TODO
2602
2603 // Queue up a `codegen_func` work item for the new Fn, making sure it will have
2604 // `analyzeFnBody` called with the Scope which contains the comptime parameters.
2605 // TODO
2606
2607 // Save it into the Module's generic function map.
2608 // TODO
2609
2610 // Call it the same as a runtime function.
2611 // TODO
2612 return mod.fail(&block.base, func_src, "TODO implement generic fn call", .{});
2538 } else res: {2613 } else res: {
2539 if (func_ty.fnIsGeneric()) {
2540 return sema.mod.fail(&block.base, func_src, "TODO implement generic fn call", .{});
2541 }
2542 try sema.requireRuntimeBlock(block, call_src);2614 try sema.requireRuntimeBlock(block, call_src);
2543 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +2615 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
2544 args.len);2616 args.len);
...@@ -3186,13 +3258,12 @@ fn zirFunc(...@@ -3186,13 +3258,12 @@ fn zirFunc(
31863258
3187 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;3259 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
3188 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);3260 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
3189 const param_types = sema.code.refSlice(extra.end, extra.data.param_types_len);
31903261
3191 var body_inst: Zir.Inst.Index = 0;3262 var body_inst: Zir.Inst.Index = 0;
3192 var src_locs: Zir.Inst.Func.SrcLocs = undefined;3263 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
3193 if (extra.data.body_len != 0) {3264 if (extra.data.body_len != 0) {
3194 body_inst = inst;3265 body_inst = inst;
3195 const extra_index = extra.end + extra.data.param_types_len + extra.data.body_len;3266 const extra_index = extra.end + extra.data.body_len;
3196 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;3267 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
3197 }3268 }
31983269
...@@ -3204,7 +3275,6 @@ fn zirFunc(...@@ -3204,7 +3275,6 @@ fn zirFunc(
3204 return sema.funcCommon(3275 return sema.funcCommon(
3205 block,3276 block,
3206 inst_data.src_node,3277 inst_data.src_node,
3207 param_types,
3208 body_inst,3278 body_inst,
3209 extra.data.return_type,3279 extra.data.return_type,
3210 cc,3280 cc,
...@@ -3214,7 +3284,6 @@ fn zirFunc(...@@ -3214,7 +3284,6 @@ fn zirFunc(
3214 false,3284 false,
3215 src_locs,3285 src_locs,
3216 null,3286 null,
3217 &.{},
3218 );3287 );
3219}3288}
32203289
...@@ -3222,7 +3291,6 @@ fn funcCommon(...@@ -3222,7 +3291,6 @@ fn funcCommon(
3222 sema: *Sema,3291 sema: *Sema,
3223 block: *Scope.Block,3292 block: *Scope.Block,
3224 src_node_offset: i32,3293 src_node_offset: i32,
3225 zir_param_types: []const Zir.Inst.Ref,
3226 body_inst: Zir.Inst.Index,3294 body_inst: Zir.Inst.Index,
3227 zir_return_type: Zir.Inst.Ref,3295 zir_return_type: Zir.Inst.Ref,
3228 cc: std.builtin.CallingConvention,3296 cc: std.builtin.CallingConvention,
...@@ -3232,7 +3300,6 @@ fn funcCommon(...@@ -3232,7 +3300,6 @@ fn funcCommon(
3232 is_extern: bool,3300 is_extern: bool,
3233 src_locs: Zir.Inst.Func.SrcLocs,3301 src_locs: Zir.Inst.Func.SrcLocs,
3234 opt_lib_name: ?[]const u8,3302 opt_lib_name: ?[]const u8,
3235 comptime_bits: []const u32,
3236) CompileError!Air.Inst.Ref {3303) CompileError!Air.Inst.Ref {
3237 const src: LazySrcLoc = .{ .node_offset = src_node_offset };3304 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
3238 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };3305 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
...@@ -3245,7 +3312,7 @@ fn funcCommon(...@@ -3245,7 +3312,7 @@ fn funcCommon(
32453312
3246 const fn_ty: Type = fn_ty: {3313 const fn_ty: Type = fn_ty: {
3247 // Hot path for some common function types.3314 // Hot path for some common function types.
3248 if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value and3315 if (sema.params.items.len == 0 and !var_args and align_val.tag() == .null_value and
3249 !inferred_error_set)3316 !inferred_error_set)
3250 {3317 {
3251 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {3318 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
...@@ -3266,22 +3333,21 @@ fn funcCommon(...@@ -3266,22 +3333,21 @@ fn funcCommon(
3266 }3333 }
32673334
3268 var any_are_comptime = false;3335 var any_are_comptime = false;
3269 const param_types = try sema.arena.alloc(Type, zir_param_types.len);3336 const param_types = try sema.arena.alloc(Type, sema.params.items.len);
3270 for (zir_param_types) |param_type, i| {3337 const comptime_params = try sema.arena.alloc(bool, sema.params.items.len);
3271 // TODO make a compile error from `resolveType` report the source location3338 for (sema.params.items) |param, i| {
3272 // of the specific parameter. Will need to take a similar strategy as3339 if (param.ty == .none) {
3273 // `resolveSwitchItemVal` to avoid resolving the source location unless3340 param_types[i] = Type.initTag(.noreturn); // indicates anytype
3274 // we actually need to report an error.3341 } else {
3275 const param_src = src;3342 // TODO make a compile error from `resolveType` report the source location
3276 param_types[i] = try sema.resolveType(block, param_src, param_type);3343 // of the specific parameter. Will need to take a similar strategy as
32773344 // `resolveSwitchItemVal` to avoid resolving the source location unless
3278 any_are_comptime = any_are_comptime or blk: {3345 // we actually need to report an error.
3279 if (comptime_bits.len == 0)3346 const param_src = src;
3280 break :blk false;3347 param_types[i] = try sema.resolveType(block, param_src, param.ty);
3281 const bag = comptime_bits[i / 32];3348 }
3282 const is_comptime = @truncate(u1, bag >> @intCast(u5, i % 32)) != 0;3349 comptime_params[i] = param.is_comptime;
3283 break :blk is_comptime;3350 any_are_comptime = any_are_comptime or param.is_comptime;
3284 };
3285 }3351 }
32863352
3287 if (align_val.tag() != .null_value) {3353 if (align_val.tag() != .null_value) {
...@@ -3301,6 +3367,7 @@ fn funcCommon(...@@ -3301,6 +3367,7 @@ fn funcCommon(
33013367
3302 break :fn_ty try Type.Tag.function.create(sema.arena, .{3368 break :fn_ty try Type.Tag.function.create(sema.arena, .{
3303 .param_types = param_types,3369 .param_types = param_types,
3370 .comptime_params = comptime_params.ptr,
3304 .return_type = return_type,3371 .return_type = return_type,
3305 .cc = cc,3372 .cc = cc,
3306 .is_var_args = var_args,3373 .is_var_args = var_args,
...@@ -6545,16 +6612,6 @@ fn zirFuncExtended(...@@ -6545,16 +6612,6 @@ fn zirFuncExtended(
6545 break :blk align_tv.val;6612 break :blk align_tv.val;
6546 } else Value.initTag(.null_value);6613 } else Value.initTag(.null_value);
65476614
6548 const comptime_bits: []const u32 = if (!small.has_comptime_bits) &.{} else blk: {
6549 const amt = (extra.data.param_types_len + 31) / 32;
6550 const bit_bags = sema.code.extra[extra_index..][0..amt];
6551 extra_index += amt;
6552 break :blk bit_bags;
6553 };
6554
6555 const param_types = sema.code.refSlice(extra_index, extra.data.param_types_len);
6556 extra_index += param_types.len;
6557
6558 var body_inst: Zir.Inst.Index = 0;6615 var body_inst: Zir.Inst.Index = 0;
6559 var src_locs: Zir.Inst.Func.SrcLocs = undefined;6616 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
6560 if (extra.data.body_len != 0) {6617 if (extra.data.body_len != 0) {
...@@ -6570,7 +6627,6 @@ fn zirFuncExtended(...@@ -6570,7 +6627,6 @@ fn zirFuncExtended(
6570 return sema.funcCommon(6627 return sema.funcCommon(
6571 block,6628 block,
6572 extra.data.src_node,6629 extra.data.src_node,
6573 param_types,
6574 body_inst,6630 body_inst,
6575 extra.data.return_type,6631 extra.data.return_type,
6576 cc,6632 cc,
...@@ -6580,7 +6636,6 @@ fn zirFuncExtended(...@@ -6580,7 +6636,6 @@ fn zirFuncExtended(
6580 is_extern,6636 is_extern,
6581 src_locs,6637 src_locs,
6582 lib_name,6638 lib_name,
6583 comptime_bits,
6584 );6639 );
6585}6640}
65866641
src/Zir.zig+65-56
...@@ -173,11 +173,22 @@ pub const Inst = struct {...@@ -173,11 +173,22 @@ pub const Inst = struct {
173 /// Twos complement wrapping integer addition.173 /// Twos complement wrapping integer addition.
174 /// Uses the `pl_node` union field. Payload is `Bin`.174 /// Uses the `pl_node` union field. Payload is `Bin`.
175 addwrap,175 addwrap,
176 /// Declares a parameter of the current function. Used for debug info and176 /// Declares a parameter of the current function. Used for:
177 /// for checking shadowing against declarations in the current namespace.177 /// * debug info
178 /// Uses the `str_tok` field. Token is the parameter name, string is the178 /// * checking shadowing against declarations in the current namespace
179 /// parameter name.179 /// * parameter type expressions referencing other parameters
180 arg,180 /// These occur in the block outside a function body (the same block as
181 /// contains the func instruction).
182 /// Uses the `pl_tok` field. Token is the parameter name, payload is a `Param`.
183 param,
184 /// Same as `param` except the parameter is marked comptime.
185 param_comptime,
186 /// Same as `param` except the parameter is marked anytype.
187 /// Uses the `str_tok` field. Token is the parameter name. String is the parameter name.
188 param_anytype,
189 /// Same as `param` except the parameter is marked both comptime and anytype.
190 /// Uses the `str_tok` field. Token is the parameter name. String is the parameter name.
191 param_anytype_comptime,
181 /// Array concatenation. `a ++ b`192 /// Array concatenation. `a ++ b`
182 /// Uses the `pl_node` union field. Payload is `Bin`.193 /// Uses the `pl_node` union field. Payload is `Bin`.
183 array_cat,194 array_cat,
...@@ -971,7 +982,10 @@ pub const Inst = struct {...@@ -971,7 +982,10 @@ pub const Inst = struct {
971 /// Function calls do not count.982 /// Function calls do not count.
972 pub fn isNoReturn(tag: Tag) bool {983 pub fn isNoReturn(tag: Tag) bool {
973 return switch (tag) {984 return switch (tag) {
974 .arg,985 .param,
986 .param_comptime,
987 .param_anytype,
988 .param_anytype_comptime,
975 .add,989 .add,
976 .addwrap,990 .addwrap,
977 .alloc,991 .alloc,
...@@ -1233,7 +1247,10 @@ pub const Inst = struct {...@@ -1233,7 +1247,10 @@ pub const Inst = struct {
1233 break :list std.enums.directEnumArray(Tag, Data.FieldEnum, 0, .{1247 break :list std.enums.directEnumArray(Tag, Data.FieldEnum, 0, .{
1234 .add = .pl_node,1248 .add = .pl_node,
1235 .addwrap = .pl_node,1249 .addwrap = .pl_node,
1236 .arg = .str_tok,1250 .param = .pl_tok,
1251 .param_comptime = .pl_tok,
1252 .param_anytype = .str_tok,
1253 .param_anytype_comptime = .str_tok,
1237 .array_cat = .pl_node,1254 .array_cat = .pl_node,
1238 .array_mul = .pl_node,1255 .array_mul = .pl_node,
1239 .array_type = .bin,1256 .array_type = .bin,
...@@ -2047,6 +2064,17 @@ pub const Inst = struct {...@@ -2047,6 +2064,17 @@ pub const Inst = struct {
2047 return .{ .node_offset = self.src_node };2064 return .{ .node_offset = self.src_node };
2048 }2065 }
2049 },2066 },
2067 pl_tok: struct {
2068 /// Offset from Decl AST token index.
2069 src_tok: ast.TokenIndex,
2070 /// index into extra.
2071 /// `Tag` determines what lives there.
2072 payload_index: u32,
2073
2074 pub fn src(self: @This()) LazySrcLoc {
2075 return .{ .token_offset = self.src_tok };
2076 }
2077 },
2050 bin: Bin,2078 bin: Bin,
2051 /// For strings which may contain null bytes.2079 /// For strings which may contain null bytes.
2052 str: struct {2080 str: struct {
...@@ -2170,6 +2198,7 @@ pub const Inst = struct {...@@ -2170,6 +2198,7 @@ pub const Inst = struct {
2170 un_node,2198 un_node,
2171 un_tok,2199 un_tok,
2172 pl_node,2200 pl_node,
2201 pl_tok,
2173 bin,2202 bin,
2174 str,2203 str,
2175 str_tok,2204 str_tok,
...@@ -2226,17 +2255,11 @@ pub const Inst = struct {...@@ -2226,17 +2255,11 @@ pub const Inst = struct {
2226 /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set2255 /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
2227 /// 1. cc: Ref, // if has_cc is set2256 /// 1. cc: Ref, // if has_cc is set
2228 /// 2. align: Ref, // if has_align is set2257 /// 2. align: Ref, // if has_align is set
2229 /// 3. comptime_bits: u32 // for every 32 parameters, if has_comptime_bits is set2258 /// 3. body: Index // for each body_len
2230 /// - sets of 1 bit:2259 /// 4. src_locs: Func.SrcLocs // if body_len != 0
2231 /// 0bX: whether corresponding parameter is comptime
2232 /// 4. param_type: Ref // for each param_types_len
2233 /// - `none` indicates that the param type is `anytype`.
2234 /// 5. body: Index // for each body_len
2235 /// 6. src_locs: Func.SrcLocs // if body_len != 0
2236 pub const ExtendedFunc = struct {2260 pub const ExtendedFunc = struct {
2237 src_node: i32,2261 src_node: i32,
2238 return_type: Ref,2262 return_type: Ref,
2239 param_types_len: u32,
2240 body_len: u32,2263 body_len: u32,
22412264
2242 pub const Small = packed struct {2265 pub const Small = packed struct {
...@@ -2247,8 +2270,7 @@ pub const Inst = struct {...@@ -2247,8 +2270,7 @@ pub const Inst = struct {
2247 has_align: bool,2270 has_align: bool,
2248 is_test: bool,2271 is_test: bool,
2249 is_extern: bool,2272 is_extern: bool,
2250 has_comptime_bits: bool,2273 _: u9 = undefined,
2251 _: u8 = undefined,
2252 };2274 };
2253 };2275 };
22542276
...@@ -2271,13 +2293,10 @@ pub const Inst = struct {...@@ -2271,13 +2293,10 @@ pub const Inst = struct {
2271 };2293 };
22722294
2273 /// Trailing:2295 /// Trailing:
2274 /// 0. param_type: Ref // for each param_types_len2296 /// 0. body: Index // for each body_len
2275 /// - `none` indicates that the param type is `anytype`.2297 /// 1. src_locs: SrcLocs // if body_len != 0
2276 /// 1. body: Index // for each body_len
2277 /// 2. src_locs: SrcLocs // if body_len != 0
2278 pub const Func = struct {2298 pub const Func = struct {
2279 return_type: Ref,2299 return_type: Ref,
2280 param_types_len: u32,
2281 body_len: u32,2300 body_len: u32,
22822301
2283 pub const SrcLocs = struct {2302 pub const SrcLocs = struct {
...@@ -2764,6 +2783,12 @@ pub const Inst = struct {...@@ -2764,6 +2783,12 @@ pub const Inst = struct {
2764 args: Ref,2783 args: Ref,
2765 };2784 };
27662785
2786 pub const Param = struct {
2787 /// Null-terminated string index.
2788 name: u32,
2789 ty: Ref,
2790 };
2791
2767 /// Trailing:2792 /// Trailing:
2768 /// 0. type_inst: Ref, // if small 0b000X is set2793 /// 0. type_inst: Ref, // if small 0b000X is set
2769 /// 1. align_inst: Ref, // if small 0b00X0 is set2794 /// 1. align_inst: Ref, // if small 0b00X0 is set
...@@ -3108,11 +3133,14 @@ const Writer = struct {...@@ -3108,11 +3133,14 @@ const Writer = struct {
3108 .decl_ref,3133 .decl_ref,
3109 .decl_val,3134 .decl_val,
3110 .import,3135 .import,
3111 .arg,
3112 .ret_err_value,3136 .ret_err_value,
3113 .ret_err_value_code,3137 .ret_err_value_code,
3138 .param_anytype,
3139 .param_anytype_comptime,
3114 => try self.writeStrTok(stream, inst),3140 => try self.writeStrTok(stream, inst),
31153141
3142 .param, .param_comptime => try self.writeParam(stream, inst),
3143
3116 .func => try self.writeFunc(stream, inst, false),3144 .func => try self.writeFunc(stream, inst, false),
3117 .func_inferred => try self.writeFunc(stream, inst, true),3145 .func_inferred => try self.writeFunc(stream, inst, true),
31183146
...@@ -3314,6 +3342,17 @@ const Writer = struct {...@@ -3314,6 +3342,17 @@ const Writer = struct {
3314 try self.writeSrc(stream, inst_data.src());3342 try self.writeSrc(stream, inst_data.src());
3315 }3343 }
33163344
3345 fn writeParam(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3346 const inst_data = self.code.instructions.items(.data)[inst].pl_tok;
3347 const extra = self.code.extraData(Inst.Param, inst_data.payload_index).data;
3348 try stream.print("\"{}\", ", .{
3349 std.zig.fmtEscapes(self.code.nullTerminatedString(extra.name)),
3350 });
3351 try self.writeInstRef(stream, extra.ty);
3352 try stream.writeAll(") ");
3353 try self.writeSrc(stream, inst_data.src());
3354 }
3355
3317 fn writePlNodeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void {3356 fn writePlNodeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3318 const inst_data = self.code.instructions.items(.data)[inst].pl_node;3357 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3319 const extra = self.code.extraData(Inst.Bin, inst_data.payload_index).data;3358 const extra = self.code.extraData(Inst.Bin, inst_data.payload_index).data;
...@@ -4277,16 +4316,14 @@ const Writer = struct {...@@ -4277,16 +4316,14 @@ const Writer = struct {
4277 const inst_data = self.code.instructions.items(.data)[inst].pl_node;4316 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
4278 const src = inst_data.src();4317 const src = inst_data.src();
4279 const extra = self.code.extraData(Inst.Func, inst_data.payload_index);4318 const extra = self.code.extraData(Inst.Func, inst_data.payload_index);
4280 const param_types = self.code.refSlice(extra.end, extra.data.param_types_len);4319 const body = self.code.extra[extra.end..][0..extra.data.body_len];
4281 const body = self.code.extra[extra.end + param_types.len ..][0..extra.data.body_len];
4282 var src_locs: Zir.Inst.Func.SrcLocs = undefined;4320 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
4283 if (body.len != 0) {4321 if (body.len != 0) {
4284 const extra_index = extra.end + param_types.len + body.len;4322 const extra_index = extra.end + body.len;
4285 src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;4323 src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
4286 }4324 }
4287 return self.writeFuncCommon(4325 return self.writeFuncCommon(
4288 stream,4326 stream,
4289 param_types,
4290 extra.data.return_type,4327 extra.data.return_type,
4291 inferred_error_set,4328 inferred_error_set,
4292 false,4329 false,
...@@ -4296,7 +4333,6 @@ const Writer = struct {...@@ -4296,7 +4333,6 @@ const Writer = struct {
4296 body,4333 body,
4297 src,4334 src,
4298 src_locs,4335 src_locs,
4299 &.{},
4300 );4336 );
4301 }4337 }
43024338
...@@ -4323,16 +4359,6 @@ const Writer = struct {...@@ -4323,16 +4359,6 @@ const Writer = struct {
4323 break :blk align_inst;4359 break :blk align_inst;
4324 };4360 };
43254361
4326 const comptime_bits: []const u32 = if (!small.has_comptime_bits) &.{} else blk: {
4327 const amt = (extra.data.param_types_len + 31) / 32;
4328 const bit_bags = self.code.extra[extra_index..][0..amt];
4329 extra_index += amt;
4330 break :blk bit_bags;
4331 };
4332
4333 const param_types = self.code.refSlice(extra_index, extra.data.param_types_len);
4334 extra_index += param_types.len;
4335
4336 const body = self.code.extra[extra_index..][0..extra.data.body_len];4362 const body = self.code.extra[extra_index..][0..extra.data.body_len];
4337 extra_index += body.len;4363 extra_index += body.len;
43384364
...@@ -4342,7 +4368,6 @@ const Writer = struct {...@@ -4342,7 +4368,6 @@ const Writer = struct {
4342 }4368 }
4343 return self.writeFuncCommon(4369 return self.writeFuncCommon(
4344 stream,4370 stream,
4345 param_types,
4346 extra.data.return_type,4371 extra.data.return_type,
4347 small.is_inferred_error,4372 small.is_inferred_error,
4348 small.is_var_args,4373 small.is_var_args,
...@@ -4352,7 +4377,6 @@ const Writer = struct {...@@ -4352,7 +4377,6 @@ const Writer = struct {
4352 body,4377 body,
4353 src,4378 src,
4354 src_locs,4379 src_locs,
4355 comptime_bits,
4356 );4380 );
4357 }4381 }
43584382
...@@ -4426,7 +4450,6 @@ const Writer = struct {...@@ -4426,7 +4450,6 @@ const Writer = struct {
4426 fn writeFuncCommon(4450 fn writeFuncCommon(
4427 self: *Writer,4451 self: *Writer,
4428 stream: anytype,4452 stream: anytype,
4429 param_types: []const Inst.Ref,
4430 ret_ty: Inst.Ref,4453 ret_ty: Inst.Ref,
4431 inferred_error_set: bool,4454 inferred_error_set: bool,
4432 var_args: bool,4455 var_args: bool,
...@@ -4436,19 +4459,7 @@ const Writer = struct {...@@ -4436,19 +4459,7 @@ const Writer = struct {
4436 body: []const Inst.Index,4459 body: []const Inst.Index,
4437 src: LazySrcLoc,4460 src: LazySrcLoc,
4438 src_locs: Zir.Inst.Func.SrcLocs,4461 src_locs: Zir.Inst.Func.SrcLocs,
4439 comptime_bits: []const u32,
4440 ) !void {4462 ) !void {
4441 try stream.writeAll("[");
4442 for (param_types) |param_type, i| {
4443 if (i != 0) try stream.writeAll(", ");
4444 if (comptime_bits.len != 0) {
4445 const bag = comptime_bits[i / 32];
4446 const is_comptime = @truncate(u1, bag >> @intCast(u5, i % 32)) != 0;
4447 try self.writeFlag(stream, "comptime ", is_comptime);
4448 }
4449 try self.writeInstRef(stream, param_type);
4450 }
4451 try stream.writeAll("], ");
4452 try self.writeInstRef(stream, ret_ty);4463 try self.writeInstRef(stream, ret_ty);
4453 try self.writeOptionalInstRef(stream, ", cc=", cc);4464 try self.writeOptionalInstRef(stream, ", cc=", cc);
4454 try self.writeOptionalInstRef(stream, ", align=", align_inst);4465 try self.writeOptionalInstRef(stream, ", align=", align_inst);
...@@ -4714,8 +4725,7 @@ fn findDeclsInner(...@@ -4714,8 +4725,7 @@ fn findDeclsInner(
47144725
4715 const inst_data = datas[inst].pl_node;4726 const inst_data = datas[inst].pl_node;
4716 const extra = zir.extraData(Inst.Func, inst_data.payload_index);4727 const extra = zir.extraData(Inst.Func, inst_data.payload_index);
4717 const param_types_len = extra.data.param_types_len;4728 const body = zir.extra[extra.end..][0..extra.data.body_len];
4718 const body = zir.extra[extra.end + param_types_len ..][0..extra.data.body_len];
4719 return zir.findDeclsBody(list, body);4729 return zir.findDeclsBody(list, body);
4720 },4730 },
4721 .extended => {4731 .extended => {
...@@ -4730,7 +4740,6 @@ fn findDeclsInner(...@@ -4730,7 +4740,6 @@ fn findDeclsInner(
4730 extra_index += @boolToInt(small.has_lib_name);4740 extra_index += @boolToInt(small.has_lib_name);
4731 extra_index += @boolToInt(small.has_cc);4741 extra_index += @boolToInt(small.has_cc);
4732 extra_index += @boolToInt(small.has_align);4742 extra_index += @boolToInt(small.has_align);
4733 extra_index += extra.data.param_types_len;
4734 const body = zir.extra[extra_index..][0..extra.data.body_len];4743 const body = zir.extra[extra_index..][0..extra.data.body_len];
4735 return zir.findDeclsBody(list, body);4744 return zir.findDeclsBody(list, body);
4736 },4745 },
src/type.zig+50-10
...@@ -759,12 +759,15 @@ pub const Type = extern union {...@@ -759,12 +759,15 @@ pub const Type = extern union {
759 for (payload.param_types) |param_type, i| {759 for (payload.param_types) |param_type, i| {
760 param_types[i] = try param_type.copy(allocator);760 param_types[i] = try param_type.copy(allocator);
761 }761 }
762 const other_comptime_params = payload.comptime_params[0..payload.param_types.len];
763 const comptime_params = try allocator.dupe(bool, other_comptime_params);
762 return Tag.function.create(allocator, .{764 return Tag.function.create(allocator, .{
763 .return_type = try payload.return_type.copy(allocator),765 .return_type = try payload.return_type.copy(allocator),
764 .param_types = param_types,766 .param_types = param_types,
765 .cc = payload.cc,767 .cc = payload.cc,
766 .is_var_args = payload.is_var_args,768 .is_var_args = payload.is_var_args,
767 .is_generic = payload.is_generic,769 .is_generic = payload.is_generic,
770 .comptime_params = comptime_params.ptr,
768 });771 });
769 },772 },
770 .pointer => {773 .pointer => {
...@@ -2408,14 +2411,41 @@ pub const Type = extern union {...@@ -2408,14 +2411,41 @@ pub const Type = extern union {
2408 };2411 };
2409 }2412 }
24102413
2411 /// Asserts the type is a function.2414 pub fn fnInfo(ty: Type) Payload.Function.Data {
2412 pub fn fnIsGeneric(self: Type) bool {2415 return switch (ty.tag()) {
2413 return switch (self.tag()) {2416 .fn_noreturn_no_args => .{
2414 .fn_noreturn_no_args => false,2417 .param_types = &.{},
2415 .fn_void_no_args => false,2418 .comptime_params = undefined,
2416 .fn_naked_noreturn_no_args => false,2419 .return_type = initTag(.noreturn),
2417 .fn_ccc_void_no_args => false,2420 .cc = .Unspecified,
2418 .function => self.castTag(.function).?.data.is_generic,2421 .is_var_args = false,
2422 .is_generic = false,
2423 },
2424 .fn_void_no_args => .{
2425 .param_types = &.{},
2426 .comptime_params = undefined,
2427 .return_type = initTag(.void),
2428 .cc = .Unspecified,
2429 .is_var_args = false,
2430 .is_generic = false,
2431 },
2432 .fn_naked_noreturn_no_args => .{
2433 .param_types = &.{},
2434 .comptime_params = undefined,
2435 .return_type = initTag(.noreturn),
2436 .cc = .Naked,
2437 .is_var_args = false,
2438 .is_generic = false,
2439 },
2440 .fn_ccc_void_no_args => .{
2441 .param_types = &.{},
2442 .comptime_params = undefined,
2443 .return_type = initTag(.void),
2444 .cc = .C,
2445 .is_var_args = false,
2446 .is_generic = false,
2447 },
2448 .function => ty.castTag(.function).?.data,
24192449
2420 else => unreachable,2450 else => unreachable,
2421 };2451 };
...@@ -3223,13 +3253,23 @@ pub const Type = extern union {...@@ -3223,13 +3253,23 @@ pub const Type = extern union {
3223 pub const base_tag = Tag.function;3253 pub const base_tag = Tag.function;
32243254
3225 base: Payload = Payload{ .tag = base_tag },3255 base: Payload = Payload{ .tag = base_tag },
3226 data: struct {3256 data: Data,
3257
3258 // TODO look into optimizing this memory to take fewer bytes
3259 const Data = struct {
3227 param_types: []Type,3260 param_types: []Type,
3261 comptime_params: [*]bool,
3228 return_type: Type,3262 return_type: Type,
3229 cc: std.builtin.CallingConvention,3263 cc: std.builtin.CallingConvention,
3230 is_var_args: bool,3264 is_var_args: bool,
3231 is_generic: bool,3265 is_generic: bool,
3232 },3266
3267 fn paramIsComptime(self: @This(), i: usize) bool {
3268 if (!self.is_generic) return false;
3269 assert(i < self.param_types.len);
3270 return self.comptime_params[i];
3271 }
3272 };
3233 };3273 };
32343274
3235 pub const ErrorSet = struct {3275 pub const ErrorSet = struct {