authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-05 23:32:42-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-08-05 23:32:42-07:00
logea7bdeb67d474526732b117992971603e4065f98
tree5dcd7d8c1cdd311cb40505d986c8fbceab52dfc9
parent9fd3aeb8088cd9a3b0744d5f508ca256a2bbf19f
parent7e9b23e6dce4d87615acd635f3731731a8601d39
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9517 from ziglang/generic-functions

stage2 generic functions

18 files changed, 1823 insertions(+), 926 deletions(-)

lib/std/hash_map.zig+1-1
...@@ -563,7 +563,7 @@ pub fn HashMap(...@@ -563,7 +563,7 @@ pub fn HashMap(
563 return self.unmanaged.getPtrContext(key, self.ctx);563 return self.unmanaged.getPtrContext(key, self.ctx);
564 }564 }
565 pub fn getPtrAdapted(self: Self, key: anytype, ctx: anytype) ?*V {565 pub fn getPtrAdapted(self: Self, key: anytype, ctx: anytype) ?*V {
566 return self.unmanaged.getPtrAdapted(key, self.ctx);566 return self.unmanaged.getPtrAdapted(key, ctx);
567 }567 }
568568
569 /// Finds the key and value associated with a key in the map569 /// Finds the key and value associated with a key in the map
lib/std/zig/ast.zig+3
...@@ -2198,6 +2198,9 @@ pub const full = struct {...@@ -2198,6 +2198,9 @@ pub const full = struct {
2198 .type_expr = param_type,2198 .type_expr = param_type,
2199 };2199 };
2200 }2200 }
2201 if (token_tags[it.tok_i] == .comma) {
2202 it.tok_i += 1;
2203 }
2201 if (token_tags[it.tok_i] == .r_paren) {2204 if (token_tags[it.tok_i] == .r_paren) {
2202 return null;2205 return null;
2203 }2206 }
src/AstGen.zig+262-288
...@@ -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
...@@ -195,6 +195,9 @@ pub const ResultLoc = union(enum) {...@@ -195,6 +195,9 @@ pub const ResultLoc = union(enum) {
195 none_or_ref,195 none_or_ref,
196 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.196 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
197 ty: Zir.Inst.Ref,197 ty: Zir.Inst.Ref,
198 /// Same as `ty` but it is guaranteed that Sema will additionall perform the coercion,
199 /// so no `as` instruction needs to be emitted.
200 coerced_ty: Zir.Inst.Ref,
198 /// The expression must store its result into this typed pointer. The result instruction201 /// The expression must store its result into this typed pointer. The result instruction
199 /// from the expression must be ignored.202 /// from the expression must be ignored.
200 ptr: Zir.Inst.Ref,203 ptr: Zir.Inst.Ref,
...@@ -225,7 +228,7 @@ pub const ResultLoc = union(enum) {...@@ -225,7 +228,7 @@ pub const ResultLoc = union(enum) {
225 fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy {228 fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy {
226 switch (rl) {229 switch (rl) {
227 // In this branch there will not be any store_to_block_ptr instructions.230 // In this branch there will not be any store_to_block_ptr instructions.
228 .discard, .none, .none_or_ref, .ty, .ref => return .{231 .discard, .none, .none_or_ref, .ty, .coerced_ty, .ref => return .{
229 .tag = .break_operand,232 .tag = .break_operand,
230 .elide_store_to_block_ptr_instructions = false,233 .elide_store_to_block_ptr_instructions = false,
231 },234 },
...@@ -259,13 +262,15 @@ pub const ResultLoc = union(enum) {...@@ -259,13 +262,15 @@ pub const ResultLoc = union(enum) {
259262
260pub const align_rl: ResultLoc = .{ .ty = .u16_type };263pub const align_rl: ResultLoc = .{ .ty = .u16_type };
261pub const bool_rl: ResultLoc = .{ .ty = .bool_type };264pub const bool_rl: ResultLoc = .{ .ty = .bool_type };
265pub const type_rl: ResultLoc = .{ .ty = .type_type };
266pub const coerced_type_rl: ResultLoc = .{ .coerced_ty = .type_type };
262267
263fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref {268fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref {
264 const prev_force_comptime = gz.force_comptime;269 const prev_force_comptime = gz.force_comptime;
265 gz.force_comptime = true;270 gz.force_comptime = true;
266 defer gz.force_comptime = prev_force_comptime;271 defer gz.force_comptime = prev_force_comptime;
267272
268 return expr(gz, scope, .{ .ty = .type_type }, type_node);273 return expr(gz, scope, coerced_type_rl, type_node);
269}274}
270275
271/// Same as `expr` but fails with a compile error if the result type is `noreturn`.276/// Same as `expr` but fails with a compile error if the result type is `noreturn`.
...@@ -1046,71 +1051,55 @@ fn fnProtoExpr(...@@ -1046,71 +1051,55 @@ fn fnProtoExpr(
1046 };1051 };
1047 assert(!is_extern);1052 assert(!is_extern);
10481053
1049 // The AST params array does not contain anytype and ... parameters.1054 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;1055 var param_type_i: usize = 0;
1076 var it = fn_proto.iterate(tree.*);1056 var it = fn_proto.iterate(tree.*);
1077 while (it.next()) |param| : (param_type_i += 1) {1057 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|1058 const is_comptime = if (param.comptime_noalias) |token|
1083 token_tags[token] == .keyword_comptime1059 token_tags[token] == .keyword_comptime
1084 else1060 else
1085 false;1061 false;
1086 cur_bit_bag = (cur_bit_bag >> bits_per_param) |
1087 (@as(u32, @boolToInt(is_comptime)) << 31);
10881062
1089 if (param.anytype_ellipsis3) |token| {1063 const is_anytype = if (param.anytype_ellipsis3) |token| blk: {
1090 switch (token_tags[token]) {1064 switch (token_tags[token]) {
1091 .keyword_anytype => {1065 .keyword_anytype => break :blk true,
1092 param_types[param_type_i] = .none;1066 .ellipsis3 => break :is_var_args true,
1093 continue;
1094 },
1095 .ellipsis3 => {
1096 is_var_args = true;
1097 break;
1098 },
1099 else => unreachable,1067 else => unreachable,
1100 }1068 }
1101 }1069 } else false;
1102 const param_type_node = param.type_expr;1070
1103 assert(param_type_node != 0);1071 const param_name: u32 = if (param.name_token) |name_token| blk: {
1104 param_types[param_type_i] =1072 if (mem.eql(u8, "_", tree.tokenSlice(name_token)))
1105 try expr(gz, scope, .{ .ty = .type_type }, param_type_node);1073 break :blk 0;
1106 }
1107 assert(param_type_i == param_count);
11081074
1109 const empty_slot_count = params_per_u32 - (param_type_i % params_per_u32);1075 break :blk try astgen.identAsString(name_token);
1110 if (empty_slot_count < params_per_u32) {1076 } else 0;
1111 cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_param);1077
1078 if (is_anytype) {
1079 const name_token = param.name_token orelse param.anytype_ellipsis3.?;
1080
1081 const tag: Zir.Inst.Tag = if (is_comptime)
1082 .param_anytype_comptime
1083 else
1084 .param_anytype;
1085 _ = try gz.addStrTok(tag, param_name, name_token);
1086 } else {
1087 const param_type_node = param.type_expr;
1088 assert(param_type_node != 0);
1089 var param_gz = gz.makeSubBlock(scope);
1090 defer param_gz.instructions.deinit(gpa);
1091 const param_type = try expr(&param_gz, scope, coerced_type_rl, param_type_node);
1092 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);
1093 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);
1094 const main_tokens = tree.nodes.items(.main_token);
1095 const name_token = param.name_token orelse main_tokens[param_type_node];
1096 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
1097 const param_inst = try gz.addParam(tag, name_token, param_name, param_gz.instructions.items);
1098 assert(param_inst_expected == param_inst);
1099 }
1112 }1100 }
1113 }1101 break :is_var_args false;
1102 };
11141103
1115 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {1104 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);1105 break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr);
...@@ -1124,15 +1113,13 @@ fn fnProtoExpr(...@@ -1124,15 +1113,13 @@ fn fnProtoExpr(
1124 if (is_inferred_error) {1113 if (is_inferred_error) {
1125 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});1114 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
1126 }1115 }
1127 const return_type_inst = try AstGen.expr(1116 var ret_gz = gz.makeSubBlock(scope);
1128 gz,1117 defer ret_gz.instructions.deinit(gpa);
1129 scope,1118 const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);
1130 .{ .ty = .type_type },1119 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
1131 fn_proto.ast.return_type,
1132 );
11331120
1134 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)1121 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
1135 try AstGen.expr(1122 try expr(
1136 gz,1123 gz,
1137 scope,1124 scope,
1138 .{ .ty = .calling_convention_type },1125 .{ .ty = .calling_convention_type },
...@@ -1143,8 +1130,9 @@ fn fnProtoExpr(...@@ -1143,8 +1130,9 @@ fn fnProtoExpr(
11431130
1144 const result = try gz.addFunc(.{1131 const result = try gz.addFunc(.{
1145 .src_node = fn_proto.ast.proto_node,1132 .src_node = fn_proto.ast.proto_node,
1146 .ret_ty = return_type_inst,1133 .param_block = 0,
1147 .param_types = param_types,1134 .ret_ty = ret_gz.instructions.items,
1135 .ret_br = ret_br,
1148 .body = &[0]Zir.Inst.Index{},1136 .body = &[0]Zir.Inst.Index{},
1149 .cc = cc,1137 .cc = cc,
1150 .align_inst = align_inst,1138 .align_inst = align_inst,
...@@ -1153,8 +1141,6 @@ fn fnProtoExpr(...@@ -1153,8 +1141,6 @@ fn fnProtoExpr(
1153 .is_inferred_error = false,1141 .is_inferred_error = false,
1154 .is_test = false,1142 .is_test = false,
1155 .is_extern = false,1143 .is_extern = false,
1156 .cur_bit_bag = cur_bit_bag,
1157 .bit_bag = bit_bag.items,
1158 });1144 });
1159 return rvalue(gz, rl, result, fn_proto.ast.proto_node);1145 return rvalue(gz, rl, result, fn_proto.ast.proto_node);
1160}1146}
...@@ -1239,7 +1225,7 @@ fn arrayInitExpr(...@@ -1239,7 +1225,7 @@ fn arrayInitExpr(
1239 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);1225 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
1240 }1226 }
1241 },1227 },
1242 .ty => |ty_inst| {1228 .ty, .coerced_ty => |ty_inst| {
1243 if (types.array != .none) {1229 if (types.array != .none) {
1244 const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);1230 const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);
1245 return rvalue(gz, rl, result, node);1231 return rvalue(gz, rl, result, node);
...@@ -1408,7 +1394,7 @@ fn structInitExpr(...@@ -1408,7 +1394,7 @@ fn structInitExpr(
1408 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon);1394 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon);
1409 }1395 }
1410 },1396 },
1411 .ty => |ty_inst| {1397 .ty, .coerced_ty => |ty_inst| {
1412 if (struct_init.ast.type_expr == 0) {1398 if (struct_init.ast.type_expr == 0) {
1413 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);1399 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
1414 }1400 }
...@@ -1447,8 +1433,8 @@ fn structInitExprRlNone(...@@ -1447,8 +1433,8 @@ fn structInitExprRlNone(
1447 const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInitAnon{1433 const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInitAnon{
1448 .fields_len = @intCast(u32, fields_list.len),1434 .fields_len = @intCast(u32, fields_list.len),
1449 });1435 });
1450 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +1436 try astgen.extra.ensureUnusedCapacity(gpa, fields_list.len *
1451 fields_list.len * @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len);1437 @typeInfo(Zir.Inst.StructInitAnon.Item).Struct.fields.len);
1452 for (fields_list) |field| {1438 for (fields_list) |field| {
1453 _ = gz.astgen.addExtraAssumeCapacity(field);1439 _ = gz.astgen.addExtraAssumeCapacity(field);
1454 }1440 }
...@@ -1520,8 +1506,8 @@ fn structInitExprRlTy(...@@ -1520,8 +1506,8 @@ fn structInitExprRlTy(
1520 const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInit{1506 const init_inst = try gz.addPlNode(tag, node, Zir.Inst.StructInit{
1521 .fields_len = @intCast(u32, fields_list.len),1507 .fields_len = @intCast(u32, fields_list.len),
1522 });1508 });
1523 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +1509 try astgen.extra.ensureUnusedCapacity(gpa, fields_list.len *
1524 fields_list.len * @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len);1510 @typeInfo(Zir.Inst.StructInit.Item).Struct.fields.len);
1525 for (fields_list) |field| {1511 for (fields_list) |field| {
1526 _ = gz.astgen.addExtraAssumeCapacity(field);1512 _ = gz.astgen.addExtraAssumeCapacity(field);
1527 }1513 }
...@@ -1918,7 +1904,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) Inner...@@ -1918,7 +1904,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`.1904 // ZIR instructions that might be a type other than `noreturn` or `void`.
1919 .add,1905 .add,
1920 .addwrap,1906 .addwrap,
1921 .arg,1907 .param,
1908 .param_comptime,
1909 .param_anytype,
1910 .param_anytype_comptime,
1922 .alloc,1911 .alloc,
1923 .alloc_mut,1912 .alloc_mut,
1924 .alloc_comptime,1913 .alloc_comptime,
...@@ -2488,7 +2477,7 @@ fn varDecl(...@@ -2488,7 +2477,7 @@ fn varDecl(
2488 // Move the init_scope instructions into the parent scope, swapping2477 // Move the init_scope instructions into the parent scope, swapping
2489 // store_to_block_ptr for store_to_inferred_ptr.2478 // store_to_block_ptr for store_to_inferred_ptr.
2490 const expected_len = parent_zir.items.len + init_scope.instructions.items.len;2479 const expected_len = parent_zir.items.len + init_scope.instructions.items.len;
2491 try parent_zir.ensureCapacity(gpa, expected_len);2480 try parent_zir.ensureTotalCapacity(gpa, expected_len);
2492 for (init_scope.instructions.items) |src_inst| {2481 for (init_scope.instructions.items) |src_inst| {
2493 if (zir_tags[src_inst] == .store_to_block_ptr) {2482 if (zir_tags[src_inst] == .store_to_block_ptr) {
2494 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) {2483 if (zir_datas[src_inst].bin.lhs == init_scope.rl_ptr) {
...@@ -2634,7 +2623,7 @@ fn assignOp(...@@ -2634,7 +2623,7 @@ fn assignOp(
2634 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);2623 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
2635 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);2624 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);
2636 const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node);2625 const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node);
2637 const rhs = try expr(gz, scope, .{ .ty = lhs_type }, node_datas[infix_node].rhs);2626 const rhs = try expr(gz, scope, .{ .coerced_ty = lhs_type }, node_datas[infix_node].rhs);
26382627
2639 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{2628 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{
2640 .lhs = lhs,2629 .lhs = lhs,
...@@ -2750,10 +2739,10 @@ fn ptrType(...@@ -2750,10 +2739,10 @@ fn ptrType(
2750 }2739 }
27512740
2752 const gpa = gz.astgen.gpa;2741 const gpa = gz.astgen.gpa;
2753 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);2742 try gz.instructions.ensureUnusedCapacity(gpa, 1);
2754 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);2743 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
2755 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +2744 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.PtrType).Struct.fields.len +
2756 @typeInfo(Zir.Inst.PtrType).Struct.fields.len + trailing_count);2745 trailing_count);
27572746
2758 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.PtrType{ .elem_type = elem_type });2747 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.PtrType{ .elem_type = elem_type });
2759 if (sentinel_ref != .none) {2748 if (sentinel_ref != .none) {
...@@ -2899,6 +2888,16 @@ fn fnDecl(...@@ -2899,6 +2888,16 @@ fn fnDecl(
2899 };2888 };
2900 defer decl_gz.instructions.deinit(gpa);2889 defer decl_gz.instructions.deinit(gpa);
29012890
2891 var fn_gz: GenZir = .{
2892 .force_comptime = false,
2893 .in_defer = false,
2894 .decl_node_index = fn_proto.ast.proto_node,
2895 .decl_line = decl_gz.decl_line,
2896 .parent = &decl_gz.base,
2897 .astgen = astgen,
2898 };
2899 defer fn_gz.instructions.deinit(gpa);
2900
2902 // TODO: support noinline2901 // TODO: support noinline
2903 const is_pub = fn_proto.visib_token != null;2902 const is_pub = fn_proto.visib_token != null;
2904 const is_export = blk: {2903 const is_export = blk: {
...@@ -2913,80 +2912,82 @@ fn fnDecl(...@@ -2913,80 +2912,82 @@ fn fnDecl(
2913 const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;2912 const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;
2914 break :blk token_tags[maybe_inline_token] == .keyword_inline;2913 break :blk token_tags[maybe_inline_token] == .keyword_inline;
2915 };2914 };
2916 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {2915 try wip_decls.next(gpa, is_pub, is_export, fn_proto.ast.align_expr != 0, fn_proto.ast.section_expr != 0);
2917 break :inst try expr(&decl_gz, &decl_gz.base, align_rl, fn_proto.ast.align_expr);
2918 };
2919 const section_inst: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: {
2920 break :inst try comptimeExpr(&decl_gz, &decl_gz.base, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr);
2921 };
2922
2923 try wip_decls.next(gpa, is_pub, is_export, align_inst != .none, section_inst != .none);
2924
2925 // The AST params array does not contain anytype and ... parameters.
2926 // We must iterate to count how many param types to allocate.
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);
29422916
2943 const bits_per_param = 1;2917 var params_scope = &fn_gz.base;
2944 const params_per_u32 = 32 / bits_per_param;2918 const is_var_args = is_var_args: {
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;
29842951
2985 const empty_slot_count = params_per_u32 - (param_type_i % params_per_u32);2952 const param_inst = if (is_anytype) param: {
2986 if (empty_slot_count < params_per_u32) {2953 const name_token = param.name_token orelse param.anytype_ellipsis3.?;
2987 cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_param);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 var param_gz = decl_gz.makeSubBlock(scope);
2963 defer param_gz.instructions.deinit(gpa);
2964 const param_type = try expr(&param_gz, params_scope, coerced_type_rl, param_type_node);
2965 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);
2966 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);
2967
2968 const main_tokens = tree.nodes.items(.main_token);
2969 const name_token = param.name_token orelse main_tokens[param_type_node];
2970 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
2971 const param_inst = try decl_gz.addParam(tag, name_token, param_name, param_gz.instructions.items);
2972 assert(param_inst_expected == param_inst);
2973 break :param indexToRef(param_inst);
2974 };
2975
2976 if (param_name == 0) continue;
2977
2978 const sub_scope = try astgen.arena.create(Scope.LocalVal);
2979 sub_scope.* = .{
2980 .parent = params_scope,
2981 .gen_zir = &decl_gz,
2982 .name = param_name,
2983 .inst = param_inst,
2984 .token_src = param.name_token.?,
2985 .id_cat = .@"function parameter",
2986 };
2987 params_scope = &sub_scope.base;
2988 }2988 }
2989 }2989 break :is_var_args false;
2990 };
29902991
2991 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: {2992 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: {
2992 const lib_name_str = try astgen.strLitAsString(lib_name_token);2993 const lib_name_str = try astgen.strLitAsString(lib_name_token);
...@@ -2996,12 +2997,17 @@ fn fnDecl(...@@ -2996,12 +2997,17 @@ fn fnDecl(
2996 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;2997 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
2997 const is_inferred_error = token_tags[maybe_bang] == .bang;2998 const is_inferred_error = token_tags[maybe_bang] == .bang;
29982999
2999 const return_type_inst = try AstGen.expr(3000 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
3000 &decl_gz,3001 break :inst try expr(&decl_gz, params_scope, align_rl, fn_proto.ast.align_expr);
3001 &decl_gz.base,3002 };
3002 .{ .ty = .type_type },3003 const section_inst: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: {
3003 fn_proto.ast.return_type,3004 break :inst try comptimeExpr(&decl_gz, params_scope, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr);
3004 );3005 };
3006
3007 var ret_gz = decl_gz.makeSubBlock(params_scope);
3008 defer ret_gz.instructions.deinit(gpa);
3009 const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
3010 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
30053011
3006 const cc: Zir.Inst.Ref = blk: {3012 const cc: Zir.Inst.Ref = blk: {
3007 if (fn_proto.ast.callconv_expr != 0) {3013 if (fn_proto.ast.callconv_expr != 0) {
...@@ -3012,9 +3018,9 @@ fn fnDecl(...@@ -3012,9 +3018,9 @@ fn fnDecl(
3012 .{},3018 .{},
3013 );3019 );
3014 }3020 }
3015 break :blk try AstGen.expr(3021 break :blk try expr(
3016 &decl_gz,3022 &decl_gz,
3017 &decl_gz.base,3023 params_scope,
3018 .{ .ty = .calling_convention_type },3024 .{ .ty = .calling_convention_type },
3019 fn_proto.ast.callconv_expr,3025 fn_proto.ast.callconv_expr,
3020 );3026 );
...@@ -3037,8 +3043,9 @@ fn fnDecl(...@@ -3037,8 +3043,9 @@ fn fnDecl(
3037 }3043 }
3038 break :func try decl_gz.addFunc(.{3044 break :func try decl_gz.addFunc(.{
3039 .src_node = decl_node,3045 .src_node = decl_node,
3040 .ret_ty = return_type_inst,3046 .ret_ty = ret_gz.instructions.items,
3041 .param_types = param_types,3047 .ret_br = ret_br,
3048 .param_block = block_inst,
3042 .body = &[0]Zir.Inst.Index{},3049 .body = &[0]Zir.Inst.Index{},
3043 .cc = cc,3050 .cc = cc,
3044 .align_inst = .none, // passed in the per-decl data3051 .align_inst = .none, // passed in the per-decl data
...@@ -3047,75 +3054,18 @@ fn fnDecl(...@@ -3047,75 +3054,18 @@ fn fnDecl(
3047 .is_inferred_error = false,3054 .is_inferred_error = false,
3048 .is_test = false,3055 .is_test = false,
3049 .is_extern = true,3056 .is_extern = true,
3050 .cur_bit_bag = cur_bit_bag,
3051 .bit_bag = bit_bag.items,
3052 });3057 });
3053 } else func: {3058 } else func: {
3054 if (is_var_args) {3059 if (is_var_args) {
3055 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{});3060 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function is variadic", .{});
3056 }3061 }
30573062
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;3063 const prev_fn_block = astgen.fn_block;
3069 astgen.fn_block = &fn_gz;3064 astgen.fn_block = &fn_gz;
3070 defer astgen.fn_block = prev_fn_block;3065 defer astgen.fn_block = prev_fn_block;
30713066
3072 // Iterate over the parameters. We put the param names as the first N3067 _ = try expr(&fn_gz, params_scope, .none, body_node);
3073 // items inside `extra` so that debug info later can refer to the parameter names3068 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 }
31193069
3120 const need_implicit_ret = blk: {3070 const need_implicit_ret = blk: {
3121 if (fn_gz.instructions.items.len == 0)3071 if (fn_gz.instructions.items.len == 0)
...@@ -3132,8 +3082,9 @@ fn fnDecl(...@@ -3132,8 +3082,9 @@ fn fnDecl(
31323082
3133 break :func try decl_gz.addFunc(.{3083 break :func try decl_gz.addFunc(.{
3134 .src_node = decl_node,3084 .src_node = decl_node,
3135 .ret_ty = return_type_inst,3085 .param_block = block_inst,
3136 .param_types = param_types,3086 .ret_ty = ret_gz.instructions.items,
3087 .ret_br = ret_br,
3137 .body = fn_gz.instructions.items,3088 .body = fn_gz.instructions.items,
3138 .cc = cc,3089 .cc = cc,
3139 .align_inst = .none, // passed in the per-decl data3090 .align_inst = .none, // passed in the per-decl data
...@@ -3142,8 +3093,6 @@ fn fnDecl(...@@ -3142,8 +3093,6 @@ fn fnDecl(
3142 .is_inferred_error = is_inferred_error,3093 .is_inferred_error = is_inferred_error,
3143 .is_test = false,3094 .is_test = false,
3144 .is_extern = false,3095 .is_extern = false,
3145 .cur_bit_bag = cur_bit_bag,
3146 .bit_bag = bit_bag.items,
3147 });3096 });
3148 };3097 };
31493098
...@@ -3479,8 +3428,9 @@ fn testDecl(...@@ -3479,8 +3428,9 @@ fn testDecl(
34793428
3480 const func_inst = try decl_block.addFunc(.{3429 const func_inst = try decl_block.addFunc(.{
3481 .src_node = node,3430 .src_node = node,
3482 .ret_ty = .void_type,3431 .param_block = block_inst,
3483 .param_types = &[0]Zir.Inst.Ref{},3432 .ret_ty = &.{},
3433 .ret_br = 0,
3484 .body = fn_block.instructions.items,3434 .body = fn_block.instructions.items,
3485 .cc = .none,3435 .cc = .none,
3486 .align_inst = .none,3436 .align_inst = .none,
...@@ -3489,8 +3439,6 @@ fn testDecl(...@@ -3489,8 +3439,6 @@ fn testDecl(
3489 .is_inferred_error = true,3439 .is_inferred_error = true,
3490 .is_test = true,3440 .is_test = true,
3491 .is_extern = false,3441 .is_extern = false,
3492 .cur_bit_bag = 0,
3493 .bit_bag = &.{},
3494 });3442 });
34953443
3496 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst);3444 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst);
...@@ -4238,7 +4186,7 @@ fn containerDecl(...@@ -4238,7 +4186,7 @@ fn containerDecl(
4238 var fields_data = ArrayListUnmanaged(u32){};4186 var fields_data = ArrayListUnmanaged(u32){};
4239 defer fields_data.deinit(gpa);4187 defer fields_data.deinit(gpa);
42404188
4241 try fields_data.ensureCapacity(gpa, counts.total_fields + counts.values);4189 try fields_data.ensureTotalCapacity(gpa, counts.total_fields + counts.values);
42424190
4243 // We only need this if there are greater than 32 fields.4191 // We only need this if there are greater than 32 fields.
4244 var bit_bag = ArrayListUnmanaged(u32){};4192 var bit_bag = ArrayListUnmanaged(u32){};
...@@ -5184,8 +5132,7 @@ fn setCondBrPayload(...@@ -5184,8 +5132,7 @@ fn setCondBrPayload(
5184) !void {5132) !void {
5185 const astgen = then_scope.astgen;5133 const astgen = then_scope.astgen;
51865134
5187 try astgen.extra.ensureCapacity(astgen.gpa, astgen.extra.items.len +5135 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);5136 then_scope.instructions.items.len + else_scope.instructions.items.len);
51905137
5191 const zir_datas = astgen.instructions.items(.data);5138 const zir_datas = astgen.instructions.items(.data);
...@@ -5476,7 +5423,7 @@ fn forExpr(...@@ -5476,7 +5423,7 @@ fn forExpr(
5476 const tree = astgen.tree;5423 const tree = astgen.tree;
5477 const token_tags = tree.tokens.items(.tag);5424 const token_tags = tree.tokens.items(.tag);
54785425
5479 const array_ptr = try expr(parent_gz, scope, .ref, for_full.ast.cond_expr);5426 const array_ptr = try expr(parent_gz, scope, .none_or_ref, for_full.ast.cond_expr);
5480 const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr);5427 const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr);
54815428
5482 const index_ptr = blk: {5429 const index_ptr = blk: {
...@@ -5839,10 +5786,9 @@ fn switchExpr(...@@ -5839,10 +5786,9 @@ fn switchExpr(
5839 _ = try case_scope.addBreak(.@"break", switch_block, case_result);5786 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
5840 }5787 }
5841 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.5788 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.
5842 try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len +5789 try scalar_cases_payload.ensureUnusedCapacity(gpa, case_scope.instructions.items.len +
5843 3 + // operand, scalar_cases_len, else body len5790 3 + // operand, scalar_cases_len, else body len
5844 @boolToInt(multi_cases_len != 0) +5791 @boolToInt(multi_cases_len != 0));
5845 case_scope.instructions.items.len);
5846 scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand));5792 scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand));
5847 scalar_cases_payload.appendAssumeCapacity(scalar_cases_len);5793 scalar_cases_payload.appendAssumeCapacity(scalar_cases_len);
5848 if (multi_cases_len != 0) {5794 if (multi_cases_len != 0) {
...@@ -5852,9 +5798,11 @@ fn switchExpr(...@@ -5852,9 +5798,11 @@ fn switchExpr(
5852 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);5798 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);
5853 } else {5799 } else {
5854 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.5800 // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`.
5855 try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len +5801 try scalar_cases_payload.ensureUnusedCapacity(
5856 2 + // operand, scalar_cases_len5802 gpa,
5857 @boolToInt(multi_cases_len != 0));5803 @as(usize, 2) + // operand, scalar_cases_len
5804 @boolToInt(multi_cases_len != 0),
5805 );
5858 scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand));5806 scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand));
5859 scalar_cases_payload.appendAssumeCapacity(scalar_cases_len);5807 scalar_cases_payload.appendAssumeCapacity(scalar_cases_len);
5860 if (multi_cases_len != 0) {5808 if (multi_cases_len != 0) {
...@@ -5975,8 +5923,8 @@ fn switchExpr(...@@ -5975,8 +5923,8 @@ fn switchExpr(
5975 block_scope.break_count += 1;5923 block_scope.break_count += 1;
5976 _ = try case_scope.addBreak(.@"break", switch_block, case_result);5924 _ = try case_scope.addBreak(.@"break", switch_block, case_result);
5977 }5925 }
5978 try scalar_cases_payload.ensureCapacity(gpa, scalar_cases_payload.items.len +5926 try scalar_cases_payload.ensureUnusedCapacity(gpa, 2 +
5979 2 + case_scope.instructions.items.len);5927 case_scope.instructions.items.len);
5980 scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst));5928 scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst));
5981 scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));5929 scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len));
5982 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);5930 scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items);
...@@ -6012,8 +5960,8 @@ fn switchExpr(...@@ -6012,8 +5960,8 @@ fn switchExpr(
6012 const payload_index = astgen.extra.items.len;5960 const payload_index = astgen.extra.items.len;
6013 const zir_datas = astgen.instructions.items(.data);5961 const zir_datas = astgen.instructions.items(.data);
6014 zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index);5962 zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index);
6015 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +5963 try astgen.extra.ensureUnusedCapacity(gpa, scalar_cases_payload.items.len +
6016 scalar_cases_payload.items.len + multi_cases_payload.items.len);5964 multi_cases_payload.items.len);
6017 const strat = rl.strategy(&block_scope);5965 const strat = rl.strategy(&block_scope);
6018 switch (strat.tag) {5966 switch (strat.tag) {
6019 .break_operand => {5967 .break_operand => {
...@@ -6821,7 +6769,7 @@ fn as(...@@ -6821,7 +6769,7 @@ fn as(
6821) InnerError!Zir.Inst.Ref {6769) InnerError!Zir.Inst.Ref {
6822 const dest_type = try typeExpr(gz, scope, lhs);6770 const dest_type = try typeExpr(gz, scope, lhs);
6823 switch (rl) {6771 switch (rl) {
6824 .none, .none_or_ref, .discard, .ref, .ty => {6772 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty => {
6825 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);6773 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);
6826 return rvalue(gz, rl, result, node);6774 return rvalue(gz, rl, result, node);
6827 },6775 },
...@@ -6844,7 +6792,7 @@ fn unionInit(...@@ -6844,7 +6792,7 @@ fn unionInit(
6844 const union_type = try typeExpr(gz, scope, params[0]);6792 const union_type = try typeExpr(gz, scope, params[0]);
6845 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);6793 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
6846 switch (rl) {6794 switch (rl) {
6847 .none, .none_or_ref, .discard, .ref, .ty, .inferred_ptr => {6795 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => {
6848 _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{6796 _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{
6849 .container_type = union_type,6797 .container_type = union_type,
6850 .field_name = field_name,6798 .field_name = field_name,
...@@ -6930,7 +6878,7 @@ fn bitCast(...@@ -6930,7 +6878,7 @@ fn bitCast(
6930 const astgen = gz.astgen;6878 const astgen = gz.astgen;
6931 const dest_type = try typeExpr(gz, scope, lhs);6879 const dest_type = try typeExpr(gz, scope, lhs);
6932 switch (rl) {6880 switch (rl) {
6933 .none, .none_or_ref, .discard, .ty => {6881 .none, .none_or_ref, .discard, .ty, .coerced_ty => {
6934 const operand = try expr(gz, scope, .none, rhs);6882 const operand = try expr(gz, scope, .none, rhs);
6935 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{6883 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{
6936 .lhs = dest_type,6884 .lhs = dest_type,
...@@ -7740,7 +7688,7 @@ fn callExpr(...@@ -7740,7 +7688,7 @@ fn callExpr(
7740 .param_index = @intCast(u32, i),7688 .param_index = @intCast(u32, i),
7741 } },7689 } },
7742 });7690 });
7743 args[i] = try expr(gz, scope, .{ .ty = param_type }, param_node);7691 args[i] = try expr(gz, scope, .{ .coerced_ty = param_type }, param_node);
7744 }7692 }
77457693
7746 const modifier: std.builtin.CallOptions.Modifier = blk: {7694 const modifier: std.builtin.CallOptions.Modifier = blk: {
...@@ -8433,7 +8381,7 @@ fn rvalue(...@@ -8433,7 +8381,7 @@ fn rvalue(
8433 src_node: ast.Node.Index,8381 src_node: ast.Node.Index,
8434) InnerError!Zir.Inst.Ref {8382) InnerError!Zir.Inst.Ref {
8435 switch (rl) {8383 switch (rl) {
8436 .none, .none_or_ref => return result,8384 .none, .none_or_ref, .coerced_ty => return result,
8437 .discard => {8385 .discard => {
8438 // Emit a compile error for discarding error values.8386 // Emit a compile error for discarding error values.
8439 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);8387 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
...@@ -8659,7 +8607,7 @@ fn failNodeNotes(...@@ -8659,7 +8607,7 @@ fn failNodeNotes(
8659 }8607 }
8660 const notes_index: u32 = if (notes.len != 0) blk: {8608 const notes_index: u32 = if (notes.len != 0) blk: {
8661 const notes_start = astgen.extra.items.len;8609 const notes_start = astgen.extra.items.len;
8662 try astgen.extra.ensureCapacity(astgen.gpa, notes_start + 1 + notes.len);8610 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len);
8663 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));8611 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));
8664 astgen.extra.appendSliceAssumeCapacity(notes);8612 astgen.extra.appendSliceAssumeCapacity(notes);
8665 break :blk @intCast(u32, notes_start);8613 break :blk @intCast(u32, notes_start);
...@@ -8700,7 +8648,7 @@ fn failTokNotes(...@@ -8700,7 +8648,7 @@ fn failTokNotes(
8700 }8648 }
8701 const notes_index: u32 = if (notes.len != 0) blk: {8649 const notes_index: u32 = if (notes.len != 0) blk: {
8702 const notes_start = astgen.extra.items.len;8650 const notes_start = astgen.extra.items.len;
8703 try astgen.extra.ensureCapacity(astgen.gpa, notes_start + 1 + notes.len);8651 try astgen.extra.ensureTotalCapacity(astgen.gpa, notes_start + 1 + notes.len);
8704 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));8652 astgen.extra.appendAssumeCapacity(@intCast(u32, notes.len));
8705 astgen.extra.appendSliceAssumeCapacity(notes);8653 astgen.extra.appendSliceAssumeCapacity(notes);
8706 break :blk @intCast(u32, notes_start);8654 break :blk @intCast(u32, notes_start);
...@@ -8864,7 +8812,7 @@ fn strLitNodeAsString(astgen: *AstGen, node: ast.Node.Index) !IndexSlice {...@@ -8864,7 +8812,7 @@ fn strLitNodeAsString(astgen: *AstGen, node: ast.Node.Index) !IndexSlice {
8864 while (tok_i <= end) : (tok_i += 1) {8812 while (tok_i <= end) : (tok_i += 1) {
8865 const slice = tree.tokenSlice(tok_i);8813 const slice = tree.tokenSlice(tok_i);
8866 const line_bytes = slice[2 .. slice.len - 1];8814 const line_bytes = slice[2 .. slice.len - 1];
8867 try string_bytes.ensureCapacity(gpa, string_bytes.items.len + line_bytes.len + 1);8815 try string_bytes.ensureUnusedCapacity(gpa, line_bytes.len + 1);
8868 string_bytes.appendAssumeCapacity('\n');8816 string_bytes.appendAssumeCapacity('\n');
8869 string_bytes.appendSliceAssumeCapacity(line_bytes);8817 string_bytes.appendSliceAssumeCapacity(line_bytes);
8870 }8818 }
...@@ -9105,7 +9053,7 @@ const GenZir = struct {...@@ -9105,7 +9053,7 @@ const GenZir = struct {
9105 // we emit ZIR for the block break instructions to have the result values,9053 // we emit ZIR for the block break instructions to have the result values,
9106 // and then rvalue() on that to pass the value to the result location.9054 // and then rvalue() on that to pass the value to the result location.
9107 switch (parent_rl) {9055 switch (parent_rl) {
9108 .ty => |ty_inst| {9056 .ty, .coerced_ty => |ty_inst| {
9109 gz.rl_ty_inst = ty_inst;9057 gz.rl_ty_inst = ty_inst;
9110 gz.break_result_loc = parent_rl;9058 gz.break_result_loc = parent_rl;
9111 },9059 },
...@@ -9131,8 +9079,8 @@ const GenZir = struct {...@@ -9131,8 +9079,8 @@ const GenZir = struct {
91319079
9132 fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void {9080 fn setBoolBrBody(gz: GenZir, inst: Zir.Inst.Index) !void {
9133 const gpa = gz.astgen.gpa;9081 const gpa = gz.astgen.gpa;
9134 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +9082 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);9083 gz.instructions.items.len);
9136 const zir_datas = gz.astgen.instructions.items(.data);9084 const zir_datas = gz.astgen.instructions.items(.data);
9137 zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity(9085 zir_datas[inst].bool_br.payload_index = gz.astgen.addExtraAssumeCapacity(
9138 Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },9086 Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },
...@@ -9142,8 +9090,8 @@ const GenZir = struct {...@@ -9142,8 +9090,8 @@ const GenZir = struct {
91429090
9143 fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void {9091 fn setBlockBody(gz: GenZir, inst: Zir.Inst.Index) !void {
9144 const gpa = gz.astgen.gpa;9092 const gpa = gz.astgen.gpa;
9145 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +9093 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);9094 gz.instructions.items.len);
9147 const zir_datas = gz.astgen.instructions.items(.data);9095 const zir_datas = gz.astgen.instructions.items(.data);
9148 zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity(9096 zir_datas[inst].pl_node.payload_index = gz.astgen.addExtraAssumeCapacity(
9149 Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },9097 Zir.Inst.Block{ .body_len = @intCast(u32, gz.instructions.items.len) },
...@@ -9155,8 +9103,8 @@ const GenZir = struct {...@@ -9155,8 +9103,8 @@ const GenZir = struct {
9155 /// `store_to_block_ptr` instructions with lhs set to .none.9103 /// `store_to_block_ptr` instructions with lhs set to .none.
9156 fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void {9104 fn setBlockBodyEliding(gz: GenZir, inst: Zir.Inst.Index) !void {
9157 const gpa = gz.astgen.gpa;9105 const gpa = gz.astgen.gpa;
9158 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +9106 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);9107 gz.instructions.items.len);
9160 const zir_datas = gz.astgen.instructions.items(.data);9108 const zir_datas = gz.astgen.instructions.items(.data);
9161 const zir_tags = gz.astgen.instructions.items(.tag);9109 const zir_tags = gz.astgen.instructions.items(.tag);
9162 const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{9110 const block_pl_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Block{
...@@ -9177,9 +9125,10 @@ const GenZir = struct {...@@ -9177,9 +9125,10 @@ const GenZir = struct {
91779125
9178 fn addFunc(gz: *GenZir, args: struct {9126 fn addFunc(gz: *GenZir, args: struct {
9179 src_node: ast.Node.Index,9127 src_node: ast.Node.Index,
9180 param_types: []const Zir.Inst.Ref,
9181 body: []const Zir.Inst.Index,9128 body: []const Zir.Inst.Index,
9182 ret_ty: Zir.Inst.Ref,9129 param_block: Zir.Inst.Index,
9130 ret_ty: []const Zir.Inst.Index,
9131 ret_br: Zir.Inst.Index,
9183 cc: Zir.Inst.Ref,9132 cc: Zir.Inst.Ref,
9184 align_inst: Zir.Inst.Ref,9133 align_inst: Zir.Inst.Ref,
9185 lib_name: u32,9134 lib_name: u32,
...@@ -9187,11 +9136,8 @@ const GenZir = struct {...@@ -9187,11 +9136,8 @@ const GenZir = struct {
9187 is_inferred_error: bool,9136 is_inferred_error: bool,
9188 is_test: bool,9137 is_test: bool,
9189 is_extern: bool,9138 is_extern: bool,
9190 cur_bit_bag: u32,
9191 bit_bag: []const u32,
9192 }) !Zir.Inst.Ref {9139 }) !Zir.Inst.Ref {
9193 assert(args.src_node != 0);9140 assert(args.src_node != 0);
9194 assert(args.ret_ty != .none);
9195 const astgen = gz.astgen;9141 const astgen = gz.astgen;
9196 const gpa = astgen.gpa;9142 const gpa = astgen.gpa;
91979143
...@@ -9226,27 +9172,22 @@ const GenZir = struct {...@@ -9226,27 +9172,22 @@ const GenZir = struct {
9226 src_locs = &src_locs_buffer;9172 src_locs = &src_locs_buffer;
9227 }9173 }
92289174
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 or9175 if (args.cc != .none or args.lib_name != 0 or
9234 args.is_var_args or args.is_test or args.align_inst != .none or9176 args.is_var_args or args.is_test or args.align_inst != .none or
9235 args.is_extern or any_are_comptime)9177 args.is_extern)
9236 {9178 {
9237 try astgen.extra.ensureUnusedCapacity(9179 try astgen.extra.ensureUnusedCapacity(
9238 gpa,9180 gpa,
9239 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +9181 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +
9240 @boolToInt(any_are_comptime) + args.bit_bag.len +9182 args.ret_ty.len + args.body.len + src_locs.len +
9241 args.param_types.len + args.body.len + src_locs.len +
9242 @boolToInt(args.lib_name != 0) +9183 @boolToInt(args.lib_name != 0) +
9243 @boolToInt(args.align_inst != .none) +9184 @boolToInt(args.align_inst != .none) +
9244 @boolToInt(args.cc != .none),9185 @boolToInt(args.cc != .none),
9245 );9186 );
9246 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{9187 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{
9247 .src_node = gz.nodeIndexToRelative(args.src_node),9188 .src_node = gz.nodeIndexToRelative(args.src_node),
9248 .return_type = args.ret_ty,9189 .param_block = args.param_block,
9249 .param_types_len = @intCast(u32, args.param_types.len),9190 .ret_body_len = @intCast(u32, args.ret_ty.len),
9250 .body_len = @intCast(u32, args.body.len),9191 .body_len = @intCast(u32, args.body.len),
9251 });9192 });
9252 if (args.lib_name != 0) {9193 if (args.lib_name != 0) {
...@@ -9258,15 +9199,14 @@ const GenZir = struct {...@@ -9258,15 +9199,14 @@ const GenZir = struct {
9258 if (args.align_inst != .none) {9199 if (args.align_inst != .none) {
9259 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));9200 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
9260 }9201 }
9261 if (any_are_comptime) {9202 astgen.extra.appendSliceAssumeCapacity(args.ret_ty);
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);9203 astgen.extra.appendSliceAssumeCapacity(args.body);
9267 astgen.extra.appendSliceAssumeCapacity(src_locs);9204 astgen.extra.appendSliceAssumeCapacity(src_locs);
92689205
9269 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);9206 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
9207 if (args.ret_br != 0) {
9208 astgen.instructions.items(.data)[args.ret_br].@"break".block_inst = new_index;
9209 }
9270 astgen.instructions.appendAssumeCapacity(.{9210 astgen.instructions.appendAssumeCapacity(.{
9271 .tag = .extended,9211 .tag = .extended,
9272 .data = .{ .extended = .{9212 .data = .{ .extended = .{
...@@ -9279,7 +9219,6 @@ const GenZir = struct {...@@ -9279,7 +9219,6 @@ const GenZir = struct {
9279 .has_align = args.align_inst != .none,9219 .has_align = args.align_inst != .none,
9280 .is_test = args.is_test,9220 .is_test = args.is_test,
9281 .is_extern = args.is_extern,9221 .is_extern = args.is_extern,
9282 .has_comptime_bits = any_are_comptime,
9283 }),9222 }),
9284 .operand = payload_index,9223 .operand = payload_index,
9285 } },9224 } },
...@@ -9287,24 +9226,27 @@ const GenZir = struct {...@@ -9287,24 +9226,27 @@ const GenZir = struct {
9287 gz.instructions.appendAssumeCapacity(new_index);9226 gz.instructions.appendAssumeCapacity(new_index);
9288 return indexToRef(new_index);9227 return indexToRef(new_index);
9289 } else {9228 } else {
9290 try gz.astgen.extra.ensureUnusedCapacity(9229 try astgen.extra.ensureUnusedCapacity(
9291 gpa,9230 gpa,
9292 @typeInfo(Zir.Inst.Func).Struct.fields.len +9231 @typeInfo(Zir.Inst.Func).Struct.fields.len +
9293 args.param_types.len + args.body.len + src_locs.len,9232 args.ret_ty.len + args.body.len + src_locs.len,
9294 );9233 );
92959234
9296 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Func{9235 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.Func{
9297 .return_type = args.ret_ty,9236 .param_block = args.param_block,
9298 .param_types_len = @intCast(u32, args.param_types.len),9237 .ret_body_len = @intCast(u32, args.ret_ty.len),
9299 .body_len = @intCast(u32, args.body.len),9238 .body_len = @intCast(u32, args.body.len),
9300 });9239 });
9301 gz.astgen.appendRefsAssumeCapacity(args.param_types);9240 astgen.extra.appendSliceAssumeCapacity(args.ret_ty);
9302 gz.astgen.extra.appendSliceAssumeCapacity(args.body);9241 astgen.extra.appendSliceAssumeCapacity(args.body);
9303 gz.astgen.extra.appendSliceAssumeCapacity(src_locs);9242 astgen.extra.appendSliceAssumeCapacity(src_locs);
93049243
9305 const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func;9244 const tag: Zir.Inst.Tag = if (args.is_inferred_error) .func_inferred else .func;
9306 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9245 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
9307 gz.astgen.instructions.appendAssumeCapacity(.{9246 if (args.ret_br != 0) {
9247 astgen.instructions.items(.data)[args.ret_br].@"break".block_inst = new_index;
9248 }
9249 astgen.instructions.appendAssumeCapacity(.{
9308 .tag = tag,9250 .tag = tag,
9309 .data = .{ .pl_node = .{9251 .data = .{ .pl_node = .{
9310 .src_node = gz.nodeIndexToRelative(args.src_node),9252 .src_node = gz.nodeIndexToRelative(args.src_node),
...@@ -9380,10 +9322,10 @@ const GenZir = struct {...@@ -9380,10 +9322,10 @@ const GenZir = struct {
9380 assert(callee != .none);9322 assert(callee != .none);
9381 assert(src_node != 0);9323 assert(src_node != 0);
9382 const gpa = gz.astgen.gpa;9324 const gpa = gz.astgen.gpa;
9383 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);9325 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9384 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);9326 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
9385 try gz.astgen.extra.ensureCapacity(gpa, gz.astgen.extra.items.len +9327 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Call).Struct.fields.len +
9386 @typeInfo(Zir.Inst.Call).Struct.fields.len + args.len);9328 args.len);
93879329
9388 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Call{9330 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Call{
9389 .callee = callee,9331 .callee = callee,
...@@ -9412,8 +9354,8 @@ const GenZir = struct {...@@ -9412,8 +9354,8 @@ const GenZir = struct {
9412 ) !Zir.Inst.Index {9354 ) !Zir.Inst.Index {
9413 assert(lhs != .none);9355 assert(lhs != .none);
9414 const gpa = gz.astgen.gpa;9356 const gpa = gz.astgen.gpa;
9415 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);9357 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9416 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);9358 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
94179359
9418 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9360 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
9419 gz.astgen.instructions.appendAssumeCapacity(.{9361 gz.astgen.instructions.appendAssumeCapacity(.{
...@@ -9486,8 +9428,8 @@ const GenZir = struct {...@@ -9486,8 +9428,8 @@ const GenZir = struct {
9486 extra: anytype,9428 extra: anytype,
9487 ) !Zir.Inst.Ref {9429 ) !Zir.Inst.Ref {
9488 const gpa = gz.astgen.gpa;9430 const gpa = gz.astgen.gpa;
9489 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);9431 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9490 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);9432 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
94919433
9492 const payload_index = try gz.astgen.addExtra(extra);9434 const payload_index = try gz.astgen.addExtra(extra);
9493 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9435 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
...@@ -9502,6 +9444,38 @@ const GenZir = struct {...@@ -9502,6 +9444,38 @@ const GenZir = struct {
9502 return indexToRef(new_index);9444 return indexToRef(new_index);
9503 }9445 }
95049446
9447 fn addParam(
9448 gz: *GenZir,
9449 tag: Zir.Inst.Tag,
9450 /// Absolute token index. This function does the conversion to Decl offset.
9451 abs_tok_index: ast.TokenIndex,
9452 name: u32,
9453 body: []const u32,
9454 ) !Zir.Inst.Index {
9455 const gpa = gz.astgen.gpa;
9456 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9457 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
9458 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).Struct.fields.len +
9459 body.len);
9460
9461 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Param{
9462 .name = name,
9463 .body_len = @intCast(u32, body.len),
9464 });
9465 gz.astgen.extra.appendSliceAssumeCapacity(body);
9466
9467 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
9468 gz.astgen.instructions.appendAssumeCapacity(.{
9469 .tag = tag,
9470 .data = .{ .pl_tok = .{
9471 .src_tok = gz.tokenIndexToRelative(abs_tok_index),
9472 .payload_index = payload_index,
9473 } },
9474 });
9475 gz.instructions.appendAssumeCapacity(new_index);
9476 return new_index;
9477 }
9478
9505 fn addExtendedPayload(9479 fn addExtendedPayload(
9506 gz: *GenZir,9480 gz: *GenZir,
9507 opcode: Zir.Inst.Extended,9481 opcode: Zir.Inst.Extended,
...@@ -9509,8 +9483,8 @@ const GenZir = struct {...@@ -9509,8 +9483,8 @@ const GenZir = struct {
9509 ) !Zir.Inst.Ref {9483 ) !Zir.Inst.Ref {
9510 const gpa = gz.astgen.gpa;9484 const gpa = gz.astgen.gpa;
95119485
9512 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);9486 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9513 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);9487 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
95149488
9515 const payload_index = try gz.astgen.addExtra(extra);9489 const payload_index = try gz.astgen.addExtra(extra);
9516 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9490 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
...@@ -9566,8 +9540,8 @@ const GenZir = struct {...@@ -9566,8 +9540,8 @@ const GenZir = struct {
9566 elem_type: Zir.Inst.Ref,9540 elem_type: Zir.Inst.Ref,
9567 ) !Zir.Inst.Ref {9541 ) !Zir.Inst.Ref {
9568 const gpa = gz.astgen.gpa;9542 const gpa = gz.astgen.gpa;
9569 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);9543 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9570 try gz.astgen.instructions.ensureCapacity(gpa, gz.astgen.instructions.len + 1);9544 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
95719545
9572 const payload_index = try gz.astgen.addExtra(Zir.Inst.ArrayTypeSentinel{9546 const payload_index = try gz.astgen.addExtra(Zir.Inst.ArrayTypeSentinel{
9573 .sentinel = sentinel,9547 .sentinel = sentinel,
...@@ -9822,7 +9796,7 @@ const GenZir = struct {...@@ -9822,7 +9796,7 @@ const GenZir = struct {
9822 /// Leaves the `payload_index` field undefined.9796 /// Leaves the `payload_index` field undefined.
9823 fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {9797 fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index {
9824 const gpa = gz.astgen.gpa;9798 const gpa = gz.astgen.gpa;
9825 try gz.instructions.ensureCapacity(gpa, gz.instructions.items.len + 1);9799 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9826 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9800 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
9827 try gz.astgen.instructions.append(gpa, .{9801 try gz.astgen.instructions.append(gpa, .{
9828 .tag = tag,9802 .tag = tag,
src/Compilation.zig+1-1
...@@ -2116,7 +2116,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -2116,7 +2116,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
2116 if (builtin.mode == .Debug and self.verbose_air) {2116 if (builtin.mode == .Debug and self.verbose_air) {
2117 std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});2117 std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});
2118 @import("print_air.zig").dump(gpa, air, decl.namespace.file_scope.zir, liveness);2118 @import("print_air.zig").dump(gpa, air, decl.namespace.file_scope.zir, liveness);
2119 std.debug.print("# End Function AIR: {s}:\n", .{decl.name});2119 std.debug.print("# End Function AIR: {s}\n\n", .{decl.name});
2120 }2120 }
21212121
2122 self.bin_file.updateFunc(module, func, air, liveness) catch |err| switch (err) {2122 self.bin_file.updateFunc(module, func, air, liveness) catch |err| switch (err) {
src/Module.zig+141-26
...@@ -61,6 +61,11 @@ export_owners: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{},...@@ -61,6 +61,11 @@ export_owners: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{},
61/// Keys are fully resolved file paths. This table owns the keys and values.61/// Keys are fully resolved file paths. This table owns the keys and values.
62import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{},62import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{},
6363
64/// The set of all the generic function instantiations. This is used so that when a generic
65/// function is called twice with the same comptime parameter arguments, both calls dispatch
66/// to the same function.
67monomorphed_funcs: MonomorphedFuncsSet = .{},
68
64/// We optimize memory usage for a compilation with no compile errors by storing the69/// We optimize memory usage for a compilation with no compile errors by storing the
65/// error messages and mapping outside of `Decl`.70/// error messages and mapping outside of `Decl`.
66/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.71/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
...@@ -114,6 +119,44 @@ emit_h: ?*GlobalEmitH,...@@ -114,6 +119,44 @@ emit_h: ?*GlobalEmitH,
114119
115test_functions: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},120test_functions: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
116121
122const MonomorphedFuncsSet = std.HashMapUnmanaged(
123 *Fn,
124 void,
125 MonomorphedFuncsContext,
126 std.hash_map.default_max_load_percentage,
127);
128
129const MonomorphedFuncsContext = struct {
130 pub fn eql(ctx: @This(), a: *Fn, b: *Fn) bool {
131 _ = ctx;
132 return a == b;
133 }
134
135 /// Must match `Sema.GenericCallAdapter.hash`.
136 pub fn hash(ctx: @This(), key: *Fn) u64 {
137 _ = ctx;
138 var hasher = std.hash.Wyhash.init(0);
139
140 // The generic function Decl is guaranteed to be the first dependency
141 // of each of its instantiations.
142 const generic_owner_decl = key.owner_decl.dependencies.keys()[0];
143 const generic_func = generic_owner_decl.val.castTag(.function).?.data;
144 std.hash.autoHash(&hasher, @ptrToInt(generic_func));
145
146 // This logic must be kept in sync with the logic in `analyzeCall` that
147 // computes the hash.
148 const comptime_args = key.comptime_args.?;
149 const generic_ty_info = generic_owner_decl.ty.fnInfo();
150 for (generic_ty_info.param_types) |param_ty, i| {
151 if (generic_ty_info.paramIsComptime(i) and param_ty.tag() != .generic_poison) {
152 comptime_args[i].val.hash(param_ty, &hasher);
153 }
154 }
155
156 return hasher.final();
157 }
158};
159
117/// A `Module` has zero or one of these depending on whether `-femit-h` is enabled.160/// A `Module` has zero or one of these depending on whether `-femit-h` is enabled.
118pub const GlobalEmitH = struct {161pub const GlobalEmitH = struct {
119 /// Where to put the output.162 /// Where to put the output.
...@@ -757,6 +800,10 @@ pub const Union = struct {...@@ -757,6 +800,10 @@ pub const Union = struct {
757pub const Fn = struct {800pub const Fn = struct {
758 /// The Decl that corresponds to the function itself.801 /// The Decl that corresponds to the function itself.
759 owner_decl: *Decl,802 owner_decl: *Decl,
803 /// If this is not null, this function is a generic function instantiation, and
804 /// there is a `Value` here for each parameter of the function. Non-comptime
805 /// parameters are marked with an `unreachable_value`.
806 comptime_args: ?[*]TypedValue = null,
760 /// The ZIR instruction that is a function instruction. Use this to find807 /// The ZIR instruction that is a function instruction. Use this to find
761 /// the body. We store this rather than the body directly so that when ZIR808 /// the body. We store this rather than the body directly so that when ZIR
762 /// is regenerated on update(), we can map this to the new corresponding809 /// is regenerated on update(), we can map this to the new corresponding
...@@ -795,6 +842,9 @@ pub const Fn = struct {...@@ -795,6 +842,9 @@ pub const Fn = struct {
795842
796 pub fn getInferredErrorSet(func: *Fn) ?*std.StringHashMapUnmanaged(void) {843 pub fn getInferredErrorSet(func: *Fn) ?*std.StringHashMapUnmanaged(void) {
797 const ret_ty = func.owner_decl.ty.fnReturnType();844 const ret_ty = func.owner_decl.ty.fnReturnType();
845 if (ret_ty.tag() == .generic_poison) {
846 return null;
847 }
798 if (ret_ty.zigTypeTag() == .ErrorUnion) {848 if (ret_ty.zigTypeTag() == .ErrorUnion) {
799 if (ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {849 if (ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {
800 return &payload.data.map;850 return &payload.data.map;
...@@ -1169,6 +1219,8 @@ pub const Scope = struct {...@@ -1169,6 +1219,8 @@ pub const Scope = struct {
1169 /// for the one that will be the same for all Block instances.1219 /// for the one that will be the same for all Block instances.
1170 src_decl: *Decl,1220 src_decl: *Decl,
1171 instructions: ArrayListUnmanaged(Air.Inst.Index),1221 instructions: ArrayListUnmanaged(Air.Inst.Index),
1222 // `param` instructions are collected here to be used by the `func` instruction.
1223 params: std.ArrayListUnmanaged(Param) = .{},
1172 label: ?*Label = null,1224 label: ?*Label = null,
1173 inlining: ?*Inlining,1225 inlining: ?*Inlining,
1174 /// If runtime_index is not 0 then one of these is guaranteed to be non null.1226 /// If runtime_index is not 0 then one of these is guaranteed to be non null.
...@@ -1183,6 +1235,12 @@ pub const Scope = struct {...@@ -1183,6 +1235,12 @@ pub const Scope = struct {
1183 /// when null, it is determined by build mode, changed by @setRuntimeSafety1235 /// when null, it is determined by build mode, changed by @setRuntimeSafety
1184 want_safety: ?bool = null,1236 want_safety: ?bool = null,
11851237
1238 const Param = struct {
1239 /// `noreturn` means `anytype`.
1240 ty: Type,
1241 is_comptime: bool,
1242 };
1243
1186 /// This `Block` maps a block ZIR instruction to the corresponding1244 /// This `Block` maps a block ZIR instruction to the corresponding
1187 /// AIR instruction for break instruction analysis.1245 /// AIR instruction for break instruction analysis.
1188 pub const Label = struct {1246 pub const Label = struct {
...@@ -1630,8 +1688,11 @@ pub const SrcLoc = struct {...@@ -1630,8 +1688,11 @@ pub const SrcLoc = struct {
1630 .@"asm" => tree.asmFull(node),1688 .@"asm" => tree.asmFull(node),
1631 else => unreachable,1689 else => unreachable,
1632 };1690 };
1691 const asm_output = full.outputs[0];
1692 const node_datas = tree.nodes.items(.data);
1693 const ret_ty_node = node_datas[asm_output].lhs;
1633 const main_tokens = tree.nodes.items(.main_token);1694 const main_tokens = tree.nodes.items(.main_token);
1634 const tok_index = main_tokens[full.outputs[0]];1695 const tok_index = main_tokens[ret_ty_node];
1635 const token_starts = tree.tokens.items(.start);1696 const token_starts = tree.tokens.items(.start);
1636 return token_starts[tok_index];1697 return token_starts[tok_index];
1637 },1698 },
...@@ -2095,7 +2156,20 @@ pub const LazySrcLoc = union(enum) {...@@ -2095,7 +2156,20 @@ pub const LazySrcLoc = union(enum) {
2095};2156};
20962157
2097pub const SemaError = error{ OutOfMemory, AnalysisFail };2158pub const SemaError = error{ OutOfMemory, AnalysisFail };
2098pub const CompileError = error{ OutOfMemory, AnalysisFail, NeededSourceLocation };2159pub const CompileError = error{
2160 OutOfMemory,
2161 /// When this is returned, the compile error for the failure has already been recorded.
2162 AnalysisFail,
2163 /// Returned when a compile error needed to be reported but a provided LazySrcLoc was set
2164 /// to the `unneeded` tag. The source location was, in fact, needed. It is expected that
2165 /// somewhere up the call stack, the operation will be retried after doing expensive work
2166 /// to compute a source location.
2167 NeededSourceLocation,
2168 /// A Type or Value was needed to be used during semantic analysis, but it was not available
2169 /// because the function is generic. This is only seen when analyzing the body of a param
2170 /// instruction.
2171 GenericPoison,
2172};
20992173
2100pub fn deinit(mod: *Module) void {2174pub fn deinit(mod: *Module) void {
2101 const gpa = mod.gpa;2175 const gpa = mod.gpa;
...@@ -2177,6 +2251,7 @@ pub fn deinit(mod: *Module) void {...@@ -2177,6 +2251,7 @@ pub fn deinit(mod: *Module) void {
21772251
2178 mod.error_name_list.deinit(gpa);2252 mod.error_name_list.deinit(gpa);
2179 mod.test_functions.deinit(gpa);2253 mod.test_functions.deinit(gpa);
2254 mod.monomorphed_funcs.deinit(gpa);
2180}2255}
21812256
2182fn freeExportList(gpa: *Allocator, export_list: []*Export) void {2257fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
...@@ -2792,14 +2867,16 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) SemaError!void {...@@ -2792,14 +2867,16 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) SemaError!void {
2792 }2867 }
2793 return error.AnalysisFail;2868 return error.AnalysisFail;
2794 },2869 },
2795 else => {2870 error.NeededSourceLocation => unreachable,
2871 error.GenericPoison => unreachable,
2872 else => |e| {
2796 decl.analysis = .sema_failure_retryable;2873 decl.analysis = .sema_failure_retryable;
2797 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);2874 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
2798 mod.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(2875 mod.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
2799 mod.gpa,2876 mod.gpa,
2800 decl.srcLoc(),2877 decl.srcLoc(),
2801 "unable to analyze: {s}",2878 "unable to analyze: {s}",
2802 .{@errorName(err)},2879 .{@errorName(e)},
2803 ));2880 ));
2804 return error.AnalysisFail;2881 return error.AnalysisFail;
2805 },2882 },
...@@ -2899,7 +2976,6 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {...@@ -2899,7 +2976,6 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
2899 .namespace = &struct_obj.namespace,2976 .namespace = &struct_obj.namespace,
2900 .func = null,2977 .func = null,
2901 .owner_func = null,2978 .owner_func = null,
2902 .param_inst_list = &.{},
2903 };2979 };
2904 defer sema.deinit();2980 defer sema.deinit();
2905 var block_scope: Scope.Block = .{2981 var block_scope: Scope.Block = .{
...@@ -2954,7 +3030,6 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2954,7 +3030,6 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
2954 .namespace = decl.namespace,3030 .namespace = decl.namespace,
2955 .func = null,3031 .func = null,
2956 .owner_func = null,3032 .owner_func = null,
2957 .param_inst_list = &.{},
2958 };3033 };
2959 defer sema.deinit();3034 defer sema.deinit();
29603035
...@@ -2980,7 +3055,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2980,7 +3055,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
2980 .inlining = null,3055 .inlining = null,
2981 .is_comptime = true,3056 .is_comptime = true,
2982 };3057 };
2983 defer block_scope.instructions.deinit(gpa);3058 defer {
3059 block_scope.instructions.deinit(gpa);
3060 block_scope.params.deinit(gpa);
3061 }
29843062
2985 const zir_block_index = decl.zirBlockIndex();3063 const zir_block_index = decl.zirBlockIndex();
2986 const inst_data = zir_datas[zir_block_index].pl_node;3064 const inst_data = zir_datas[zir_block_index].pl_node;
...@@ -3625,8 +3703,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {...@@ -3625,8 +3703,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3625 defer decl.value_arena.?.* = arena.state;3703 defer decl.value_arena.?.* = arena.state;
36263704
3627 const fn_ty = decl.ty;3705 const fn_ty = decl.ty;
3628 const param_inst_list = try gpa.alloc(Air.Inst.Ref, fn_ty.fnParamLen());
3629 defer gpa.free(param_inst_list);
36303706
3631 var sema: Sema = .{3707 var sema: Sema = .{
3632 .mod = mod,3708 .mod = mod,
...@@ -3637,7 +3713,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {...@@ -3637,7 +3713,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3637 .namespace = decl.namespace,3713 .namespace = decl.namespace,
3638 .func = func,3714 .func = func,
3639 .owner_func = func,3715 .owner_func = func,
3640 .param_inst_list = param_inst_list,
3641 };3716 };
3642 defer sema.deinit();3717 defer sema.deinit();
36433718
...@@ -3656,29 +3731,71 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {...@@ -3656,29 +3731,71 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3656 };3731 };
3657 defer inner_block.instructions.deinit(gpa);3732 defer inner_block.instructions.deinit(gpa);
36583733
3659 // AIR requires the arg parameters to be the first N instructions.3734 const fn_info = sema.code.getFnInfo(func.zir_body_inst);
3660 try inner_block.instructions.ensureTotalCapacity(gpa, param_inst_list.len);3735 const zir_tags = sema.code.instructions.items(.tag);
3661 for (param_inst_list) |*param_inst, param_index| {3736
3662 const param_type = fn_ty.fnParamType(param_index);3737 // Here we are performing "runtime semantic analysis" for a function body, which means
3738 // we must map the parameter ZIR instructions to `arg` AIR instructions.
3739 // AIR requires the `arg` parameters to be the first N instructions.
3740 // This could be a generic function instantiation, however, in which case we need to
3741 // map the comptime parameters to constant values and only emit arg AIR instructions
3742 // for the runtime ones.
3743 const runtime_params_len = @intCast(u32, fn_ty.fnParamLen());
3744 try inner_block.instructions.ensureTotalCapacity(gpa, runtime_params_len);
3745 try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType`
3746 try sema.inst_map.ensureUnusedCapacity(gpa, fn_info.total_params_len);
3747
3748 var runtime_param_index: usize = 0;
3749 var total_param_index: usize = 0;
3750 for (fn_info.param_body) |inst| {
3751 const name = switch (zir_tags[inst]) {
3752 .param, .param_comptime => blk: {
3753 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
3754 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index).data;
3755 break :blk extra.name;
3756 },
3757
3758 .param_anytype, .param_anytype_comptime => blk: {
3759 const str_tok = sema.code.instructions.items(.data)[inst].str_tok;
3760 break :blk str_tok.start;
3761 },
3762
3763 else => continue,
3764 };
3765 if (func.comptime_args) |comptime_args| {
3766 const arg_tv = comptime_args[total_param_index];
3767 if (arg_tv.val.tag() != .unreachable_value) {
3768 // We have a comptime value for this parameter.
3769 const arg = try sema.addConstant(arg_tv.ty, arg_tv.val);
3770 sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
3771 total_param_index += 1;
3772 continue;
3773 }
3774 }
3775 const param_type = fn_ty.fnParamType(runtime_param_index);
3663 const ty_ref = try sema.addType(param_type);3776 const ty_ref = try sema.addType(param_type);
3664 const arg_index = @intCast(u32, sema.air_instructions.len);3777 const arg_index = @intCast(u32, sema.air_instructions.len);
3665 inner_block.instructions.appendAssumeCapacity(arg_index);3778 inner_block.instructions.appendAssumeCapacity(arg_index);
3666 param_inst.* = Air.indexToRef(arg_index);3779 sema.air_instructions.appendAssumeCapacity(.{
3667 try sema.air_instructions.append(gpa, .{
3668 .tag = .arg,3780 .tag = .arg,
3669 .data = .{3781 .data = .{ .ty_str = .{
3670 .ty_str = .{3782 .ty = ty_ref,
3671 .ty = ty_ref,3783 .str = name,
3672 .str = undefined, // Set in the semantic analysis of the arg instruction.3784 } },
3673 },
3674 },
3675 });3785 });
3786 sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index));
3787 total_param_index += 1;
3788 runtime_param_index += 1;
3676 }3789 }
36773790
3678 func.state = .in_progress;3791 func.state = .in_progress;
3679 log.debug("set {s} to in_progress", .{decl.name});3792 log.debug("set {s} to in_progress", .{decl.name});
36803793
3681 try sema.analyzeFnBody(&inner_block, func.zir_body_inst);3794 _ = sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {
3795 error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
3796 error.GenericPoison => @panic("zig compiler bug: GenericPoison"),
3797 else => |e| return e,
3798 };
36823799
3683 // Copy the block into place and mark that as the main block.3800 // Copy the block into place and mark that as the main block.
3684 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +3801 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
...@@ -3714,7 +3831,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {...@@ -3714,7 +3831,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
3714 decl.analysis = .outdated;3831 decl.analysis = .outdated;
3715}3832}
37163833
3717fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node.Index) !*Decl {3834pub 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.3835 // 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: {3836 const new_decl: *Decl = if (mod.emit_h != null) blk: {
3720 const parent_struct = try mod.gpa.create(DeclPlusEmitH);3837 const parent_struct = try mod.gpa.create(DeclPlusEmitH);
...@@ -4330,7 +4447,6 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) CompileError!void...@@ -4330,7 +4447,6 @@ pub fn analyzeStructFields(mod: *Module, struct_obj: *Struct) CompileError!void
4330 .namespace = &struct_obj.namespace,4447 .namespace = &struct_obj.namespace,
4331 .owner_func = null,4448 .owner_func = null,
4332 .func = null,4449 .func = null,
4333 .param_inst_list = &.{},
4334 };4450 };
4335 defer sema.deinit();4451 defer sema.deinit();
43364452
...@@ -4484,7 +4600,6 @@ pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) CompileError!void {...@@ -4484,7 +4600,6 @@ pub fn analyzeUnionFields(mod: *Module, union_obj: *Union) CompileError!void {
4484 .namespace = &union_obj.namespace,4600 .namespace = &union_obj.namespace,
4485 .owner_func = null,4601 .owner_func = null,
4486 .func = null,4602 .func = null,
4487 .param_inst_list = &.{},
4488 };4603 };
4489 defer sema.deinit();4604 defer sema.deinit();
44904605
src/Sema.zig+625-191
...@@ -29,13 +29,6 @@ owner_func: ?*Module.Fn,...@@ -29,13 +29,6 @@ owner_func: ?*Module.Fn,
29/// This starts out the same as `owner_func` and then diverges in the case of29/// This starts out the same as `owner_func` and then diverges in the case of
30/// an inline or comptime function call.30/// an inline or comptime function call.
31func: ?*Module.Fn,31func: ?*Module.Fn,
32/// For now, AIR requires arg instructions to be the first N instructions in the
33/// AIR code. We store references here for the purpose of `resolveInst`.
34/// This can get reworked with AIR memory layout changes, into simply:
35/// > Denormalized data to make `resolveInst` faster. This is 0 if not inside a function,
36/// > otherwise it is the number of parameters of the function.
37/// > param_count: u32
38param_inst_list: []const Air.Inst.Ref,
39branch_quota: u32 = 1000,32branch_quota: u32 = 1000,
40branch_count: u32 = 0,33branch_count: u32 = 0,
41/// This field is updated when a new source location becomes active, so that34/// This field is updated when a new source location becomes active, so that
...@@ -43,8 +36,22 @@ branch_count: u32 = 0,...@@ -43,8 +36,22 @@ branch_count: u32 = 0,
43/// access to the source location set by the previous instruction which did36/// access to the source location set by the previous instruction which did
44/// contain a mapped source location.37/// contain a mapped source location.
45src: LazySrcLoc = .{ .token_offset = 0 },38src: LazySrcLoc = .{ .token_offset = 0 },
46next_arg_index: usize = 0,
47decl_val_table: std.AutoHashMapUnmanaged(*Decl, Air.Inst.Ref) = .{},39decl_val_table: std.AutoHashMapUnmanaged(*Decl, Air.Inst.Ref) = .{},
40/// When doing a generic function instantiation, this array collects a
41/// `Value` object for each parameter that is comptime known and thus elided
42/// from the generated function. This memory is allocated by a parent `Sema` and
43/// owned by the values arena of the Sema owner_decl.
44comptime_args: []TypedValue = &.{},
45/// Marks the function instruction that `comptime_args` applies to so that we
46/// don't accidentally apply it to a function prototype which is used in the
47/// type expression of a generic function parameter.
48comptime_args_fn_inst: Zir.Inst.Index = 0,
49/// When `comptime_args` is provided, this field is also provided. It was used as
50/// the key in the `monomorphed_funcs` set. The `func` instruction is supposed
51/// to use this instead of allocating a fresh one. This avoids an unnecessary
52/// extra hash table lookup in the `monomorphed_funcs` set.
53/// Sema will set this to null when it takes ownership.
54preallocated_new_func: ?*Module.Fn = null,
4855
49const std = @import("std");56const std = @import("std");
50const mem = std.mem;57const mem = std.mem;
...@@ -80,45 +87,6 @@ pub fn deinit(sema: *Sema) void {...@@ -80,45 +87,6 @@ pub fn deinit(sema: *Sema) void {
80 sema.* = undefined;87 sema.* = undefined;
81}88}
8289
83pub fn analyzeFnBody(
84 sema: *Sema,
85 block: *Scope.Block,
86 fn_body_inst: Zir.Inst.Index,
87) SemaError!void {
88 const tags = sema.code.instructions.items(.tag);
89 const datas = sema.code.instructions.items(.data);
90 const body: []const Zir.Inst.Index = switch (tags[fn_body_inst]) {
91 .func, .func_inferred => blk: {
92 const inst_data = datas[fn_body_inst].pl_node;
93 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
94 const param_types_len = extra.data.param_types_len;
95 const body = sema.code.extra[extra.end + param_types_len ..][0..extra.data.body_len];
96 break :blk body;
97 },
98 .extended => blk: {
99 const extended = datas[fn_body_inst].extended;
100 assert(extended.opcode == .func);
101 const extra = sema.code.extraData(Zir.Inst.ExtendedFunc, extended.operand);
102 const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small);
103 var extra_index: usize = extra.end;
104 extra_index += @boolToInt(small.has_lib_name);
105 extra_index += @boolToInt(small.has_cc);
106 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];
112 break :blk body;
113 },
114 else => unreachable,
115 };
116 _ = sema.analyzeBody(block, body) catch |err| switch (err) {
117 error.NeededSourceLocation => unreachable,
118 else => |e| return e,
119 };
120}
121
122/// Returns only the result from the body that is specified.90/// Returns only the result from the body that is specified.
123/// Only appropriate to call when it is determined at comptime that this body91/// Only appropriate to call when it is determined at comptime that this body
124/// has no peers.92/// has no peers.
...@@ -162,7 +130,6 @@ pub fn analyzeBody(...@@ -162,7 +130,6 @@ pub fn analyzeBody(
162 const inst = body[i];130 const inst = body[i];
163 const air_inst: Air.Inst.Ref = switch (tags[inst]) {131 const air_inst: Air.Inst.Ref = switch (tags[inst]) {
164 // zig fmt: off132 // zig fmt: off
165 .arg => try sema.zirArg(block, inst),
166 .alloc => try sema.zirAlloc(block, inst),133 .alloc => try sema.zirAlloc(block, inst),
167 .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),134 .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)),135 .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
...@@ -499,6 +466,26 @@ pub fn analyzeBody(...@@ -499,6 +466,26 @@ pub fn analyzeBody(
499 i += 1;466 i += 1;
500 continue;467 continue;
501 },468 },
469 .param => {
470 try sema.zirParam(block, inst, false);
471 i += 1;
472 continue;
473 },
474 .param_comptime => {
475 try sema.zirParam(block, inst, true);
476 i += 1;
477 continue;
478 },
479 .param_anytype => {
480 try sema.zirParamAnytype(block, inst, false);
481 i += 1;
482 continue;
483 },
484 .param_anytype_comptime => {
485 try sema.zirParamAnytype(block, inst, true);
486 i += 1;
487 continue;
488 },
502489
503 // Special case instructions to handle comptime control flow.490 // Special case instructions to handle comptime control flow.
504 .repeat_inline => {491 .repeat_inline => {
...@@ -648,6 +635,7 @@ fn resolveValue(...@@ -648,6 +635,7 @@ fn resolveValue(
648 air_ref: Air.Inst.Ref,635 air_ref: Air.Inst.Ref,
649) CompileError!Value {636) CompileError!Value {
650 if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {637 if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {
638 if (val.tag() == .generic_poison) return error.GenericPoison;
651 return val;639 return val;
652 }640 }
653 return sema.failWithNeededComptime(block, src);641 return sema.failWithNeededComptime(block, src);
...@@ -665,6 +653,7 @@ fn resolveConstValue(...@@ -665,6 +653,7 @@ fn resolveConstValue(
665 switch (val.tag()) {653 switch (val.tag()) {
666 .undef => return sema.failWithUseOfUndef(block, src),654 .undef => return sema.failWithUseOfUndef(block, src),
667 .variable => return sema.failWithNeededComptime(block, src),655 .variable => return sema.failWithNeededComptime(block, src),
656 .generic_poison => return error.GenericPoison,
668 else => return val,657 else => return val,
669 }658 }
670 }659 }
...@@ -1044,7 +1033,6 @@ fn zirEnumDecl(...@@ -1044,7 +1033,6 @@ fn zirEnumDecl(
1044 .namespace = &enum_obj.namespace,1033 .namespace = &enum_obj.namespace,
1045 .owner_func = null,1034 .owner_func = null,
1046 .func = null,1035 .func = null,
1047 .param_inst_list = &.{},
1048 .branch_quota = sema.branch_quota,1036 .branch_quota = sema.branch_quota,
1049 .branch_count = sema.branch_count,1037 .branch_count = sema.branch_count,
1050 };1038 };
...@@ -1324,57 +1312,44 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co...@@ -1324,57 +1312,44 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co
13241312
1325 const inst_data = sema.code.instructions.items(.data)[inst].un_node;1313 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1326 const src = inst_data.src();1314 const src = inst_data.src();
1327 const array_ptr = sema.resolveInst(inst_data.operand);1315 const array = sema.resolveInst(inst_data.operand);
1328 const array_ptr_src = src;1316 const array_ty = sema.typeOf(array);
13291317
1330 const elem_ty = sema.typeOf(array_ptr).elemType();1318 if (array_ty.isSlice()) {
1331 if (elem_ty.isSlice()) {1319 return sema.analyzeSliceLen(block, src, array);
1332 const slice_inst = try sema.analyzeLoad(block, src, array_ptr, array_ptr_src);
1333 return sema.analyzeSliceLen(block, src, slice_inst);
1334 }1320 }
1335 if (!elem_ty.isIndexable()) {
1336 const cond_src: LazySrcLoc = .{ .node_offset_for_cond = inst_data.src_node };
1337 const msg = msg: {
1338 const msg = try sema.mod.errMsg(
1339 &block.base,
1340 cond_src,
1341 "type '{}' does not support indexing",
1342 .{elem_ty},
1343 );
1344 errdefer msg.destroy(sema.gpa);
1345 try sema.mod.errNote(
1346 &block.base,
1347 cond_src,
1348 msg,
1349 "for loop operand must be an array, slice, tuple, or vector",
1350 .{},
1351 );
1352 break :msg msg;
1353 };
1354 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
1355 }
1356 const result_ptr = try sema.fieldPtr(block, src, array_ptr, "len", src);
1357 const result_ptr_src = array_ptr_src;
1358 return sema.analyzeLoad(block, src, result_ptr, result_ptr_src);
1359}
13601321
1361fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {1322 if (array_ty.isSinglePointer()) {
1362 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;1323 const elem_ty = array_ty.elemType();
1363 const arg_name = inst_data.get(sema.code);1324 if (elem_ty.isSlice()) {
1364 const arg_index = sema.next_arg_index;1325 const slice_inst = try sema.analyzeLoad(block, src, array, src);
1365 sema.next_arg_index += 1;1326 return sema.analyzeSliceLen(block, src, slice_inst);
13661327 }
1367 // TODO check if arg_name shadows a Decl1328 if (!elem_ty.isIndexable()) {
1368 _ = arg_name;1329 const msg = msg: {
13691330 const msg = try sema.mod.errMsg(
1370 if (block.inlining) |_| {1331 &block.base,
1371 return sema.param_inst_list[arg_index];1332 src,
1333 "type '{}' does not support indexing",
1334 .{elem_ty},
1335 );
1336 errdefer msg.destroy(sema.gpa);
1337 try sema.mod.errNote(
1338 &block.base,
1339 src,
1340 msg,
1341 "for loop operand must be an array, slice, tuple, or vector",
1342 .{},
1343 );
1344 break :msg msg;
1345 };
1346 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
1347 }
1348 const result_ptr = try sema.fieldPtr(block, src, array, "len", src);
1349 return sema.analyzeLoad(block, src, result_ptr, src);
1372 }1350 }
13731351
1374 // Set the name of the Air.Arg instruction for use by codegen debug info.1352 return sema.mod.fail(&block.base, src, "TODO implement Sema.zirIndexablePtrLen", .{});
1375 const air_arg = sema.param_inst_list[arg_index];
1376 sema.air_instructions.items(.data)[Air.refToIndex(air_arg).?].ty_str.str = inst_data.start;
1377 return air_arg;
1378}1353}
13791354
1380fn zirAllocExtended(1355fn zirAllocExtended(
...@@ -2385,6 +2360,40 @@ fn zirCall(...@@ -2385,6 +2360,40 @@ fn zirCall(
2385 return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args);2360 return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args);
2386}2361}
23872362
2363const GenericCallAdapter = struct {
2364 generic_fn: *Module.Fn,
2365 precomputed_hash: u64,
2366 func_ty_info: Type.Payload.Function.Data,
2367 comptime_vals: []const Value,
2368
2369 pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool {
2370 _ = adapted_key;
2371 // The generic function Decl is guaranteed to be the first dependency
2372 // of each of its instantiations.
2373 const generic_owner_decl = other_key.owner_decl.dependencies.keys()[0];
2374 if (ctx.generic_fn.owner_decl != generic_owner_decl) return false;
2375
2376 // This logic must be kept in sync with the logic in `analyzeCall` that
2377 // computes the hash.
2378 const other_comptime_args = other_key.comptime_args.?;
2379 for (ctx.func_ty_info.param_types) |param_ty, i| {
2380 if (ctx.func_ty_info.paramIsComptime(i) and param_ty.tag() != .generic_poison) {
2381 if (!ctx.comptime_vals[i].eql(other_comptime_args[i].val, param_ty)) {
2382 return false;
2383 }
2384 }
2385 }
2386 return true;
2387 }
2388
2389 /// The implementation of the hash is in semantic analysis of function calls, so
2390 /// that any errors when computing the hash can be properly reported.
2391 pub fn hash(ctx: @This(), adapted_key: void) u64 {
2392 _ = adapted_key;
2393 return ctx.precomputed_hash;
2394 }
2395};
2396
2388fn analyzeCall(2397fn analyzeCall(
2389 sema: *Sema,2398 sema: *Sema,
2390 block: *Scope.Block,2399 block: *Scope.Block,
...@@ -2393,41 +2402,44 @@ fn analyzeCall(...@@ -2393,41 +2402,44 @@ fn analyzeCall(
2393 call_src: LazySrcLoc,2402 call_src: LazySrcLoc,
2394 modifier: std.builtin.CallOptions.Modifier,2403 modifier: std.builtin.CallOptions.Modifier,
2395 ensure_result_used: bool,2404 ensure_result_used: bool,
2396 args: []const Air.Inst.Ref,2405 uncasted_args: []const Air.Inst.Ref,
2397) CompileError!Air.Inst.Ref {2406) CompileError!Air.Inst.Ref {
2407 const mod = sema.mod;
2408
2398 const func_ty = sema.typeOf(func);2409 const func_ty = sema.typeOf(func);
2399 if (func_ty.zigTypeTag() != .Fn)2410 if (func_ty.zigTypeTag() != .Fn)
2400 return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func_ty});2411 return mod.fail(&block.base, func_src, "type '{}' not a function", .{func_ty});
24012412
2402 const cc = func_ty.fnCallingConvention();2413 const func_ty_info = func_ty.fnInfo();
2414 const cc = func_ty_info.cc;
2403 if (cc == .Naked) {2415 if (cc == .Naked) {
2404 // TODO add error note: declared here2416 // TODO add error note: declared here
2405 return sema.mod.fail(2417 return mod.fail(
2406 &block.base,2418 &block.base,
2407 func_src,2419 func_src,
2408 "unable to call function with naked calling convention",2420 "unable to call function with naked calling convention",
2409 .{},2421 .{},
2410 );2422 );
2411 }2423 }
2412 const fn_params_len = func_ty.fnParamLen();2424 const fn_params_len = func_ty_info.param_types.len;
2413 if (func_ty.fnIsVarArgs()) {2425 if (func_ty_info.is_var_args) {
2414 assert(cc == .C);2426 assert(cc == .C);
2415 if (args.len < fn_params_len) {2427 if (uncasted_args.len < fn_params_len) {
2416 // TODO add error note: declared here2428 // TODO add error note: declared here
2417 return sema.mod.fail(2429 return mod.fail(
2418 &block.base,2430 &block.base,
2419 func_src,2431 func_src,
2420 "expected at least {d} argument(s), found {d}",2432 "expected at least {d} argument(s), found {d}",
2421 .{ fn_params_len, args.len },2433 .{ fn_params_len, uncasted_args.len },
2422 );2434 );
2423 }2435 }
2424 } else if (fn_params_len != args.len) {2436 } else if (fn_params_len != uncasted_args.len) {
2425 // TODO add error note: declared here2437 // TODO add error note: declared here
2426 return sema.mod.fail(2438 return mod.fail(
2427 &block.base,2439 &block.base,
2428 func_src,2440 func_src,
2429 "expected {d} argument(s), found {d}",2441 "expected {d} argument(s), found {d}",
2430 .{ fn_params_len, args.len },2442 .{ fn_params_len, uncasted_args.len },
2431 );2443 );
2432 }2444 }
24332445
...@@ -2442,21 +2454,30 @@ fn analyzeCall(...@@ -2442,21 +2454,30 @@ fn analyzeCall(
2442 .never_inline,2454 .never_inline,
2443 .no_async,2455 .no_async,
2444 .always_tail,2456 .always_tail,
2445 => return sema.mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{2457 => return mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{
2446 modifier,2458 modifier,
2447 }),2459 }),
2448 }2460 }
24492461
2450 const gpa = sema.gpa;2462 const gpa = sema.gpa;
24512463
2452 const is_comptime_call = block.is_comptime or modifier == .compile_time;2464 const is_comptime_call = block.is_comptime or modifier == .compile_time or
2465 func_ty_info.return_type.requiresComptime();
2453 const is_inline_call = is_comptime_call or modifier == .always_inline or2466 const is_inline_call = is_comptime_call or modifier == .always_inline or
2454 func_ty.fnCallingConvention() == .Inline;2467 func_ty_info.cc == .Inline;
2455 const result: Air.Inst.Ref = if (is_inline_call) res: {2468 const result: Air.Inst.Ref = if (is_inline_call) res: {
2469 // TODO look into not allocating this args array
2470 const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
2471 for (uncasted_args) |uncasted_arg, i| {
2472 const param_ty = func_ty.fnParamType(i);
2473 const arg_src = call_src; // TODO: better source location
2474 args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
2475 }
2476
2456 const func_val = try sema.resolveConstValue(block, func_src, func);2477 const func_val = try sema.resolveConstValue(block, func_src, func);
2457 const module_fn = switch (func_val.tag()) {2478 const module_fn = switch (func_val.tag()) {
2458 .function => func_val.castTag(.function).?.data,2479 .function => func_val.castTag(.function).?.data,
2459 .extern_fn => return sema.mod.fail(&block.base, call_src, "{s} call of extern function", .{2480 .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"),2481 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
2461 }),2482 }),
2462 else => unreachable,2483 else => unreachable,
...@@ -2502,14 +2523,6 @@ fn analyzeCall(...@@ -2502,14 +2523,6 @@ fn analyzeCall(
2502 sema.func = module_fn;2523 sema.func = module_fn;
2503 defer sema.func = parent_func;2524 defer sema.func = parent_func;
25042525
2505 const parent_param_inst_list = sema.param_inst_list;
2506 sema.param_inst_list = args;
2507 defer sema.param_inst_list = parent_param_inst_list;
2508
2509 const parent_next_arg_index = sema.next_arg_index;
2510 sema.next_arg_index = 0;
2511 defer sema.next_arg_index = parent_next_arg_index;
2512
2513 var child_block: Scope.Block = .{2526 var child_block: Scope.Block = .{
2514 .parent = null,2527 .parent = null,
2515 .sema = sema,2528 .sema = sema,
...@@ -2529,16 +2542,229 @@ fn analyzeCall(...@@ -2529,16 +2542,229 @@ fn analyzeCall(
2529 try sema.emitBackwardBranch(&child_block, call_src);2542 try sema.emitBackwardBranch(&child_block, call_src);
25302543
2531 // This will have return instructions analyzed as break instructions to2544 // This will have return instructions analyzed as break instructions to
2532 // the block_inst above.2545 // the block_inst above. Here we are performing "comptime/inline semantic analysis"
2533 try sema.analyzeFnBody(&child_block, module_fn.zir_body_inst);2546 // for a function body, which means we must map the parameter ZIR instructions to
2547 // the AIR instructions of the callsite.
2548 const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst);
2549 const zir_tags = sema.code.instructions.items(.tag);
2550 var arg_i: usize = 0;
2551 try sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, args.len));
2552 for (fn_info.param_body) |inst| {
2553 switch (zir_tags[inst]) {
2554 .param, .param_comptime, .param_anytype, .param_anytype_comptime => {},
2555 else => continue,
2556 }
2557 sema.inst_map.putAssumeCapacityNoClobber(inst, args[arg_i]);
2558 arg_i += 1;
2559 }
2560 _ = try sema.analyzeBody(&child_block, fn_info.body);
2561 break :res try sema.analyzeBlockBody(block, call_src, &child_block, merges);
2562 } else if (func_ty_info.is_generic) res: {
2563 const func_val = try sema.resolveConstValue(block, func_src, func);
2564 const module_fn = func_val.castTag(.function).?.data;
2565 // Check the Module's generic function map with an adapted context, so that we
2566 // can match against `uncasted_args` rather than doing the work below to create a
2567 // generic Scope only to junk it if it matches an existing instantiation.
2568 const namespace = module_fn.owner_decl.namespace;
2569 const fn_zir = namespace.file_scope.zir;
2570 const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst);
2571 const zir_tags = fn_zir.instructions.items(.tag);
2572 const new_module_func = new_func: {
2573 // This hash must match `Module.MonomorphedFuncsContext.hash`.
2574 // For parameters explicitly marked comptime and simple parameter type expressions,
2575 // we know whether a parameter is elided from a monomorphed function, and can
2576 // use it in the hash here. However, for parameter type expressions that are not
2577 // explicitly marked comptime and rely on previous parameter comptime values, we
2578 // don't find out until after generating a monomorphed function whether the parameter
2579 // type ended up being a "must-be-comptime-known" type.
2580 var hasher = std.hash.Wyhash.init(0);
2581 std.hash.autoHash(&hasher, @ptrToInt(module_fn));
2582
2583 const comptime_vals = try sema.arena.alloc(Value, func_ty_info.param_types.len);
2584
2585 for (func_ty_info.param_types) |param_ty, i| {
2586 const is_comptime = func_ty_info.paramIsComptime(i);
2587 if (is_comptime and param_ty.tag() != .generic_poison) {
2588 const arg_src = call_src; // TODO better source location
2589 const casted_arg = try sema.coerce(block, param_ty, uncasted_args[i], arg_src);
2590 if (try sema.resolveMaybeUndefVal(block, arg_src, casted_arg)) |arg_val| {
2591 arg_val.hash(param_ty, &hasher);
2592 comptime_vals[i] = arg_val;
2593 } else {
2594 return sema.failWithNeededComptime(block, arg_src);
2595 }
2596 }
2597 }
2598
2599 const adapter: GenericCallAdapter = .{
2600 .generic_fn = module_fn,
2601 .precomputed_hash = hasher.final(),
2602 .func_ty_info = func_ty_info,
2603 .comptime_vals = comptime_vals,
2604 };
2605 const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter);
2606 if (gop.found_existing) {
2607 const callee_func = gop.key_ptr.*;
2608 break :res try sema.finishGenericCall(
2609 block,
2610 call_src,
2611 callee_func,
2612 func_src,
2613 uncasted_args,
2614 fn_info,
2615 zir_tags,
2616 );
2617 }
2618 gop.key_ptr.* = try gpa.create(Module.Fn);
2619 break :new_func gop.key_ptr.*;
2620 };
2621
2622 {
2623 try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);
2624
2625 // Create a Decl for the new function.
2626 const new_decl = try mod.allocateNewDecl(namespace, module_fn.owner_decl.src_node);
2627 // TODO better names for generic function instantiations
2628 const name_index = mod.getNextAnonNameIndex();
2629 new_decl.name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{
2630 module_fn.owner_decl.name, name_index,
2631 });
2632 new_decl.src_line = module_fn.owner_decl.src_line;
2633 new_decl.is_pub = module_fn.owner_decl.is_pub;
2634 new_decl.is_exported = module_fn.owner_decl.is_exported;
2635 new_decl.has_align = module_fn.owner_decl.has_align;
2636 new_decl.has_linksection = module_fn.owner_decl.has_linksection;
2637 new_decl.zir_decl_index = module_fn.owner_decl.zir_decl_index;
2638 new_decl.alive = true; // This Decl is called at runtime.
2639 new_decl.has_tv = true;
2640 new_decl.owns_tv = true;
2641 new_decl.analysis = .in_progress;
2642 new_decl.generation = mod.generation;
2643
2644 namespace.anon_decls.putAssumeCapacityNoClobber(new_decl, {});
2645
2646 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
2647 errdefer new_decl_arena.deinit();
2648
2649 // Re-run the block that creates the function, with the comptime parameters
2650 // pre-populated inside `inst_map`. This causes `param_comptime` and
2651 // `param_anytype_comptime` ZIR instructions to be ignored, resulting in a
2652 // new, monomorphized function, with the comptime parameters elided.
2653 var child_sema: Sema = .{
2654 .mod = mod,
2655 .gpa = gpa,
2656 .arena = sema.arena,
2657 .code = fn_zir,
2658 .owner_decl = new_decl,
2659 .namespace = namespace,
2660 .func = null,
2661 .owner_func = null,
2662 .comptime_args = try new_decl_arena.allocator.alloc(TypedValue, uncasted_args.len),
2663 .comptime_args_fn_inst = module_fn.zir_body_inst,
2664 .preallocated_new_func = new_module_func,
2665 };
2666 defer child_sema.deinit();
2667
2668 var child_block: Scope.Block = .{
2669 .parent = null,
2670 .sema = &child_sema,
2671 .src_decl = new_decl,
2672 .instructions = .{},
2673 .inlining = null,
2674 .is_comptime = true,
2675 };
2676 defer {
2677 child_block.instructions.deinit(gpa);
2678 child_block.params.deinit(gpa);
2679 }
2680
2681 try child_sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, uncasted_args.len));
2682 var arg_i: usize = 0;
2683 for (fn_info.param_body) |inst| {
2684 const is_comptime = switch (zir_tags[inst]) {
2685 .param_comptime, .param_anytype_comptime => true,
2686 .param, .param_anytype => false,
2687 else => continue,
2688 } or func_ty_info.paramIsComptime(arg_i);
2689 const arg_src = call_src; // TODO: better source location
2690 const arg = uncasted_args[arg_i];
2691 if (try sema.resolveMaybeUndefVal(block, arg_src, arg)) |arg_val| {
2692 const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val);
2693 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
2694 } else if (is_comptime) {
2695 return sema.failWithNeededComptime(block, arg_src);
2696 }
2697 arg_i += 1;
2698 }
2699 const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body);
2700 const new_func_val = try child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst);
2701 const new_func = new_func_val.castTag(.function).?.data;
2702 assert(new_func == new_module_func);
2703
2704 arg_i = 0;
2705 for (fn_info.param_body) |inst| {
2706 switch (zir_tags[inst]) {
2707 .param_comptime, .param_anytype_comptime, .param, .param_anytype => {},
2708 else => continue,
2709 }
2710 const arg = child_sema.inst_map.get(inst).?;
2711 const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(&child_block, .unneeded, arg) catch unreachable).?;
2712
2713 if (arg_val.tag() == .generic_poison) {
2714 child_sema.comptime_args[arg_i] = .{
2715 .ty = Type.initTag(.noreturn),
2716 .val = Value.initTag(.unreachable_value),
2717 };
2718 } else {
2719 child_sema.comptime_args[arg_i] = .{
2720 .ty = try child_sema.typeOf(arg).copy(&new_decl_arena.allocator),
2721 .val = try arg_val.copy(&new_decl_arena.allocator),
2722 };
2723 }
2724
2725 arg_i += 1;
2726 }
2727
2728 // Populate the Decl ty/val with the function and its type.
2729 new_decl.ty = try child_sema.typeOf(new_func_inst).copy(&new_decl_arena.allocator);
2730 new_decl.val = try Value.Tag.function.create(&new_decl_arena.allocator, new_func);
2731 new_decl.analysis = .complete;
25342732
2535 const result = try sema.analyzeBlockBody(block, call_src, &child_block, merges);2733 // The generic function Decl is guaranteed to be the first dependency
2734 // of each of its instantiations.
2735 assert(new_decl.dependencies.keys().len == 0);
2736 try mod.declareDeclDependency(new_decl, module_fn.owner_decl);
25362737
2537 break :res result;2738 // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field
2739 // will be populated, ensuring it will have `analyzeBody` called with the ZIR
2740 // parameters mapped appropriately.
2741 try mod.comp.bin_file.allocateDeclIndexes(new_decl);
2742 try mod.comp.work_queue.writeItem(.{ .codegen_func = new_func });
2743
2744 try new_decl.finalizeNewArena(&new_decl_arena);
2745 }
2746
2747 break :res try sema.finishGenericCall(
2748 block,
2749 call_src,
2750 new_module_func,
2751 func_src,
2752 uncasted_args,
2753 fn_info,
2754 zir_tags,
2755 );
2538 } else res: {2756 } else res: {
2539 if (func_ty.fnIsGeneric()) {2757 const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
2540 return sema.mod.fail(&block.base, func_src, "TODO implement generic fn call", .{});2758 for (uncasted_args) |uncasted_arg, i| {
2759 if (i < fn_params_len) {
2760 const param_ty = func_ty.fnParamType(i);
2761 const arg_src = call_src; // TODO: better source location
2762 args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
2763 } else {
2764 args[i] = uncasted_arg;
2765 }
2541 }2766 }
2767
2542 try sema.requireRuntimeBlock(block, call_src);2768 try sema.requireRuntimeBlock(block, call_src);
2543 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +2769 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
2544 args.len);2770 args.len);
...@@ -2561,6 +2787,75 @@ fn analyzeCall(...@@ -2561,6 +2787,75 @@ fn analyzeCall(
2561 return result;2787 return result;
2562}2788}
25632789
2790fn finishGenericCall(
2791 sema: *Sema,
2792 block: *Scope.Block,
2793 call_src: LazySrcLoc,
2794 callee: *Module.Fn,
2795 func_src: LazySrcLoc,
2796 uncasted_args: []const Air.Inst.Ref,
2797 fn_info: Zir.FnInfo,
2798 zir_tags: []const Zir.Inst.Tag,
2799) CompileError!Air.Inst.Ref {
2800 const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);
2801
2802 // Make a runtime call to the new function, making sure to omit the comptime args.
2803 try sema.requireRuntimeBlock(block, call_src);
2804
2805 const comptime_args = callee.comptime_args.?;
2806 const runtime_args_len = count: {
2807 var count: u32 = 0;
2808 var arg_i: usize = 0;
2809 for (fn_info.param_body) |inst| {
2810 switch (zir_tags[inst]) {
2811 .param_comptime, .param_anytype_comptime, .param, .param_anytype => {
2812 if (comptime_args[arg_i].val.tag() == .unreachable_value) {
2813 count += 1;
2814 }
2815 arg_i += 1;
2816 },
2817 else => continue,
2818 }
2819 }
2820 break :count count;
2821 };
2822 const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len);
2823 {
2824 const new_fn_ty = callee.owner_decl.ty;
2825 var runtime_i: u32 = 0;
2826 var total_i: u32 = 0;
2827 for (fn_info.param_body) |inst| {
2828 switch (zir_tags[inst]) {
2829 .param_comptime, .param_anytype_comptime, .param, .param_anytype => {},
2830 else => continue,
2831 }
2832 const is_runtime = comptime_args[total_i].val.tag() == .unreachable_value;
2833 if (is_runtime) {
2834 const param_ty = new_fn_ty.fnParamType(runtime_i);
2835 const arg_src = call_src; // TODO: better source location
2836 const uncasted_arg = uncasted_args[total_i];
2837 const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
2838 runtime_args[runtime_i] = casted_arg;
2839 runtime_i += 1;
2840 }
2841 total_i += 1;
2842 }
2843 }
2844 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
2845 runtime_args_len);
2846 const func_inst = try block.addInst(.{
2847 .tag = .call,
2848 .data = .{ .pl_op = .{
2849 .operand = callee_inst,
2850 .payload = sema.addExtraAssumeCapacity(Air.Call{
2851 .args_len = runtime_args_len,
2852 }),
2853 } },
2854 });
2855 sema.appendRefsAssumeCapacity(runtime_args);
2856 return func_inst;
2857}
2858
2564fn zirIntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {2859fn zirIntType(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
2565 _ = block;2860 _ = block;
2566 const tracy = trace(@src());2861 const tracy = trace(@src());
...@@ -3186,13 +3481,15 @@ fn zirFunc(...@@ -3186,13 +3481,15 @@ fn zirFunc(
31863481
3187 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;3482 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
3188 const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);3483 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);3484 var extra_index = extra.end;
3485 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
3486 extra_index += ret_ty_body.len;
31903487
3191 var body_inst: Zir.Inst.Index = 0;3488 var body_inst: Zir.Inst.Index = 0;
3192 var src_locs: Zir.Inst.Func.SrcLocs = undefined;3489 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
3193 if (extra.data.body_len != 0) {3490 if (extra.data.body_len != 0) {
3194 body_inst = inst;3491 body_inst = inst;
3195 const extra_index = extra.end + extra.data.param_types_len + extra.data.body_len;3492 extra_index += extra.data.body_len;
3196 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;3493 src_locs = sema.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
3197 }3494 }
31983495
...@@ -3204,9 +3501,8 @@ fn zirFunc(...@@ -3204,9 +3501,8 @@ fn zirFunc(
3204 return sema.funcCommon(3501 return sema.funcCommon(
3205 block,3502 block,
3206 inst_data.src_node,3503 inst_data.src_node,
3207 param_types,
3208 body_inst,3504 body_inst,
3209 extra.data.return_type,3505 ret_ty_body,
3210 cc,3506 cc,
3211 Value.initTag(.null_value),3507 Value.initTag(.null_value),
3212 false,3508 false,
...@@ -3214,7 +3510,6 @@ fn zirFunc(...@@ -3214,7 +3510,6 @@ fn zirFunc(
3214 false,3510 false,
3215 src_locs,3511 src_locs,
3216 null,3512 null,
3217 &.{},
3218 );3513 );
3219}3514}
32203515
...@@ -3222,9 +3517,8 @@ fn funcCommon(...@@ -3222,9 +3517,8 @@ fn funcCommon(
3222 sema: *Sema,3517 sema: *Sema,
3223 block: *Scope.Block,3518 block: *Scope.Block,
3224 src_node_offset: i32,3519 src_node_offset: i32,
3225 zir_param_types: []const Zir.Inst.Ref,
3226 body_inst: Zir.Inst.Index,3520 body_inst: Zir.Inst.Index,
3227 zir_return_type: Zir.Inst.Ref,3521 ret_ty_body: []const Zir.Inst.Index,
3228 cc: std.builtin.CallingConvention,3522 cc: std.builtin.CallingConvention,
3229 align_val: Value,3523 align_val: Value,
3230 var_args: bool,3524 var_args: bool,
...@@ -3232,21 +3526,59 @@ fn funcCommon(...@@ -3232,21 +3526,59 @@ fn funcCommon(
3232 is_extern: bool,3526 is_extern: bool,
3233 src_locs: Zir.Inst.Func.SrcLocs,3527 src_locs: Zir.Inst.Func.SrcLocs,
3234 opt_lib_name: ?[]const u8,3528 opt_lib_name: ?[]const u8,
3235 comptime_bits: []const u32,
3236) CompileError!Air.Inst.Ref {3529) CompileError!Air.Inst.Ref {
3237 const src: LazySrcLoc = .{ .node_offset = src_node_offset };3530 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
3238 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };3531 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
3239 const bare_return_type = try sema.resolveType(block, ret_ty_src, zir_return_type);3532
3533 // The return type body might be a type expression that depends on generic parameters.
3534 // In such case we need to use a generic_poison value for the return type and mark
3535 // the function as generic.
3536 var is_generic = false;
3537 const bare_return_type: Type = ret_ty: {
3538 if (ret_ty_body.len == 0) break :ret_ty Type.initTag(.void);
3539
3540 const err = err: {
3541 // Make sure any nested param instructions don't clobber our work.
3542 const prev_params = block.params;
3543 block.params = .{};
3544 defer {
3545 block.params.deinit(sema.gpa);
3546 block.params = prev_params;
3547 }
3548 if (sema.resolveBody(block, ret_ty_body)) |ret_ty_inst| {
3549 if (sema.analyzeAsType(block, ret_ty_src, ret_ty_inst)) |ret_ty| {
3550 break :ret_ty ret_ty;
3551 } else |err| break :err err;
3552 } else |err| break :err err;
3553 };
3554 switch (err) {
3555 error.GenericPoison => {
3556 // The type is not available until the generic instantiation.
3557 is_generic = true;
3558 break :ret_ty Type.initTag(.generic_poison);
3559 },
3560 else => |e| return e,
3561 }
3562 };
32403563
3241 const mod = sema.mod;3564 const mod = sema.mod;
32423565
3243 const new_func = if (body_inst == 0) undefined else try sema.gpa.create(Module.Fn);3566 const new_func: *Module.Fn = new_func: {
3567 if (body_inst == 0) break :new_func undefined;
3568 if (sema.comptime_args_fn_inst == body_inst) {
3569 const new_func = sema.preallocated_new_func.?;
3570 sema.preallocated_new_func = null; // take ownership
3571 break :new_func new_func;
3572 }
3573 break :new_func try sema.gpa.create(Module.Fn);
3574 };
3244 errdefer if (body_inst != 0) sema.gpa.destroy(new_func);3575 errdefer if (body_inst != 0) sema.gpa.destroy(new_func);
32453576
3246 const fn_ty: Type = fn_ty: {3577 const fn_ty: Type = fn_ty: {
3247 // Hot path for some common function types.3578 // Hot path for some common function types.
3248 if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value and3579 // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.
3249 !inferred_error_set)3580 if (!is_generic and block.params.items.len == 0 and !var_args and
3581 align_val.tag() == .null_value and !inferred_error_set)
3250 {3582 {
3251 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {3583 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
3252 break :fn_ty Type.initTag(.fn_noreturn_no_args);3584 break :fn_ty Type.initTag(.fn_noreturn_no_args);
...@@ -3265,30 +3597,24 @@ fn funcCommon(...@@ -3265,30 +3597,24 @@ fn funcCommon(
3265 }3597 }
3266 }3598 }
32673599
3268 var any_are_comptime = false;3600 const param_types = try sema.arena.alloc(Type, block.params.items.len);
3269 const param_types = try sema.arena.alloc(Type, zir_param_types.len);3601 const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
3270 for (zir_param_types) |param_type, i| {3602 for (block.params.items) |param, i| {
3271 // TODO make a compile error from `resolveType` report the source location3603 param_types[i] = param.ty;
3272 // of the specific parameter. Will need to take a similar strategy as3604 comptime_params[i] = param.is_comptime;
3273 // `resolveSwitchItemVal` to avoid resolving the source location unless3605 is_generic = is_generic or param.is_comptime or
3274 // we actually need to report an error.3606 param.ty.tag() == .generic_poison or param.ty.requiresComptime();
3275 const param_src = src;
3276 param_types[i] = try sema.resolveType(block, param_src, param_type);
3277
3278 any_are_comptime = any_are_comptime or blk: {
3279 if (comptime_bits.len == 0)
3280 break :blk false;
3281 const bag = comptime_bits[i / 32];
3282 const is_comptime = @truncate(u1, bag >> @intCast(u5, i % 32)) != 0;
3283 break :blk is_comptime;
3284 };
3285 }3607 }
32863608
3287 if (align_val.tag() != .null_value) {3609 if (align_val.tag() != .null_value) {
3288 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});3610 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
3289 }3611 }
32903612
3291 const return_type = if (!inferred_error_set) bare_return_type else blk: {3613 is_generic = is_generic or bare_return_type.requiresComptime();
3614
3615 const return_type = if (!inferred_error_set or bare_return_type.tag() == .generic_poison)
3616 bare_return_type
3617 else blk: {
3292 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, .{3618 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, .{
3293 .func = new_func,3619 .func = new_func,
3294 .map = .{},3620 .map = .{},
...@@ -3301,10 +3627,11 @@ fn funcCommon(...@@ -3301,10 +3627,11 @@ fn funcCommon(
33013627
3302 break :fn_ty try Type.Tag.function.create(sema.arena, .{3628 break :fn_ty try Type.Tag.function.create(sema.arena, .{
3303 .param_types = param_types,3629 .param_types = param_types,
3630 .comptime_params = comptime_params.ptr,
3304 .return_type = return_type,3631 .return_type = return_type,
3305 .cc = cc,3632 .cc = cc,
3306 .is_var_args = var_args,3633 .is_var_args = var_args,
3307 .is_generic = any_are_comptime,3634 .is_generic = is_generic,
3308 });3635 });
3309 };3636 };
33103637
...@@ -3363,11 +3690,16 @@ fn funcCommon(...@@ -3363,11 +3690,16 @@ fn funcCommon(
3363 const is_inline = fn_ty.fnCallingConvention() == .Inline;3690 const is_inline = fn_ty.fnCallingConvention() == .Inline;
3364 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;3691 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;
33653692
3693 const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == body_inst) blk: {
3694 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;
3695 } else null;
3696
3366 const fn_payload = try sema.arena.create(Value.Payload.Function);3697 const fn_payload = try sema.arena.create(Value.Payload.Function);
3367 new_func.* = .{3698 new_func.* = .{
3368 .state = anal_state,3699 .state = anal_state,
3369 .zir_body_inst = body_inst,3700 .zir_body_inst = body_inst,
3370 .owner_decl = sema.owner_decl,3701 .owner_decl = sema.owner_decl,
3702 .comptime_args = comptime_args,
3371 .lbrace_line = src_locs.lbrace_line,3703 .lbrace_line = src_locs.lbrace_line,
3372 .rbrace_line = src_locs.rbrace_line,3704 .rbrace_line = src_locs.rbrace_line,
3373 .lbrace_column = @truncate(u16, src_locs.columns),3705 .lbrace_column = @truncate(u16, src_locs.columns),
...@@ -3380,6 +3712,113 @@ fn funcCommon(...@@ -3380,6 +3712,113 @@ fn funcCommon(
3380 return sema.addConstant(fn_ty, Value.initPayload(&fn_payload.base));3712 return sema.addConstant(fn_ty, Value.initPayload(&fn_payload.base));
3381}3713}
33823714
3715fn zirParam(
3716 sema: *Sema,
3717 block: *Scope.Block,
3718 inst: Zir.Inst.Index,
3719 is_comptime: bool,
3720) CompileError!void {
3721 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
3722 const src = inst_data.src();
3723 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
3724 const param_name = sema.code.nullTerminatedString(extra.data.name);
3725 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
3726
3727 // TODO check if param_name shadows a Decl. This only needs to be done if
3728 // usingnamespace is implemented.
3729 _ = param_name;
3730
3731 // We could be in a generic function instantiation, or we could be evaluating a generic
3732 // function without any comptime args provided.
3733 const param_ty = param_ty: {
3734 const err = err: {
3735 // Make sure any nested param instructions don't clobber our work.
3736 const prev_params = block.params;
3737 block.params = .{};
3738 defer {
3739 block.params.deinit(sema.gpa);
3740 block.params = prev_params;
3741 }
3742
3743 if (sema.resolveBody(block, body)) |param_ty_inst| {
3744 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {
3745 break :param_ty param_ty;
3746 } else |err| break :err err;
3747 } else |err| break :err err;
3748 };
3749 switch (err) {
3750 error.GenericPoison => {
3751 // The type is not available until the generic instantiation.
3752 // We result the param instruction with a poison value and
3753 // insert an anytype parameter.
3754 try block.params.append(sema.gpa, .{
3755 .ty = Type.initTag(.generic_poison),
3756 .is_comptime = is_comptime,
3757 });
3758 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);
3759 return;
3760 },
3761 else => |e| return e,
3762 }
3763 };
3764 if (sema.inst_map.get(inst)) |arg| {
3765 if (is_comptime or param_ty.requiresComptime()) {
3766 // We have a comptime value for this parameter so it should be elided from the
3767 // function type of the function instruction in this block.
3768 const coerced_arg = try sema.coerce(block, param_ty, arg, src);
3769 sema.inst_map.putAssumeCapacity(inst, coerced_arg);
3770 return;
3771 }
3772 // Even though a comptime argument is provided, the generic function wants to treat
3773 // this as a runtime parameter.
3774 assert(sema.inst_map.remove(inst));
3775 }
3776
3777 try block.params.append(sema.gpa, .{
3778 .ty = param_ty,
3779 .is_comptime = is_comptime or param_ty.requiresComptime(),
3780 });
3781 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
3782 try sema.inst_map.putNoClobber(sema.gpa, inst, result);
3783}
3784
3785fn zirParamAnytype(
3786 sema: *Sema,
3787 block: *Scope.Block,
3788 inst: Zir.Inst.Index,
3789 is_comptime: bool,
3790) CompileError!void {
3791 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
3792 const param_name = inst_data.get(sema.code);
3793
3794 // TODO check if param_name shadows a Decl. This only needs to be done if
3795 // usingnamespace is implemented.
3796 _ = param_name;
3797
3798 if (sema.inst_map.get(inst)) |air_ref| {
3799 const param_ty = sema.typeOf(air_ref);
3800 if (is_comptime or param_ty.requiresComptime()) {
3801 // We have a comptime value for this parameter so it should be elided from the
3802 // function type of the function instruction in this block.
3803 return;
3804 }
3805 // The map is already populated but we do need to add a runtime parameter.
3806 try block.params.append(sema.gpa, .{
3807 .ty = param_ty,
3808 .is_comptime = false,
3809 });
3810 return;
3811 }
3812
3813 // We are evaluating a generic function without any comptime args provided.
3814
3815 try block.params.append(sema.gpa, .{
3816 .ty = Type.initTag(.generic_poison),
3817 .is_comptime = is_comptime,
3818 });
3819 try sema.inst_map.put(sema.gpa, inst, .generic_poison);
3820}
3821
3383fn zirAs(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {3822fn zirAs(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
3384 const tracy = trace(@src());3823 const tracy = trace(@src());
3385 defer tracy.end();3824 defer tracy.end();
...@@ -4898,18 +5337,18 @@ fn analyzeArithmetic(...@@ -4898,18 +5337,18 @@ fn analyzeArithmetic(
4898) CompileError!Air.Inst.Ref {5337) CompileError!Air.Inst.Ref {
4899 const lhs_ty = sema.typeOf(lhs);5338 const lhs_ty = sema.typeOf(lhs);
4900 const rhs_ty = sema.typeOf(rhs);5339 const rhs_ty = sema.typeOf(rhs);
4901 if (lhs_ty.zigTypeTag() == .Vector and rhs_ty.zigTypeTag() == .Vector) {5340 const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
5341 const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
5342 if (lhs_zig_ty_tag == .Vector and rhs_zig_ty_tag == .Vector) {
4902 if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {5343 if (lhs_ty.arrayLen() != rhs_ty.arrayLen()) {
4903 return sema.mod.fail(&block.base, src, "vector length mismatch: {d} and {d}", .{5344 return sema.mod.fail(&block.base, src, "vector length mismatch: {d} and {d}", .{
4904 lhs_ty.arrayLen(),5345 lhs_ty.arrayLen(), rhs_ty.arrayLen(),
4905 rhs_ty.arrayLen(),
4906 });5346 });
4907 }5347 }
4908 return sema.mod.fail(&block.base, src, "TODO implement support for vectors in zirBinOp", .{});5348 return sema.mod.fail(&block.base, src, "TODO implement support for vectors in zirBinOp", .{});
4909 } else if (lhs_ty.zigTypeTag() == .Vector or rhs_ty.zigTypeTag() == .Vector) {5349 } else if (lhs_zig_ty_tag == .Vector or rhs_zig_ty_tag == .Vector) {
4910 return sema.mod.fail(&block.base, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{5350 return sema.mod.fail(&block.base, src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
4911 lhs_ty,5351 lhs_ty, rhs_ty,
4912 rhs_ty,
4913 });5352 });
4914 }5353 }
49155354
...@@ -4929,7 +5368,9 @@ fn analyzeArithmetic(...@@ -4929,7 +5368,9 @@ fn analyzeArithmetic(
4929 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;5368 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
49305369
4931 if (!is_int and !(is_float and floatOpAllowed(zir_tag))) {5370 if (!is_int and !(is_float and floatOpAllowed(zir_tag))) {
4932 return sema.mod.fail(&block.base, src, "invalid operands to binary expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) });5371 return sema.mod.fail(&block.base, src, "invalid operands to binary expression: '{s}' and '{s}'", .{
5372 @tagName(lhs_zig_ty_tag), @tagName(rhs_zig_ty_tag),
5373 });
4933 }5374 }
49345375
4935 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {5376 if (try sema.resolveMaybeUndefVal(block, lhs_src, casted_lhs)) |lhs_val| {
...@@ -5728,6 +6169,10 @@ fn analyzeRet(...@@ -5728,6 +6169,10 @@ fn analyzeRet(
5728 const casted_operand = if (!need_coercion) operand else op: {6169 const casted_operand = if (!need_coercion) operand else op: {
5729 const func = sema.func.?;6170 const func = sema.func.?;
5730 const fn_ty = func.owner_decl.ty;6171 const fn_ty = func.owner_decl.ty;
6172 // TODO: In the case of a comptime/inline function call of a generic function,
6173 // this needs to be the resolved return type based on the function parameter type
6174 // expressions being evaluated with comptime arguments passed in. Otherwise, this
6175 // ends up being .generic_poison and failing the comptime/inline function call analysis.
5731 const fn_ret_ty = fn_ty.fnReturnType();6176 const fn_ret_ty = fn_ty.fnReturnType();
5732 break :op try sema.coerce(block, fn_ret_ty, operand, src);6177 break :op try sema.coerce(block, fn_ret_ty, operand, src);
5733 };6178 };
...@@ -6545,15 +6990,8 @@ fn zirFuncExtended(...@@ -6545,15 +6990,8 @@ fn zirFuncExtended(
6545 break :blk align_tv.val;6990 break :blk align_tv.val;
6546 } else Value.initTag(.null_value);6991 } else Value.initTag(.null_value);
65476992
6548 const comptime_bits: []const u32 = if (!small.has_comptime_bits) &.{} else blk: {6993 const ret_ty_body = sema.code.extra[extra_index..][0..extra.data.ret_body_len];
6549 const amt = (extra.data.param_types_len + 31) / 32;6994 extra_index += ret_ty_body.len;
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;
65576995
6558 var body_inst: Zir.Inst.Index = 0;6996 var body_inst: Zir.Inst.Index = 0;
6559 var src_locs: Zir.Inst.Func.SrcLocs = undefined;6997 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
...@@ -6570,9 +7008,8 @@ fn zirFuncExtended(...@@ -6570,9 +7008,8 @@ fn zirFuncExtended(
6570 return sema.funcCommon(7008 return sema.funcCommon(
6571 block,7009 block,
6572 extra.data.src_node,7010 extra.data.src_node,
6573 param_types,
6574 body_inst,7011 body_inst,
6575 extra.data.return_type,7012 ret_ty_body,
6576 cc,7013 cc,
6577 align_val,7014 align_val,
6578 is_var_args,7015 is_var_args,
...@@ -6580,7 +7017,6 @@ fn zirFuncExtended(...@@ -6580,7 +7017,6 @@ fn zirFuncExtended(
6580 is_extern,7017 is_extern,
6581 src_locs,7018 src_locs,
6582 lib_name,7019 lib_name,
6583 comptime_bits,
6584 );7020 );
6585}7021}
65867022
...@@ -6797,19 +7233,12 @@ fn safetyPanic(...@@ -6797,19 +7233,12 @@ fn safetyPanic(
6797 const msg_inst = msg_inst: {7233 const msg_inst = msg_inst: {
6798 // TODO instead of making a new decl for every panic in the entire compilation,7234 // TODO instead of making a new decl for every panic in the entire compilation,
6799 // introduce the concept of a reference-counted decl for these7235 // introduce the concept of a reference-counted decl for these
6800 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);7236 var anon_decl = try block.startAnonDecl();
6801 errdefer new_decl_arena.deinit();7237 defer anon_decl.deinit();
68027238 break :msg_inst try sema.analyzeDeclRef(try anon_decl.finish(
6803 const decl_ty = try Type.Tag.array_u8.create(&new_decl_arena.allocator, msg.len);7239 try Type.Tag.array_u8.create(anon_decl.arena(), msg.len),
6804 const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, msg);7240 try Value.Tag.bytes.create(anon_decl.arena(), msg),
68057241 ));
6806 const new_decl = try sema.mod.createAnonymousDecl(&block.base, .{
6807 .ty = decl_ty,
6808 .val = decl_val,
6809 });
6810 errdefer sema.mod.deleteAnonDecl(&block.base, new_decl);
6811 try new_decl.finalizeNewArena(&new_decl_arena);
6812 break :msg_inst try sema.analyzeDeclRef(new_decl);
6813 };7242 };
68147243
6815 const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src);7244 const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src);
...@@ -7469,8 +7898,10 @@ fn coerce(...@@ -7469,8 +7898,10 @@ fn coerce(
7469 inst: Air.Inst.Ref,7898 inst: Air.Inst.Ref,
7470 inst_src: LazySrcLoc,7899 inst_src: LazySrcLoc,
7471) CompileError!Air.Inst.Ref {7900) CompileError!Air.Inst.Ref {
7472 if (dest_type_unresolved.tag() == .var_args_param) {7901 switch (dest_type_unresolved.tag()) {
7473 return sema.coerceVarArgParam(block, inst, inst_src);7902 .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src),
7903 .generic_poison => return inst,
7904 else => {},
7474 }7905 }
7475 const dest_type_src = inst_src; // TODO better source location7906 const dest_type_src = inst_src; // TODO better source location
7476 const dest_type = try sema.resolveTypeFields(block, dest_type_src, dest_type_unresolved);7907 const dest_type = try sema.resolveTypeFields(block, dest_type_src, dest_type_unresolved);
...@@ -8671,6 +9102,7 @@ fn typeHasOnePossibleValue(...@@ -8671,6 +9102,7 @@ fn typeHasOnePossibleValue(
86719102
8672 .inferred_alloc_const => unreachable,9103 .inferred_alloc_const => unreachable,
8673 .inferred_alloc_mut => unreachable,9104 .inferred_alloc_mut => unreachable,
9105 .generic_poison => return error.GenericPoison,
8674 };9106 };
8675}9107}
86769108
...@@ -8793,6 +9225,8 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {...@@ -8793,6 +9225,8 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
8793 .fn_ccc_void_no_args => return .fn_ccc_void_no_args_type,9225 .fn_ccc_void_no_args => return .fn_ccc_void_no_args_type,
8794 .single_const_pointer_to_comptime_int => return .single_const_pointer_to_comptime_int_type,9226 .single_const_pointer_to_comptime_int => return .single_const_pointer_to_comptime_int_type,
8795 .const_slice_u8 => return .const_slice_u8_type,9227 .const_slice_u8 => return .const_slice_u8_type,
9228 .anyerror_void_error_union => return .anyerror_void_error_union_type,
9229 .generic_poison => return .generic_poison_type,
8796 else => {},9230 else => {},
8797 }9231 }
8798 try sema.air_instructions.append(sema.gpa, .{9232 try sema.air_instructions.append(sema.gpa, .{
...@@ -8810,7 +9244,7 @@ fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {...@@ -8810,7 +9244,7 @@ fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {
8810 return sema.addConstant(ty, Value.initTag(.undef));9244 return sema.addConstant(ty, Value.initTag(.undef));
8811}9245}
88129246
8813fn addConstant(sema: *Sema, ty: Type, val: Value) CompileError!Air.Inst.Ref {9247pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {
8814 const gpa = sema.gpa;9248 const gpa = sema.gpa;
8815 const ty_inst = try sema.addType(ty);9249 const ty_inst = try sema.addType(ty);
8816 try sema.air_values.append(gpa, val);9250 try sema.air_values.append(gpa, val);
src/Zir.zig+196-63
...@@ -61,7 +61,7 @@ pub const ExtraIndex = enum(u32) {...@@ -61,7 +61,7 @@ pub const ExtraIndex = enum(u32) {
61 _,61 _,
62};62};
6363
64pub fn getMainStruct(zir: Zir) Zir.Inst.Index {64pub fn getMainStruct(zir: Zir) Inst.Index {
65 return zir.extra[@enumToInt(ExtraIndex.main_struct)] -65 return zir.extra[@enumToInt(ExtraIndex.main_struct)] -
66 @intCast(u32, Inst.Ref.typed_value_map.len);66 @intCast(u32, Inst.Ref.typed_value_map.len);
67}67}
...@@ -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,
...@@ -1687,6 +1704,8 @@ pub const Inst = struct {...@@ -1687,6 +1704,8 @@ pub const Inst = struct {
1687 fn_ccc_void_no_args_type,1704 fn_ccc_void_no_args_type,
1688 single_const_pointer_to_comptime_int_type,1705 single_const_pointer_to_comptime_int_type,
1689 const_slice_u8_type,1706 const_slice_u8_type,
1707 anyerror_void_error_union_type,
1708 generic_poison_type,
16901709
1691 /// `undefined` (untyped)1710 /// `undefined` (untyped)
1692 undef,1711 undef,
...@@ -1714,6 +1733,9 @@ pub const Inst = struct {...@@ -1714,6 +1733,9 @@ pub const Inst = struct {
1714 calling_convention_c,1733 calling_convention_c,
1715 /// `std.builtin.CallingConvention.Inline`1734 /// `std.builtin.CallingConvention.Inline`
1716 calling_convention_inline,1735 calling_convention_inline,
1736 /// Used for generic parameters where the type and value
1737 /// is not known until generic function instantiation.
1738 generic_poison,
17171739
1718 _,1740 _,
17191741
...@@ -1892,6 +1914,14 @@ pub const Inst = struct {...@@ -1892,6 +1914,14 @@ pub const Inst = struct {
1892 .ty = Type.initTag(.type),1914 .ty = Type.initTag(.type),
1893 .val = Value.initTag(.const_slice_u8_type),1915 .val = Value.initTag(.const_slice_u8_type),
1894 },1916 },
1917 .anyerror_void_error_union_type = .{
1918 .ty = Type.initTag(.type),
1919 .val = Value.initTag(.anyerror_void_error_union_type),
1920 },
1921 .generic_poison_type = .{
1922 .ty = Type.initTag(.type),
1923 .val = Value.initTag(.generic_poison_type),
1924 },
1895 .enum_literal_type = .{1925 .enum_literal_type = .{
1896 .ty = Type.initTag(.type),1926 .ty = Type.initTag(.type),
1897 .val = Value.initTag(.enum_literal_type),1927 .val = Value.initTag(.enum_literal_type),
...@@ -1989,6 +2019,10 @@ pub const Inst = struct {...@@ -1989,6 +2019,10 @@ pub const Inst = struct {
1989 .ty = Type.initTag(.calling_convention),2019 .ty = Type.initTag(.calling_convention),
1990 .val = .{ .ptr_otherwise = &calling_convention_inline_payload.base },2020 .val = .{ .ptr_otherwise = &calling_convention_inline_payload.base },
1991 },2021 },
2022 .generic_poison = .{
2023 .ty = Type.initTag(.generic_poison),
2024 .val = Value.initTag(.generic_poison),
2025 },
1992 });2026 });
1993 };2027 };
19942028
...@@ -2047,6 +2081,17 @@ pub const Inst = struct {...@@ -2047,6 +2081,17 @@ pub const Inst = struct {
2047 return .{ .node_offset = self.src_node };2081 return .{ .node_offset = self.src_node };
2048 }2082 }
2049 },2083 },
2084 pl_tok: struct {
2085 /// Offset from Decl AST token index.
2086 src_tok: ast.TokenIndex,
2087 /// index into extra.
2088 /// `Tag` determines what lives there.
2089 payload_index: u32,
2090
2091 pub fn src(self: @This()) LazySrcLoc {
2092 return .{ .token_offset = self.src_tok };
2093 }
2094 },
2050 bin: Bin,2095 bin: Bin,
2051 /// For strings which may contain null bytes.2096 /// For strings which may contain null bytes.
2052 str: struct {2097 str: struct {
...@@ -2170,6 +2215,7 @@ pub const Inst = struct {...@@ -2170,6 +2215,7 @@ pub const Inst = struct {
2170 un_node,2215 un_node,
2171 un_tok,2216 un_tok,
2172 pl_node,2217 pl_node,
2218 pl_tok,
2173 bin,2219 bin,
2174 str,2220 str,
2175 str_tok,2221 str_tok,
...@@ -2226,17 +2272,15 @@ pub const Inst = struct {...@@ -2226,17 +2272,15 @@ pub const Inst = struct {
2226 /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set2272 /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
2227 /// 1. cc: Ref, // if has_cc is set2273 /// 1. cc: Ref, // if has_cc is set
2228 /// 2. align: Ref, // if has_align is set2274 /// 2. align: Ref, // if has_align is set
2229 /// 3. comptime_bits: u32 // for every 32 parameters, if has_comptime_bits is set2275 /// 3. return_type: Index // for each ret_body_len
2230 /// - sets of 1 bit:2276 /// 4. body: Index // for each body_len
2231 /// 0bX: whether corresponding parameter is comptime2277 /// 5. src_locs: Func.SrcLocs // if body_len != 0
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 {2278 pub const ExtendedFunc = struct {
2237 src_node: i32,2279 src_node: i32,
2238 return_type: Ref,2280 /// If this is 0 it means a void return type.
2239 param_types_len: u32,2281 ret_body_len: u32,
2282 /// Points to the block that contains the param instructions for this function.
2283 param_block: Index,
2240 body_len: u32,2284 body_len: u32,
22412285
2242 pub const Small = packed struct {2286 pub const Small = packed struct {
...@@ -2247,8 +2291,7 @@ pub const Inst = struct {...@@ -2247,8 +2291,7 @@ pub const Inst = struct {
2247 has_align: bool,2291 has_align: bool,
2248 is_test: bool,2292 is_test: bool,
2249 is_extern: bool,2293 is_extern: bool,
2250 has_comptime_bits: bool,2294 _: u9 = undefined,
2251 _: u8 = undefined,
2252 };2295 };
2253 };2296 };
22542297
...@@ -2271,13 +2314,14 @@ pub const Inst = struct {...@@ -2271,13 +2314,14 @@ pub const Inst = struct {
2271 };2314 };
22722315
2273 /// Trailing:2316 /// Trailing:
2274 /// 0. param_type: Ref // for each param_types_len2317 /// 0. return_type: Index // for each ret_body_len
2275 /// - `none` indicates that the param type is `anytype`.
2276 /// 1. body: Index // for each body_len2318 /// 1. body: Index // for each body_len
2277 /// 2. src_locs: SrcLocs // if body_len != 02319 /// 2. src_locs: SrcLocs // if body_len != 0
2278 pub const Func = struct {2320 pub const Func = struct {
2279 return_type: Ref,2321 /// If this is 0 it means a void return type.
2280 param_types_len: u32,2322 ret_body_len: u32,
2323 /// Points to the block that contains the param instructions for this function.
2324 param_block: Index,
2281 body_len: u32,2325 body_len: u32,
22822326
2283 pub const SrcLocs = struct {2327 pub const SrcLocs = struct {
...@@ -2764,6 +2808,14 @@ pub const Inst = struct {...@@ -2764,6 +2808,14 @@ pub const Inst = struct {
2764 args: Ref,2808 args: Ref,
2765 };2809 };
27662810
2811 /// Trailing: inst: Index // for every body_len
2812 pub const Param = struct {
2813 /// Null-terminated string index.
2814 name: u32,
2815 /// The body contains the type of the parameter.
2816 body_len: u32,
2817 };
2818
2767 /// Trailing:2819 /// Trailing:
2768 /// 0. type_inst: Ref, // if small 0b000X is set2820 /// 0. type_inst: Ref, // if small 0b000X is set
2769 /// 1. align_inst: Ref, // if small 0b00X0 is set2821 /// 1. align_inst: Ref, // if small 0b00X0 is set
...@@ -3108,11 +3160,14 @@ const Writer = struct {...@@ -3108,11 +3160,14 @@ const Writer = struct {
3108 .decl_ref,3160 .decl_ref,
3109 .decl_val,3161 .decl_val,
3110 .import,3162 .import,
3111 .arg,
3112 .ret_err_value,3163 .ret_err_value,
3113 .ret_err_value_code,3164 .ret_err_value_code,
3165 .param_anytype,
3166 .param_anytype_comptime,
3114 => try self.writeStrTok(stream, inst),3167 => try self.writeStrTok(stream, inst),
31153168
3169 .param, .param_comptime => try self.writeParam(stream, inst),
3170
3116 .func => try self.writeFunc(stream, inst, false),3171 .func => try self.writeFunc(stream, inst, false),
3117 .func_inferred => try self.writeFunc(stream, inst, true),3172 .func_inferred => try self.writeFunc(stream, inst, true),
31183173
...@@ -3314,6 +3369,22 @@ const Writer = struct {...@@ -3314,6 +3369,22 @@ const Writer = struct {
3314 try self.writeSrc(stream, inst_data.src());3369 try self.writeSrc(stream, inst_data.src());
3315 }3370 }
33163371
3372 fn writeParam(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3373 const inst_data = self.code.instructions.items(.data)[inst].pl_tok;
3374 const extra = self.code.extraData(Inst.Param, inst_data.payload_index);
3375 const body = self.code.extra[extra.end..][0..extra.data.body_len];
3376 try stream.print("\"{}\", ", .{
3377 std.zig.fmtEscapes(self.code.nullTerminatedString(extra.data.name)),
3378 });
3379 try stream.writeAll("{\n");
3380 self.indent += 2;
3381 try self.writeBody(stream, body);
3382 self.indent -= 2;
3383 try stream.writeByteNTimes(' ', self.indent);
3384 try stream.writeAll(") ");
3385 try self.writeSrc(stream, inst_data.src());
3386 }
3387
3317 fn writePlNodeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void {3388 fn writePlNodeBin(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3318 const inst_data = self.code.instructions.items(.data)[inst].pl_node;3389 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
3319 const extra = self.code.extraData(Inst.Bin, inst_data.payload_index).data;3390 const extra = self.code.extraData(Inst.Bin, inst_data.payload_index).data;
...@@ -4277,17 +4348,21 @@ const Writer = struct {...@@ -4277,17 +4348,21 @@ const Writer = struct {
4277 const inst_data = self.code.instructions.items(.data)[inst].pl_node;4348 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
4278 const src = inst_data.src();4349 const src = inst_data.src();
4279 const extra = self.code.extraData(Inst.Func, inst_data.payload_index);4350 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);4351 var extra_index = extra.end;
4281 const body = self.code.extra[extra.end + param_types.len ..][0..extra.data.body_len];4352
4353 const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
4354 extra_index += ret_ty_body.len;
4355
4356 const body = self.code.extra[extra_index..][0..extra.data.body_len];
4357 extra_index += body.len;
4358
4282 var src_locs: Zir.Inst.Func.SrcLocs = undefined;4359 var src_locs: Zir.Inst.Func.SrcLocs = undefined;
4283 if (body.len != 0) {4360 if (body.len != 0) {
4284 const extra_index = extra.end + param_types.len + body.len;
4285 src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;4361 src_locs = self.code.extraData(Zir.Inst.Func.SrcLocs, extra_index).data;
4286 }4362 }
4287 return self.writeFuncCommon(4363 return self.writeFuncCommon(
4288 stream,4364 stream,
4289 param_types,4365 ret_ty_body,
4290 extra.data.return_type,
4291 inferred_error_set,4366 inferred_error_set,
4292 false,4367 false,
4293 false,4368 false,
...@@ -4296,7 +4371,6 @@ const Writer = struct {...@@ -4296,7 +4371,6 @@ const Writer = struct {
4296 body,4371 body,
4297 src,4372 src,
4298 src_locs,4373 src_locs,
4299 &.{},
4300 );4374 );
4301 }4375 }
43024376
...@@ -4323,15 +4397,8 @@ const Writer = struct {...@@ -4323,15 +4397,8 @@ const Writer = struct {
4323 break :blk align_inst;4397 break :blk align_inst;
4324 };4398 };
43254399
4326 const comptime_bits: []const u32 = if (!small.has_comptime_bits) &.{} else blk: {4400 const ret_ty_body = self.code.extra[extra_index..][0..extra.data.ret_body_len];
4327 const amt = (extra.data.param_types_len + 31) / 32;4401 extra_index += ret_ty_body.len;
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;
43354402
4336 const body = self.code.extra[extra_index..][0..extra.data.body_len];4403 const body = self.code.extra[extra_index..][0..extra.data.body_len];
4337 extra_index += body.len;4404 extra_index += body.len;
...@@ -4342,8 +4409,7 @@ const Writer = struct {...@@ -4342,8 +4409,7 @@ const Writer = struct {
4342 }4409 }
4343 return self.writeFuncCommon(4410 return self.writeFuncCommon(
4344 stream,4411 stream,
4345 param_types,4412 ret_ty_body,
4346 extra.data.return_type,
4347 small.is_inferred_error,4413 small.is_inferred_error,
4348 small.is_var_args,4414 small.is_var_args,
4349 small.is_extern,4415 small.is_extern,
...@@ -4352,7 +4418,6 @@ const Writer = struct {...@@ -4352,7 +4418,6 @@ const Writer = struct {
4352 body,4418 body,
4353 src,4419 src,
4354 src_locs,4420 src_locs,
4355 comptime_bits,
4356 );4421 );
4357 }4422 }
43584423
...@@ -4426,8 +4491,7 @@ const Writer = struct {...@@ -4426,8 +4491,7 @@ const Writer = struct {
4426 fn writeFuncCommon(4491 fn writeFuncCommon(
4427 self: *Writer,4492 self: *Writer,
4428 stream: anytype,4493 stream: anytype,
4429 param_types: []const Inst.Ref,4494 ret_ty_body: []const Inst.Index,
4430 ret_ty: Inst.Ref,
4431 inferred_error_set: bool,4495 inferred_error_set: bool,
4432 var_args: bool,4496 var_args: bool,
4433 is_extern: bool,4497 is_extern: bool,
...@@ -4436,20 +4500,18 @@ const Writer = struct {...@@ -4436,20 +4500,18 @@ const Writer = struct {
4436 body: []const Inst.Index,4500 body: []const Inst.Index,
4437 src: LazySrcLoc,4501 src: LazySrcLoc,
4438 src_locs: Zir.Inst.Func.SrcLocs,4502 src_locs: Zir.Inst.Func.SrcLocs,
4439 comptime_bits: []const u32,
4440 ) !void {4503 ) !void {
4441 try stream.writeAll("[");4504 if (ret_ty_body.len == 0) {
4442 for (param_types) |param_type, i| {4505 try stream.writeAll("ret_ty=void");
4443 if (i != 0) try stream.writeAll(", ");4506 } else {
4444 if (comptime_bits.len != 0) {4507 try stream.writeAll("ret_ty={\n");
4445 const bag = comptime_bits[i / 32];4508 self.indent += 2;
4446 const is_comptime = @truncate(u1, bag >> @intCast(u5, i % 32)) != 0;4509 try self.writeBody(stream, ret_ty_body);
4447 try self.writeFlag(stream, "comptime ", is_comptime);4510 self.indent -= 2;
4448 }4511 try stream.writeByteNTimes(' ', self.indent);
4449 try self.writeInstRef(stream, param_type);4512 try stream.writeAll("}");
4450 }4513 }
4451 try stream.writeAll("], ");4514
4452 try self.writeInstRef(stream, ret_ty);
4453 try self.writeOptionalInstRef(stream, ", cc=", cc);4515 try self.writeOptionalInstRef(stream, ", cc=", cc);
4454 try self.writeOptionalInstRef(stream, ", align=", align_inst);4516 try self.writeOptionalInstRef(stream, ", align=", align_inst);
4455 try self.writeFlag(stream, ", vargs", var_args);4517 try self.writeFlag(stream, ", vargs", var_args);
...@@ -4457,9 +4519,9 @@ const Writer = struct {...@@ -4457,9 +4519,9 @@ const Writer = struct {
4457 try self.writeFlag(stream, ", inferror", inferred_error_set);4519 try self.writeFlag(stream, ", inferror", inferred_error_set);
44584520
4459 if (body.len == 0) {4521 if (body.len == 0) {
4460 try stream.writeAll(", {}) ");4522 try stream.writeAll(", body={}) ");
4461 } else {4523 } else {
4462 try stream.writeAll(", {\n");4524 try stream.writeAll(", body={\n");
4463 self.indent += 2;4525 self.indent += 2;
4464 try self.writeBody(stream, body);4526 try self.writeBody(stream, body);
4465 self.indent -= 2;4527 self.indent -= 2;
...@@ -4714,8 +4776,7 @@ fn findDeclsInner(...@@ -4714,8 +4776,7 @@ fn findDeclsInner(
47144776
4715 const inst_data = datas[inst].pl_node;4777 const inst_data = datas[inst].pl_node;
4716 const extra = zir.extraData(Inst.Func, inst_data.payload_index);4778 const extra = zir.extraData(Inst.Func, inst_data.payload_index);
4717 const param_types_len = extra.data.param_types_len;4779 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);4780 return zir.findDeclsBody(list, body);
4720 },4781 },
4721 .extended => {4782 .extended => {
...@@ -4730,7 +4791,6 @@ fn findDeclsInner(...@@ -4730,7 +4791,6 @@ fn findDeclsInner(
4730 extra_index += @boolToInt(small.has_lib_name);4791 extra_index += @boolToInt(small.has_lib_name);
4731 extra_index += @boolToInt(small.has_cc);4792 extra_index += @boolToInt(small.has_cc);
4732 extra_index += @boolToInt(small.has_align);4793 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];4794 const body = zir.extra[extra_index..][0..extra.data.body_len];
4735 return zir.findDeclsBody(list, body);4795 return zir.findDeclsBody(list, body);
4736 },4796 },
...@@ -4885,10 +4945,83 @@ fn findDeclsSwitchMulti(...@@ -4885,10 +4945,83 @@ fn findDeclsSwitchMulti(
48854945
4886fn findDeclsBody(4946fn findDeclsBody(
4887 zir: Zir,4947 zir: Zir,
4888 list: *std.ArrayList(Zir.Inst.Index),4948 list: *std.ArrayList(Inst.Index),
4889 body: []const Zir.Inst.Index,4949 body: []const Inst.Index,
4890) Allocator.Error!void {4950) Allocator.Error!void {
4891 for (body) |member| {4951 for (body) |member| {
4892 try zir.findDeclsInner(list, member);4952 try zir.findDeclsInner(list, member);
4893 }4953 }
4894}4954}
4955
4956pub const FnInfo = struct {
4957 param_body: []const Inst.Index,
4958 ret_ty_body: []const Inst.Index,
4959 body: []const Inst.Index,
4960 total_params_len: u32,
4961};
4962
4963pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
4964 const tags = zir.instructions.items(.tag);
4965 const datas = zir.instructions.items(.data);
4966 const info: struct {
4967 param_block: Inst.Index,
4968 body: []const Inst.Index,
4969 ret_ty_body: []const Inst.Index,
4970 } = switch (tags[fn_inst]) {
4971 .func, .func_inferred => blk: {
4972 const inst_data = datas[fn_inst].pl_node;
4973 const extra = zir.extraData(Inst.Func, inst_data.payload_index);
4974 var extra_index: usize = extra.end;
4975
4976 const ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len];
4977 extra_index += ret_ty_body.len;
4978
4979 const body = zir.extra[extra_index..][0..extra.data.body_len];
4980 extra_index += body.len;
4981
4982 break :blk .{
4983 .param_block = extra.data.param_block,
4984 .ret_ty_body = ret_ty_body,
4985 .body = body,
4986 };
4987 },
4988 .extended => blk: {
4989 const extended = datas[fn_inst].extended;
4990 assert(extended.opcode == .func);
4991 const extra = zir.extraData(Inst.ExtendedFunc, extended.operand);
4992 const small = @bitCast(Inst.ExtendedFunc.Small, extended.small);
4993 var extra_index: usize = extra.end;
4994 extra_index += @boolToInt(small.has_lib_name);
4995 extra_index += @boolToInt(small.has_cc);
4996 extra_index += @boolToInt(small.has_align);
4997 const ret_ty_body = zir.extra[extra_index..][0..extra.data.ret_body_len];
4998 extra_index += ret_ty_body.len;
4999 const body = zir.extra[extra_index..][0..extra.data.body_len];
5000 extra_index += body.len;
5001 break :blk .{
5002 .param_block = extra.data.param_block,
5003 .ret_ty_body = ret_ty_body,
5004 .body = body,
5005 };
5006 },
5007 else => unreachable,
5008 };
5009 assert(tags[info.param_block] == .block or tags[info.param_block] == .block_inline);
5010 const param_block = zir.extraData(Inst.Block, datas[info.param_block].pl_node.payload_index);
5011 const param_body = zir.extra[param_block.end..][0..param_block.data.body_len];
5012 var total_params_len: u32 = 0;
5013 for (param_body) |inst| {
5014 switch (tags[inst]) {
5015 .param, .param_comptime, .param_anytype, .param_anytype_comptime => {
5016 total_params_len += 1;
5017 },
5018 else => continue,
5019 }
5020 }
5021 return .{
5022 .param_body = param_body,
5023 .ret_ty_body = info.ret_ty_body,
5024 .body = info.body,
5025 .total_params_len = total_params_len,
5026 };
5027}
src/codegen/llvm.zig+44-6
...@@ -575,6 +575,14 @@ pub const DeclGen = struct {...@@ -575,6 +575,14 @@ pub const DeclGen = struct {
575 const info = t.intInfo(self.module.getTarget());575 const info = t.intInfo(self.module.getTarget());
576 return self.context.intType(info.bits);576 return self.context.intType(info.bits);
577 },577 },
578 .Float => switch (t.floatBits(self.module.getTarget())) {
579 16 => return self.context.halfType(),
580 32 => return self.context.floatType(),
581 64 => return self.context.doubleType(),
582 80 => return self.context.x86FP80Type(),
583 128 => return self.context.fp128Type(),
584 else => unreachable,
585 },
578 .Bool => return self.context.intType(1),586 .Bool => return self.context.intType(1),
579 .Pointer => {587 .Pointer => {
580 if (t.isSlice()) {588 if (t.isSlice()) {
...@@ -661,7 +669,6 @@ pub const DeclGen = struct {...@@ -661,7 +669,6 @@ pub const DeclGen = struct {
661669
662 .BoundFn => @panic("TODO remove BoundFn from the language"),670 .BoundFn => @panic("TODO remove BoundFn from the language"),
663671
664 .Float,
665 .Enum,672 .Enum,
666 .Union,673 .Union,
667 .Opaque,674 .Opaque,
...@@ -699,13 +706,40 @@ pub const DeclGen = struct {...@@ -699,13 +706,40 @@ pub const DeclGen = struct {
699 }706 }
700 return llvm_int;707 return llvm_int;
701 },708 },
709 .Float => {
710 if (tv.ty.floatBits(self.module.getTarget()) <= 64) {
711 const llvm_ty = try self.llvmType(tv.ty);
712 return llvm_ty.constReal(tv.val.toFloat(f64));
713 }
714 return self.todo("bitcast to f128 from an integer", .{});
715 },
702 .Pointer => switch (tv.val.tag()) {716 .Pointer => switch (tv.val.tag()) {
703 .decl_ref => {717 .decl_ref => {
704 const decl = tv.val.castTag(.decl_ref).?.data;718 if (tv.ty.isSlice()) {
705 decl.alive = true;719 var buf: Type.Payload.ElemType = undefined;
706 const val = try self.resolveGlobalDecl(decl);720 const ptr_ty = tv.ty.slicePtrFieldType(&buf);
707 const llvm_type = try self.llvmType(tv.ty);721 var slice_len: Value.Payload.U64 = .{
708 return val.constBitCast(llvm_type);722 .base = .{ .tag = .int_u64 },
723 .data = tv.val.sliceLen(),
724 };
725 const fields: [2]*const llvm.Value = .{
726 try self.genTypedValue(.{
727 .ty = ptr_ty,
728 .val = tv.val,
729 }),
730 try self.genTypedValue(.{
731 .ty = Type.initTag(.usize),
732 .val = Value.initPayload(&slice_len.base),
733 }),
734 };
735 return self.context.constStruct(&fields, fields.len, .False);
736 } else {
737 const decl = tv.val.castTag(.decl_ref).?.data;
738 decl.alive = true;
739 const val = try self.resolveGlobalDecl(decl);
740 const llvm_type = try self.llvmType(tv.ty);
741 return val.constBitCast(llvm_type);
742 }
709 },743 },
710 .variable => {744 .variable => {
711 const decl = tv.val.castTag(.variable).?.data.owner_decl;745 const decl = tv.val.castTag(.variable).?.data.owner_decl;
...@@ -839,6 +873,10 @@ pub const DeclGen = struct {...@@ -839,6 +873,10 @@ pub const DeclGen = struct {
839 .False,873 .False,
840 );874 );
841 },875 },
876 .ComptimeInt => unreachable,
877 .ComptimeFloat => unreachable,
878 .Type => unreachable,
879 .EnumLiteral => unreachable,
842 else => return self.todo("implement const of type '{}'", .{tv.ty}),880 else => return self.todo("implement const of type '{}'", .{tv.ty}),
843 }881 }
844 }882 }
src/codegen/llvm/bindings.zig+18
...@@ -31,6 +31,21 @@ pub const Context = opaque {...@@ -31,6 +31,21 @@ pub const Context = opaque {
31 pub const intType = LLVMIntTypeInContext;31 pub const intType = LLVMIntTypeInContext;
32 extern fn LLVMIntTypeInContext(C: *const Context, NumBits: c_uint) *const Type;32 extern fn LLVMIntTypeInContext(C: *const Context, NumBits: c_uint) *const Type;
3333
34 pub const halfType = LLVMHalfTypeInContext;
35 extern fn LLVMHalfTypeInContext(C: *const Context) *const Type;
36
37 pub const floatType = LLVMFloatTypeInContext;
38 extern fn LLVMFloatTypeInContext(C: *const Context) *const Type;
39
40 pub const doubleType = LLVMDoubleTypeInContext;
41 extern fn LLVMDoubleTypeInContext(C: *const Context) *const Type;
42
43 pub const x86FP80Type = LLVMX86FP80TypeInContext;
44 extern fn LLVMX86FP80TypeInContext(C: *const Context) *const Type;
45
46 pub const fp128Type = LLVMFP128TypeInContext;
47 extern fn LLVMFP128TypeInContext(C: *const Context) *const Type;
48
34 pub const voidType = LLVMVoidTypeInContext;49 pub const voidType = LLVMVoidTypeInContext;
35 extern fn LLVMVoidTypeInContext(C: *const Context) *const Type;50 extern fn LLVMVoidTypeInContext(C: *const Context) *const Type;
3651
...@@ -127,6 +142,9 @@ pub const Type = opaque {...@@ -127,6 +142,9 @@ pub const Type = opaque {
127 pub const constInt = LLVMConstInt;142 pub const constInt = LLVMConstInt;
128 extern fn LLVMConstInt(IntTy: *const Type, N: c_ulonglong, SignExtend: Bool) *const Value;143 extern fn LLVMConstInt(IntTy: *const Type, N: c_ulonglong, SignExtend: Bool) *const Value;
129144
145 pub const constReal = LLVMConstReal;
146 extern fn LLVMConstReal(RealTy: *const Type, N: f64) *const Value;
147
130 pub const constArray = LLVMConstArray;148 pub const constArray = LLVMConstArray;
131 extern fn LLVMConstArray(ElementTy: *const Type, ConstantVals: [*]*const Value, Length: c_uint) *const Value;149 extern fn LLVMConstArray(ElementTy: *const Type, ConstantVals: [*]*const Value, Length: c_uint) *const Value;
132150
src/print_air.zig+1-1
...@@ -222,7 +222,7 @@ const Writer = struct {...@@ -222,7 +222,7 @@ const Writer = struct {
222 const extra = w.air.extraData(Air.Block, ty_pl.payload);222 const extra = w.air.extraData(Air.Block, ty_pl.payload);
223 const body = w.air.extra[extra.end..][0..extra.data.body_len];223 const body = w.air.extra[extra.end..][0..extra.data.body_len];
224224
225 try s.writeAll("{\n");225 try s.print("{}, {{\n", .{w.air.getRefType(ty_pl.ty)});
226 const old_indent = w.indent;226 const old_indent = w.indent;
227 w.indent += 2;227 w.indent += 2;
228 try w.writeBody(s, body);228 try w.writeBody(s, body);
src/type.zig+193-26
...@@ -21,8 +21,14 @@ pub const Type = extern union {...@@ -21,8 +21,14 @@ pub const Type = extern union {
21 tag_if_small_enough: usize,21 tag_if_small_enough: usize,
22 ptr_otherwise: *Payload,22 ptr_otherwise: *Payload,
2323
24 pub fn zigTypeTag(self: Type) std.builtin.TypeId {24 pub fn zigTypeTag(ty: Type) std.builtin.TypeId {
25 switch (self.tag()) {25 return ty.zigTypeTagOrPoison() catch unreachable;
26 }
27
28 pub fn zigTypeTagOrPoison(ty: Type) error{GenericPoison}!std.builtin.TypeId {
29 switch (ty.tag()) {
30 .generic_poison => return error.GenericPoison,
31
26 .u1,32 .u1,
27 .u8,33 .u8,
28 .i8,34 .i8,
...@@ -548,8 +554,13 @@ pub const Type = extern union {...@@ -548,8 +554,13 @@ pub const Type = extern union {
548554
549 pub fn hash(self: Type) u64 {555 pub fn hash(self: Type) u64 {
550 var hasher = std.hash.Wyhash.init(0);556 var hasher = std.hash.Wyhash.init(0);
557 self.hashWithHasher(&hasher);
558 return hasher.final();
559 }
560
561 pub fn hashWithHasher(self: Type, hasher: *std.hash.Wyhash) void {
551 const zig_type_tag = self.zigTypeTag();562 const zig_type_tag = self.zigTypeTag();
552 std.hash.autoHash(&hasher, zig_type_tag);563 std.hash.autoHash(hasher, zig_type_tag);
553 switch (zig_type_tag) {564 switch (zig_type_tag) {
554 .Type,565 .Type,
555 .Void,566 .Void,
...@@ -567,34 +578,34 @@ pub const Type = extern union {...@@ -567,34 +578,34 @@ pub const Type = extern union {
567 .Int => {578 .Int => {
568 // Detect that e.g. u64 != usize, even if the bits match on a particular target.579 // Detect that e.g. u64 != usize, even if the bits match on a particular target.
569 if (self.isNamedInt()) {580 if (self.isNamedInt()) {
570 std.hash.autoHash(&hasher, self.tag());581 std.hash.autoHash(hasher, self.tag());
571 } else {582 } else {
572 // Remaining cases are arbitrary sized integers.583 // Remaining cases are arbitrary sized integers.
573 // The target will not be branched upon, because we handled target-dependent cases above.584 // The target will not be branched upon, because we handled target-dependent cases above.
574 const info = self.intInfo(@as(Target, undefined));585 const info = self.intInfo(@as(Target, undefined));
575 std.hash.autoHash(&hasher, info.signedness);586 std.hash.autoHash(hasher, info.signedness);
576 std.hash.autoHash(&hasher, info.bits);587 std.hash.autoHash(hasher, info.bits);
577 }588 }
578 },589 },
579 .Array, .Vector => {590 .Array, .Vector => {
580 std.hash.autoHash(&hasher, self.arrayLen());591 std.hash.autoHash(hasher, self.arrayLen());
581 std.hash.autoHash(&hasher, self.elemType().hash());592 std.hash.autoHash(hasher, self.elemType().hash());
582 // TODO hash array sentinel593 // TODO hash array sentinel
583 },594 },
584 .Fn => {595 .Fn => {
585 std.hash.autoHash(&hasher, self.fnReturnType().hash());596 std.hash.autoHash(hasher, self.fnReturnType().hash());
586 std.hash.autoHash(&hasher, self.fnCallingConvention());597 std.hash.autoHash(hasher, self.fnCallingConvention());
587 const params_len = self.fnParamLen();598 const params_len = self.fnParamLen();
588 std.hash.autoHash(&hasher, params_len);599 std.hash.autoHash(hasher, params_len);
589 var i: usize = 0;600 var i: usize = 0;
590 while (i < params_len) : (i += 1) {601 while (i < params_len) : (i += 1) {
591 std.hash.autoHash(&hasher, self.fnParamType(i).hash());602 std.hash.autoHash(hasher, self.fnParamType(i).hash());
592 }603 }
593 std.hash.autoHash(&hasher, self.fnIsVarArgs());604 std.hash.autoHash(hasher, self.fnIsVarArgs());
594 },605 },
595 .Optional => {606 .Optional => {
596 var buf: Payload.ElemType = undefined;607 var buf: Payload.ElemType = undefined;
597 std.hash.autoHash(&hasher, self.optionalChild(&buf).hash());608 std.hash.autoHash(hasher, self.optionalChild(&buf).hash());
598 },609 },
599 .Float,610 .Float,
600 .Struct,611 .Struct,
...@@ -611,7 +622,6 @@ pub const Type = extern union {...@@ -611,7 +622,6 @@ pub const Type = extern union {
611 // TODO implement more type hashing622 // TODO implement more type hashing
612 },623 },
613 }624 }
614 return hasher.final();
615 }625 }
616626
617 pub const HashContext64 = struct {627 pub const HashContext64 = struct {
...@@ -699,6 +709,7 @@ pub const Type = extern union {...@@ -699,6 +709,7 @@ pub const Type = extern union {
699 .export_options,709 .export_options,
700 .extern_options,710 .extern_options,
701 .@"anyframe",711 .@"anyframe",
712 .generic_poison,
702 => unreachable,713 => unreachable,
703714
704 .array_u8,715 .array_u8,
...@@ -759,12 +770,15 @@ pub const Type = extern union {...@@ -759,12 +770,15 @@ pub const Type = extern union {
759 for (payload.param_types) |param_type, i| {770 for (payload.param_types) |param_type, i| {
760 param_types[i] = try param_type.copy(allocator);771 param_types[i] = try param_type.copy(allocator);
761 }772 }
773 const other_comptime_params = payload.comptime_params[0..payload.param_types.len];
774 const comptime_params = try allocator.dupe(bool, other_comptime_params);
762 return Tag.function.create(allocator, .{775 return Tag.function.create(allocator, .{
763 .return_type = try payload.return_type.copy(allocator),776 .return_type = try payload.return_type.copy(allocator),
764 .param_types = param_types,777 .param_types = param_types,
765 .cc = payload.cc,778 .cc = payload.cc,
766 .is_var_args = payload.is_var_args,779 .is_var_args = payload.is_var_args,
767 .is_generic = payload.is_generic,780 .is_generic = payload.is_generic,
781 .comptime_params = comptime_params.ptr,
768 });782 });
769 },783 },
770 .pointer => {784 .pointer => {
...@@ -1080,11 +1094,118 @@ pub const Type = extern union {...@@ -1080,11 +1094,118 @@ pub const Type = extern union {
1080 },1094 },
1081 .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"),1095 .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"),
1082 .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"),1096 .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"),
1097 .generic_poison => return writer.writeAll("(generic poison)"),
1083 }1098 }
1084 unreachable;1099 unreachable;
1085 }1100 }
1086 }1101 }
10871102
1103 /// Anything that reports hasCodeGenBits() false returns false here as well.
1104 /// `generic_poison` will return false.
1105 pub fn requiresComptime(ty: Type) bool {
1106 return switch (ty.tag()) {
1107 .u1,
1108 .u8,
1109 .i8,
1110 .u16,
1111 .i16,
1112 .u32,
1113 .i32,
1114 .u64,
1115 .i64,
1116 .u128,
1117 .i128,
1118 .usize,
1119 .isize,
1120 .c_short,
1121 .c_ushort,
1122 .c_int,
1123 .c_uint,
1124 .c_long,
1125 .c_ulong,
1126 .c_longlong,
1127 .c_ulonglong,
1128 .c_longdouble,
1129 .f16,
1130 .f32,
1131 .f64,
1132 .f128,
1133 .c_void,
1134 .bool,
1135 .void,
1136 .anyerror,
1137 .noreturn,
1138 .@"anyframe",
1139 .@"null",
1140 .@"undefined",
1141 .atomic_ordering,
1142 .atomic_rmw_op,
1143 .calling_convention,
1144 .float_mode,
1145 .reduce_op,
1146 .call_options,
1147 .export_options,
1148 .extern_options,
1149 .manyptr_u8,
1150 .manyptr_const_u8,
1151 .fn_noreturn_no_args,
1152 .fn_void_no_args,
1153 .fn_naked_noreturn_no_args,
1154 .fn_ccc_void_no_args,
1155 .single_const_pointer_to_comptime_int,
1156 .const_slice_u8,
1157 .anyerror_void_error_union,
1158 .empty_struct_literal,
1159 .function,
1160 .empty_struct,
1161 .error_set,
1162 .error_set_single,
1163 .error_set_inferred,
1164 .@"opaque",
1165 .generic_poison,
1166 => false,
1167
1168 .type,
1169 .comptime_int,
1170 .comptime_float,
1171 .enum_literal,
1172 => true,
1173
1174 .var_args_param => unreachable,
1175 .inferred_alloc_mut => unreachable,
1176 .inferred_alloc_const => unreachable,
1177
1178 .array_u8,
1179 .array_u8_sentinel_0,
1180 .array,
1181 .array_sentinel,
1182 .vector,
1183 .pointer,
1184 .single_const_pointer,
1185 .single_mut_pointer,
1186 .many_const_pointer,
1187 .many_mut_pointer,
1188 .c_const_pointer,
1189 .c_mut_pointer,
1190 .const_slice,
1191 .mut_slice,
1192 .int_signed,
1193 .int_unsigned,
1194 .optional,
1195 .optional_single_mut_pointer,
1196 .optional_single_const_pointer,
1197 .error_union,
1198 .anyframe_T,
1199 .@"struct",
1200 .@"union",
1201 .union_tagged,
1202 .enum_simple,
1203 .enum_full,
1204 .enum_nonexhaustive,
1205 => false, // TODO some of these should be `true` depending on their child types
1206 };
1207 }
1208
1088 pub fn toValue(self: Type, allocator: *Allocator) Allocator.Error!Value {1209 pub fn toValue(self: Type, allocator: *Allocator) Allocator.Error!Value {
1089 switch (self.tag()) {1210 switch (self.tag()) {
1090 .u1 => return Value.initTag(.u1_type),1211 .u1 => return Value.initTag(.u1_type),
...@@ -1179,7 +1300,6 @@ pub const Type = extern union {...@@ -1179,7 +1300,6 @@ pub const Type = extern union {
1179 .fn_void_no_args,1300 .fn_void_no_args,
1180 .fn_naked_noreturn_no_args,1301 .fn_naked_noreturn_no_args,
1181 .fn_ccc_void_no_args,1302 .fn_ccc_void_no_args,
1182 .function,
1183 .single_const_pointer_to_comptime_int,1303 .single_const_pointer_to_comptime_int,
1184 .const_slice_u8,1304 .const_slice_u8,
1185 .array_u8_sentinel_0,1305 .array_u8_sentinel_0,
...@@ -1204,6 +1324,8 @@ pub const Type = extern union {...@@ -1204,6 +1324,8 @@ pub const Type = extern union {
1204 .anyframe_T,1324 .anyframe_T,
1205 => true,1325 => true,
12061326
1327 .function => !self.castTag(.function).?.data.is_generic,
1328
1207 .@"struct" => {1329 .@"struct" => {
1208 // TODO introduce lazy value mechanism1330 // TODO introduce lazy value mechanism
1209 const struct_obj = self.castTag(.@"struct").?.data;1331 const struct_obj = self.castTag(.@"struct").?.data;
...@@ -1283,6 +1405,7 @@ pub const Type = extern union {...@@ -1283,6 +1405,7 @@ pub const Type = extern union {
1283 .inferred_alloc_const => unreachable,1405 .inferred_alloc_const => unreachable,
1284 .inferred_alloc_mut => unreachable,1406 .inferred_alloc_mut => unreachable,
1285 .var_args_param => unreachable,1407 .var_args_param => unreachable,
1408 .generic_poison => unreachable,
1286 };1409 };
1287 }1410 }
12881411
...@@ -1505,6 +1628,8 @@ pub const Type = extern union {...@@ -1505,6 +1628,8 @@ pub const Type = extern union {
1505 .@"opaque",1628 .@"opaque",
1506 .var_args_param,1629 .var_args_param,
1507 => unreachable,1630 => unreachable,
1631
1632 .generic_poison => unreachable,
1508 };1633 };
1509 }1634 }
15101635
...@@ -1532,6 +1657,7 @@ pub const Type = extern union {...@@ -1532,6 +1657,7 @@ pub const Type = extern union {
1532 .inferred_alloc_mut => unreachable,1657 .inferred_alloc_mut => unreachable,
1533 .@"opaque" => unreachable,1658 .@"opaque" => unreachable,
1534 .var_args_param => unreachable,1659 .var_args_param => unreachable,
1660 .generic_poison => unreachable,
15351661
1536 .@"struct" => {1662 .@"struct" => {
1537 const s = self.castTag(.@"struct").?.data;1663 const s = self.castTag(.@"struct").?.data;
...@@ -1698,6 +1824,7 @@ pub const Type = extern union {...@@ -1698,6 +1824,7 @@ pub const Type = extern union {
1698 .inferred_alloc_mut => unreachable,1824 .inferred_alloc_mut => unreachable,
1699 .@"opaque" => unreachable,1825 .@"opaque" => unreachable,
1700 .var_args_param => unreachable,1826 .var_args_param => unreachable,
1827 .generic_poison => unreachable,
17011828
1702 .@"struct" => {1829 .@"struct" => {
1703 @panic("TODO bitSize struct");1830 @panic("TODO bitSize struct");
...@@ -2408,14 +2535,41 @@ pub const Type = extern union {...@@ -2408,14 +2535,41 @@ pub const Type = extern union {
2408 };2535 };
2409 }2536 }
24102537
2411 /// Asserts the type is a function.2538 pub fn fnInfo(ty: Type) Payload.Function.Data {
2412 pub fn fnIsGeneric(self: Type) bool {2539 return switch (ty.tag()) {
2413 return switch (self.tag()) {2540 .fn_noreturn_no_args => .{
2414 .fn_noreturn_no_args => false,2541 .param_types = &.{},
2415 .fn_void_no_args => false,2542 .comptime_params = undefined,
2416 .fn_naked_noreturn_no_args => false,2543 .return_type = initTag(.noreturn),
2417 .fn_ccc_void_no_args => false,2544 .cc = .Unspecified,
2418 .function => self.castTag(.function).?.data.is_generic,2545 .is_var_args = false,
2546 .is_generic = false,
2547 },
2548 .fn_void_no_args => .{
2549 .param_types = &.{},
2550 .comptime_params = undefined,
2551 .return_type = initTag(.void),
2552 .cc = .Unspecified,
2553 .is_var_args = false,
2554 .is_generic = false,
2555 },
2556 .fn_naked_noreturn_no_args => .{
2557 .param_types = &.{},
2558 .comptime_params = undefined,
2559 .return_type = initTag(.noreturn),
2560 .cc = .Naked,
2561 .is_var_args = false,
2562 .is_generic = false,
2563 },
2564 .fn_ccc_void_no_args => .{
2565 .param_types = &.{},
2566 .comptime_params = undefined,
2567 .return_type = initTag(.void),
2568 .cc = .C,
2569 .is_var_args = false,
2570 .is_generic = false,
2571 },
2572 .function => ty.castTag(.function).?.data,
24192573
2420 else => unreachable,2574 else => unreachable,
2421 };2575 };
...@@ -2595,6 +2749,7 @@ pub const Type = extern union {...@@ -2595,6 +2749,7 @@ pub const Type = extern union {
25952749
2596 .inferred_alloc_const => unreachable,2750 .inferred_alloc_const => unreachable,
2597 .inferred_alloc_mut => unreachable,2751 .inferred_alloc_mut => unreachable,
2752 .generic_poison => unreachable,
2598 };2753 };
2599 }2754 }
26002755
...@@ -3008,6 +3163,7 @@ pub const Type = extern union {...@@ -3008,6 +3163,7 @@ pub const Type = extern union {
3008 single_const_pointer_to_comptime_int,3163 single_const_pointer_to_comptime_int,
3009 const_slice_u8,3164 const_slice_u8,
3010 anyerror_void_error_union,3165 anyerror_void_error_union,
3166 generic_poison,
3011 /// This is a special type for variadic parameters of a function call.3167 /// This is a special type for variadic parameters of a function call.
3012 /// Casts to it will validate that the type can be passed to a c calling convetion function.3168 /// Casts to it will validate that the type can be passed to a c calling convetion function.
3013 var_args_param,3169 var_args_param,
...@@ -3105,6 +3261,7 @@ pub const Type = extern union {...@@ -3105,6 +3261,7 @@ pub const Type = extern union {
3105 .single_const_pointer_to_comptime_int,3261 .single_const_pointer_to_comptime_int,
3106 .anyerror_void_error_union,3262 .anyerror_void_error_union,
3107 .const_slice_u8,3263 .const_slice_u8,
3264 .generic_poison,
3108 .inferred_alloc_const,3265 .inferred_alloc_const,
3109 .inferred_alloc_mut,3266 .inferred_alloc_mut,
3110 .var_args_param,3267 .var_args_param,
...@@ -3223,13 +3380,23 @@ pub const Type = extern union {...@@ -3223,13 +3380,23 @@ pub const Type = extern union {
3223 pub const base_tag = Tag.function;3380 pub const base_tag = Tag.function;
32243381
3225 base: Payload = Payload{ .tag = base_tag },3382 base: Payload = Payload{ .tag = base_tag },
3226 data: struct {3383 data: Data,
3384
3385 // TODO look into optimizing this memory to take fewer bytes
3386 pub const Data = struct {
3227 param_types: []Type,3387 param_types: []Type,
3388 comptime_params: [*]bool,
3228 return_type: Type,3389 return_type: Type,
3229 cc: std.builtin.CallingConvention,3390 cc: std.builtin.CallingConvention,
3230 is_var_args: bool,3391 is_var_args: bool,
3231 is_generic: bool,3392 is_generic: bool,
3232 },3393
3394 pub fn paramIsComptime(self: @This(), i: usize) bool {
3395 if (!self.is_generic) return false;
3396 assert(i < self.param_types.len);
3397 return self.comptime_params[i];
3398 }
3399 };
3233 };3400 };
32343401
3235 pub const ErrorSet = struct {3402 pub const ErrorSet = struct {
src/value.zig+89-111
...@@ -76,6 +76,8 @@ pub const Value = extern union {...@@ -76,6 +76,8 @@ pub const Value = extern union {
76 fn_ccc_void_no_args_type,76 fn_ccc_void_no_args_type,
77 single_const_pointer_to_comptime_int_type,77 single_const_pointer_to_comptime_int_type,
78 const_slice_u8_type,78 const_slice_u8_type,
79 anyerror_void_error_union_type,
80 generic_poison_type,
7981
80 undef,82 undef,
81 zero,83 zero,
...@@ -85,6 +87,7 @@ pub const Value = extern union {...@@ -85,6 +87,7 @@ pub const Value = extern union {
85 null_value,87 null_value,
86 bool_true,88 bool_true,
87 bool_false,89 bool_false,
90 generic_poison,
8891
89 abi_align_default,92 abi_align_default,
90 empty_struct_value,93 empty_struct_value,
...@@ -188,6 +191,8 @@ pub const Value = extern union {...@@ -188,6 +191,8 @@ pub const Value = extern union {
188 .single_const_pointer_to_comptime_int_type,191 .single_const_pointer_to_comptime_int_type,
189 .anyframe_type,192 .anyframe_type,
190 .const_slice_u8_type,193 .const_slice_u8_type,
194 .anyerror_void_error_union_type,
195 .generic_poison_type,
191 .enum_literal_type,196 .enum_literal_type,
192 .undef,197 .undef,
193 .zero,198 .zero,
...@@ -210,6 +215,7 @@ pub const Value = extern union {...@@ -210,6 +215,7 @@ pub const Value = extern union {
210 .call_options_type,215 .call_options_type,
211 .export_options_type,216 .export_options_type,
212 .extern_options_type,217 .extern_options_type,
218 .generic_poison,
213 => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),219 => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),
214220
215 .int_big_positive,221 .int_big_positive,
...@@ -366,6 +372,8 @@ pub const Value = extern union {...@@ -366,6 +372,8 @@ pub const Value = extern union {
366 .single_const_pointer_to_comptime_int_type,372 .single_const_pointer_to_comptime_int_type,
367 .anyframe_type,373 .anyframe_type,
368 .const_slice_u8_type,374 .const_slice_u8_type,
375 .anyerror_void_error_union_type,
376 .generic_poison_type,
369 .enum_literal_type,377 .enum_literal_type,
370 .undef,378 .undef,
371 .zero,379 .zero,
...@@ -388,6 +396,7 @@ pub const Value = extern union {...@@ -388,6 +396,7 @@ pub const Value = extern union {
388 .call_options_type,396 .call_options_type,
389 .export_options_type,397 .export_options_type,
390 .extern_options_type,398 .extern_options_type,
399 .generic_poison,
391 => unreachable,400 => unreachable,
392401
393 .ty => {402 .ty => {
...@@ -556,6 +565,9 @@ pub const Value = extern union {...@@ -556,6 +565,9 @@ pub const Value = extern union {
556 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),565 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
557 .anyframe_type => return out_stream.writeAll("anyframe"),566 .anyframe_type => return out_stream.writeAll("anyframe"),
558 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),567 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
568 .anyerror_void_error_union_type => return out_stream.writeAll("anyerror!void"),
569 .generic_poison_type => return out_stream.writeAll("(generic poison type)"),
570 .generic_poison => return out_stream.writeAll("(generic poison)"),
559 .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),571 .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
560 .manyptr_u8_type => return out_stream.writeAll("[*]u8"),572 .manyptr_u8_type => return out_stream.writeAll("[*]u8"),
561 .manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"),573 .manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"),
...@@ -709,6 +721,8 @@ pub const Value = extern union {...@@ -709,6 +721,8 @@ pub const Value = extern union {
709 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),721 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
710 .anyframe_type => Type.initTag(.@"anyframe"),722 .anyframe_type => Type.initTag(.@"anyframe"),
711 .const_slice_u8_type => Type.initTag(.const_slice_u8),723 .const_slice_u8_type => Type.initTag(.const_slice_u8),
724 .anyerror_void_error_union_type => Type.initTag(.anyerror_void_error_union),
725 .generic_poison_type => Type.initTag(.generic_poison),
712 .enum_literal_type => Type.initTag(.enum_literal),726 .enum_literal_type => Type.initTag(.enum_literal),
713 .manyptr_u8_type => Type.initTag(.manyptr_u8),727 .manyptr_u8_type => Type.initTag(.manyptr_u8),
714 .manyptr_const_u8_type => Type.initTag(.manyptr_const_u8),728 .manyptr_const_u8_type => Type.initTag(.manyptr_const_u8),
...@@ -732,46 +746,7 @@ pub const Value = extern union {...@@ -732,46 +746,7 @@ pub const Value = extern union {
732 return Type.initPayload(&buffer.base);746 return Type.initPayload(&buffer.base);
733 },747 },
734748
735 .undef,749 else => unreachable,
736 .zero,
737 .one,
738 .void_value,
739 .unreachable_value,
740 .empty_array,
741 .bool_true,
742 .bool_false,
743 .null_value,
744 .int_u64,
745 .int_i64,
746 .int_big_positive,
747 .int_big_negative,
748 .function,
749 .extern_fn,
750 .variable,
751 .decl_ref,
752 .decl_ref_mut,
753 .elem_ptr,
754 .field_ptr,
755 .bytes,
756 .repeated,
757 .array,
758 .slice,
759 .float_16,
760 .float_32,
761 .float_64,
762 .float_128,
763 .enum_literal,
764 .enum_field_index,
765 .@"error",
766 .error_union,
767 .empty_struct_value,
768 .@"struct",
769 .@"union",
770 .inferred_alloc,
771 .inferred_alloc_comptime,
772 .abi_align_default,
773 .eu_payload_ptr,
774 => unreachable,
775 };750 };
776 }751 }
777752
...@@ -1142,12 +1117,82 @@ pub const Value = extern union {...@@ -1142,12 +1117,82 @@ pub const Value = extern union {
1142 return order(a, b).compare(.eq);1117 return order(a, b).compare(.eq);
1143 }1118 }
11441119
1120 pub fn hash(val: Value, ty: Type, hasher: *std.hash.Wyhash) void {
1121 switch (ty.zigTypeTag()) {
1122 .BoundFn => unreachable, // TODO remove this from the language
1123
1124 .Void,
1125 .NoReturn,
1126 .Undefined,
1127 .Null,
1128 => {},
1129
1130 .Type => {
1131 var buf: ToTypeBuffer = undefined;
1132 return val.toType(&buf).hashWithHasher(hasher);
1133 },
1134 .Bool => {
1135 std.hash.autoHash(hasher, val.toBool());
1136 },
1137 .Int, .ComptimeInt => {
1138 var space: BigIntSpace = undefined;
1139 const big = val.toBigInt(&space);
1140 std.hash.autoHash(hasher, big.positive);
1141 for (big.limbs) |limb| {
1142 std.hash.autoHash(hasher, limb);
1143 }
1144 },
1145 .Float, .ComptimeFloat => {
1146 @panic("TODO implement hashing float values");
1147 },
1148 .Pointer => {
1149 @panic("TODO implement hashing pointer values");
1150 },
1151 .Array, .Vector => {
1152 @panic("TODO implement hashing array/vector values");
1153 },
1154 .Struct => {
1155 @panic("TODO implement hashing struct values");
1156 },
1157 .Optional => {
1158 @panic("TODO implement hashing optional values");
1159 },
1160 .ErrorUnion => {
1161 @panic("TODO implement hashing error union values");
1162 },
1163 .ErrorSet => {
1164 @panic("TODO implement hashing error set values");
1165 },
1166 .Enum => {
1167 @panic("TODO implement hashing enum values");
1168 },
1169 .Union => {
1170 @panic("TODO implement hashing union values");
1171 },
1172 .Fn => {
1173 @panic("TODO implement hashing function values");
1174 },
1175 .Opaque => {
1176 @panic("TODO implement hashing opaque values");
1177 },
1178 .Frame => {
1179 @panic("TODO implement hashing frame values");
1180 },
1181 .AnyFrame => {
1182 @panic("TODO implement hashing anyframe values");
1183 },
1184 .EnumLiteral => {
1185 @panic("TODO implement hashing enum literal values");
1186 },
1187 }
1188 }
1189
1145 pub const ArrayHashContext = struct {1190 pub const ArrayHashContext = struct {
1146 ty: Type,1191 ty: Type,
11471192
1148 pub fn hash(self: @This(), v: Value) u32 {1193 pub fn hash(self: @This(), val: Value) u32 {
1149 const other_context: HashContext = .{ .ty = self.ty };1194 const other_context: HashContext = .{ .ty = self.ty };
1150 return @truncate(u32, other_context.hash(v));1195 return @truncate(u32, other_context.hash(val));
1151 }1196 }
1152 pub fn eql(self: @This(), a: Value, b: Value) bool {1197 pub fn eql(self: @This(), a: Value, b: Value) bool {
1153 return a.eql(b, self.ty);1198 return a.eql(b, self.ty);
...@@ -1157,76 +1202,9 @@ pub const Value = extern union {...@@ -1157,76 +1202,9 @@ pub const Value = extern union {
1157 pub const HashContext = struct {1202 pub const HashContext = struct {
1158 ty: Type,1203 ty: Type,
11591204
1160 pub fn hash(self: @This(), v: Value) u64 {1205 pub fn hash(self: @This(), val: Value) u64 {
1161 var hasher = std.hash.Wyhash.init(0);1206 var hasher = std.hash.Wyhash.init(0);
11621207 val.hash(self.ty, &hasher);
1163 switch (self.ty.zigTypeTag()) {
1164 .BoundFn => unreachable, // TODO remove this from the language
1165
1166 .Void,
1167 .NoReturn,
1168 .Undefined,
1169 .Null,
1170 => {},
1171
1172 .Type => {
1173 var buf: ToTypeBuffer = undefined;
1174 return v.toType(&buf).hash();
1175 },
1176 .Bool => {
1177 std.hash.autoHash(&hasher, v.toBool());
1178 },
1179 .Int, .ComptimeInt => {
1180 var space: BigIntSpace = undefined;
1181 const big = v.toBigInt(&space);
1182 std.hash.autoHash(&hasher, big.positive);
1183 for (big.limbs) |limb| {
1184 std.hash.autoHash(&hasher, limb);
1185 }
1186 },
1187 .Float, .ComptimeFloat => {
1188 @panic("TODO implement hashing float values");
1189 },
1190 .Pointer => {
1191 @panic("TODO implement hashing pointer values");
1192 },
1193 .Array, .Vector => {
1194 @panic("TODO implement hashing array/vector values");
1195 },
1196 .Struct => {
1197 @panic("TODO implement hashing struct values");
1198 },
1199 .Optional => {
1200 @panic("TODO implement hashing optional values");
1201 },
1202 .ErrorUnion => {
1203 @panic("TODO implement hashing error union values");
1204 },
1205 .ErrorSet => {
1206 @panic("TODO implement hashing error set values");
1207 },
1208 .Enum => {
1209 @panic("TODO implement hashing enum values");
1210 },
1211 .Union => {
1212 @panic("TODO implement hashing union values");
1213 },
1214 .Fn => {
1215 @panic("TODO implement hashing function values");
1216 },
1217 .Opaque => {
1218 @panic("TODO implement hashing opaque values");
1219 },
1220 .Frame => {
1221 @panic("TODO implement hashing frame values");
1222 },
1223 .AnyFrame => {
1224 @panic("TODO implement hashing anyframe values");
1225 },
1226 .EnumLiteral => {
1227 @panic("TODO implement hashing enum literal values");
1228 },
1229 }
1230 return hasher.final();1208 return hasher.final();
1231 }1209 }
12321210
test/behavior.zig+2-1
...@@ -4,6 +4,7 @@ test {...@@ -4,6 +4,7 @@ test {
4 // Tests that pass for both.4 // Tests that pass for both.
5 _ = @import("behavior/bool.zig");5 _ = @import("behavior/bool.zig");
6 _ = @import("behavior/basic.zig");6 _ = @import("behavior/basic.zig");
7 _ = @import("behavior/generics.zig");
78
8 if (!builtin.zig_is_stage2) {9 if (!builtin.zig_is_stage2) {
9 // Tests that only pass for stage1.10 // Tests that only pass for stage1.
...@@ -94,7 +95,7 @@ test {...@@ -94,7 +95,7 @@ test {
94 _ = @import("behavior/fn_in_struct_in_comptime.zig");95 _ = @import("behavior/fn_in_struct_in_comptime.zig");
95 _ = @import("behavior/fn_delegation.zig");96 _ = @import("behavior/fn_delegation.zig");
96 _ = @import("behavior/for.zig");97 _ = @import("behavior/for.zig");
97 _ = @import("behavior/generics.zig");98 _ = @import("behavior/generics_stage1.zig");
98 _ = @import("behavior/hasdecl.zig");99 _ = @import("behavior/hasdecl.zig");
99 _ = @import("behavior/hasfield.zig");100 _ = @import("behavior/hasfield.zig");
100 _ = @import("behavior/if.zig");101 _ = @import("behavior/if.zig");
test/behavior/basic.zig+79
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const mem = std.mem;
2const expect = std.testing.expect;3const expect = std.testing.expect;
34
4// normal comment5// normal comment
...@@ -83,3 +84,81 @@ test "unicode escape in character literal" {...@@ -83,3 +84,81 @@ test "unicode escape in character literal" {
83test "unicode character in character literal" {84test "unicode character in character literal" {
84 try expect('💩' == 128169);85 try expect('💩' == 128169);
85}86}
87
88fn first4KeysOfHomeRow() []const u8 {
89 return "aoeu";
90}
91
92test "return string from function" {
93 try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
94}
95
96test "hex escape" {
97 try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
98}
99
100test "multiline string" {
101 const s1 =
102 \\one
103 \\two)
104 \\three
105 ;
106 const s2 = "one\ntwo)\nthree";
107 try expect(mem.eql(u8, s1, s2));
108}
109
110test "multiline string comments at start" {
111 const s1 =
112 //\\one
113 \\two)
114 \\three
115 ;
116 const s2 = "two)\nthree";
117 try expect(mem.eql(u8, s1, s2));
118}
119
120test "multiline string comments at end" {
121 const s1 =
122 \\one
123 \\two)
124 //\\three
125 ;
126 const s2 = "one\ntwo)";
127 try expect(mem.eql(u8, s1, s2));
128}
129
130test "multiline string comments in middle" {
131 const s1 =
132 \\one
133 //\\two)
134 \\three
135 ;
136 const s2 = "one\nthree";
137 try expect(mem.eql(u8, s1, s2));
138}
139
140test "multiline string comments at multiple places" {
141 const s1 =
142 \\one
143 //\\two
144 \\three
145 //\\four
146 \\five
147 ;
148 const s2 = "one\nthree\nfive";
149 try expect(mem.eql(u8, s1, s2));
150}
151
152test "call result of if else expression" {
153 try expect(mem.eql(u8, f2(true), "a"));
154 try expect(mem.eql(u8, f2(false), "b"));
155}
156fn f2(x: bool) []const u8 {
157 return (if (x) fA else fB)();
158}
159fn fA() []const u8 {
160 return "a";
161}
162fn fB() []const u8 {
163 return "b";
164}
test/behavior/generics.zig+34-131
...@@ -1,16 +1,43 @@...@@ -1,16 +1,43 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const testing = std.testing;3const testing = std.testing;
3const expect = testing.expect;4const expect = testing.expect;
4const expectEqual = testing.expectEqual;5const expectEqual = testing.expectEqual;
56
7test "one param, explicit comptime" {
8 var x: usize = 0;
9 x += checkSize(i32);
10 x += checkSize(bool);
11 x += checkSize(bool);
12 try expect(x == 6);
13}
14
15fn checkSize(comptime T: type) usize {
16 return @sizeOf(T);
17}
18
6test "simple generic fn" {19test "simple generic fn" {
7 try expect(max(i32, 3, -1) == 3);20 try expect(max(i32, 3, -1) == 3);
8 try expect(max(f32, 0.123, 0.456) == 0.456);21 try expect(max(u8, 1, 100) == 100);
22 if (!builtin.zig_is_stage2) {
23 // TODO: stage2 is incorrectly emitting the following:
24 // error: cast of value 1.23e-01 to type 'f32' loses information
25 try expect(max(f32, 0.123, 0.456) == 0.456);
26 }
9 try expect(add(2, 3) == 5);27 try expect(add(2, 3) == 5);
10}28}
1129
12fn max(comptime T: type, a: T, b: T) T {30fn max(comptime T: type, a: T, b: T) T {
13 return if (a > b) a else b;31 if (!builtin.zig_is_stage2) {
32 // TODO: stage2 is incorrectly emitting AIR that allocates a result
33 // value, stores to it, but then returns void instead of the result.
34 return if (a > b) a else b;
35 }
36 if (a > b) {
37 return a;
38 } else {
39 return b;
40 }
14}41}
1542
16fn add(comptime a: i32, b: i32) i32 {43fn add(comptime a: i32, b: i32) i32 {
...@@ -37,133 +64,9 @@ fn sameButWithFloats(a: f64, b: f64) f64 {...@@ -37,133 +64,9 @@ fn sameButWithFloats(a: f64, b: f64) f64 {
37test "fn with comptime args" {64test "fn with comptime args" {
38 try expect(gimmeTheBigOne(1234, 5678) == 5678);65 try expect(gimmeTheBigOne(1234, 5678) == 5678);
39 try expect(shouldCallSameInstance(34, 12) == 34);66 try expect(shouldCallSameInstance(34, 12) == 34);
40 try expect(sameButWithFloats(0.43, 0.49) == 0.49);67 if (!builtin.zig_is_stage2) {
41}68 // TODO: stage2 llvm backend needs to use fcmp instead of icmp
4269 // probably AIR should just have different instructions for floats.
43test "var params" {70 try expect(sameButWithFloats(0.43, 0.49) == 0.49);
44 try expect(max_i32(12, 34) == 34);71 }
45 try expect(max_f64(1.2, 3.4) == 3.4);
46}
47
48test {
49 comptime try expect(max_i32(12, 34) == 34);
50 comptime try expect(max_f64(1.2, 3.4) == 3.4);
51}
52
53fn max_var(a: anytype, b: anytype) @TypeOf(a + b) {
54 return if (a > b) a else b;
55}
56
57fn max_i32(a: i32, b: i32) i32 {
58 return max_var(a, b);
59}
60
61fn max_f64(a: f64, b: f64) f64 {
62 return max_var(a, b);
63}
64
65pub fn List(comptime T: type) type {
66 return SmallList(T, 8);
67}
68
69pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) type {
70 return struct {
71 items: []T,
72 length: usize,
73 prealloc_items: [STATIC_SIZE]T,
74 };
75}
76
77test "function with return type type" {
78 var list: List(i32) = undefined;
79 var list2: List(i32) = undefined;
80 list.length = 10;
81 list2.length = 10;
82 try expect(list.prealloc_items.len == 8);
83 try expect(list2.prealloc_items.len == 8);
84}
85
86test "generic struct" {
87 var a1 = GenNode(i32){
88 .value = 13,
89 .next = null,
90 };
91 var b1 = GenNode(bool){
92 .value = true,
93 .next = null,
94 };
95 try expect(a1.value == 13);
96 try expect(a1.value == a1.getVal());
97 try expect(b1.getVal());
98}
99fn GenNode(comptime T: type) type {
100 return struct {
101 value: T,
102 next: ?*GenNode(T),
103 fn getVal(n: *const GenNode(T)) T {
104 return n.value;
105 }
106 };
107}
108
109test "const decls in struct" {
110 try expect(GenericDataThing(3).count_plus_one == 4);
111}
112fn GenericDataThing(comptime count: isize) type {
113 return struct {
114 const count_plus_one = count + 1;
115 };
116}
117
118test "use generic param in generic param" {
119 try expect(aGenericFn(i32, 3, 4) == 7);
120}
121fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
122 return a + b;
123}
124
125test "generic fn with implicit cast" {
126 try expect(getFirstByte(u8, &[_]u8{13}) == 13);
127 try expect(getFirstByte(u16, &[_]u16{
128 0,
129 13,
130 }) == 0);
131}
132fn getByte(ptr: ?*const u8) u8 {
133 return ptr.?.*;
134}
135fn getFirstByte(comptime T: type, mem: []const T) u8 {
136 return getByte(@ptrCast(*const u8, &mem[0]));
137}
138
139const foos = [_]fn (anytype) bool{
140 foo1,
141 foo2,
142};
143
144fn foo1(arg: anytype) bool {
145 return arg;
146}
147fn foo2(arg: anytype) bool {
148 return !arg;
149}
150
151test "array of generic fns" {
152 try expect(foos[0](true));
153 try expect(!foos[1](true));
154}
155
156test "generic fn keeps non-generic parameter types" {
157 const A = 128;
158
159 const S = struct {
160 fn f(comptime T: type, s: []T) !void {
161 try expect(A != @typeInfo(@TypeOf(s)).Pointer.alignment);
162 }
163 };
164
165 // The compiler monomorphizes `S.f` for `T=u8` on its first use, check that
166 // `x` type not affect `s` parameter type.
167 var x: [16]u8 align(A) = undefined;
168 try S.f(u8, &x);
169}72}
test/behavior/generics_stage1.zig created+132
...@@ -0,0 +1,132 @@
1const std = @import("std");
2const testing = std.testing;
3const expect = testing.expect;
4const expectEqual = testing.expectEqual;
5
6test "anytype params" {
7 try expect(max_i32(12, 34) == 34);
8 try expect(max_f64(1.2, 3.4) == 3.4);
9}
10
11test {
12 comptime try expect(max_i32(12, 34) == 34);
13 comptime try expect(max_f64(1.2, 3.4) == 3.4);
14}
15
16fn max_anytype(a: anytype, b: anytype) @TypeOf(a + b) {
17 return if (a > b) a else b;
18}
19
20fn max_i32(a: i32, b: i32) i32 {
21 return max_anytype(a, b);
22}
23
24fn max_f64(a: f64, b: f64) f64 {
25 return max_anytype(a, b);
26}
27
28pub fn List(comptime T: type) type {
29 return SmallList(T, 8);
30}
31
32pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) type {
33 return struct {
34 items: []T,
35 length: usize,
36 prealloc_items: [STATIC_SIZE]T,
37 };
38}
39
40test "function with return type type" {
41 var list: List(i32) = undefined;
42 var list2: List(i32) = undefined;
43 list.length = 10;
44 list2.length = 10;
45 try expect(list.prealloc_items.len == 8);
46 try expect(list2.prealloc_items.len == 8);
47}
48
49test "generic struct" {
50 var a1 = GenNode(i32){
51 .value = 13,
52 .next = null,
53 };
54 var b1 = GenNode(bool){
55 .value = true,
56 .next = null,
57 };
58 try expect(a1.value == 13);
59 try expect(a1.value == a1.getVal());
60 try expect(b1.getVal());
61}
62fn GenNode(comptime T: type) type {
63 return struct {
64 value: T,
65 next: ?*GenNode(T),
66 fn getVal(n: *const GenNode(T)) T {
67 return n.value;
68 }
69 };
70}
71
72test "const decls in struct" {
73 try expect(GenericDataThing(3).count_plus_one == 4);
74}
75fn GenericDataThing(comptime count: isize) type {
76 return struct {
77 const count_plus_one = count + 1;
78 };
79}
80
81test "use generic param in generic param" {
82 try expect(aGenericFn(i32, 3, 4) == 7);
83}
84fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
85 return a + b;
86}
87
88test "generic fn with implicit cast" {
89 try expect(getFirstByte(u8, &[_]u8{13}) == 13);
90 try expect(getFirstByte(u16, &[_]u16{
91 0,
92 13,
93 }) == 0);
94}
95fn getByte(ptr: ?*const u8) u8 {
96 return ptr.?.*;
97}
98fn getFirstByte(comptime T: type, mem: []const T) u8 {
99 return getByte(@ptrCast(*const u8, &mem[0]));
100}
101
102const foos = [_]fn (anytype) bool{
103 foo1,
104 foo2,
105};
106
107fn foo1(arg: anytype) bool {
108 return arg;
109}
110fn foo2(arg: anytype) bool {
111 return !arg;
112}
113
114test "array of generic fns" {
115 try expect(foos[0](true));
116 try expect(!foos[1](true));
117}
118
119test "generic fn keeps non-generic parameter types" {
120 const A = 128;
121
122 const S = struct {
123 fn f(comptime T: type, s: []T) !void {
124 try expect(A != @typeInfo(@TypeOf(s)).Pointer.alignment);
125 }
126 };
127
128 // The compiler monomorphizes `S.f` for `T=u8` on its first use, check that
129 // `x` type not affect `s` parameter type.
130 var x: [16]u8 align(A) = undefined;
131 try S.f(u8, &x);
132}
test/behavior/misc.zig+1-79
...@@ -5,14 +5,6 @@ const expectEqualStrings = std.testing.expectEqualStrings;...@@ -5,14 +5,6 @@ const expectEqualStrings = std.testing.expectEqualStrings;
5const mem = std.mem;5const mem = std.mem;
6const builtin = @import("builtin");6const builtin = @import("builtin");
77
8fn first4KeysOfHomeRow() []const u8 {
9 return "aoeu";
10}
11
12test "return string from function" {
13 try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
14}
15
16test "memcpy and memset intrinsics" {8test "memcpy and memset intrinsics" {
17 var foo: [20]u8 = undefined;9 var foo: [20]u8 = undefined;
18 var bar: [20]u8 = undefined;10 var bar: [20]u8 = undefined;
...@@ -48,10 +40,6 @@ test "constant equal function pointers" {...@@ -48,10 +40,6 @@ test "constant equal function pointers" {
4840
49fn emptyFn() void {}41fn emptyFn() void {}
5042
51test "hex escape" {
52 try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
53}
54
55test "string concatenation" {43test "string concatenation" {
56 try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));44 try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
57}45}
...@@ -70,59 +58,7 @@ test "string escapes" {...@@ -70,59 +58,7 @@ test "string escapes" {
70 try expectEqualStrings("\u{1234}\u{069}\u{1}", "\xe1\x88\xb4\x69\x01");58 try expectEqualStrings("\u{1234}\u{069}\u{1}", "\xe1\x88\xb4\x69\x01");
71}59}
7260
73test "multiline string" {61test "multiline string literal is null terminated" {
74 const s1 =
75 \\one
76 \\two)
77 \\three
78 ;
79 const s2 = "one\ntwo)\nthree";
80 try expect(mem.eql(u8, s1, s2));
81}
82
83test "multiline string comments at start" {
84 const s1 =
85 //\\one
86 \\two)
87 \\three
88 ;
89 const s2 = "two)\nthree";
90 try expect(mem.eql(u8, s1, s2));
91}
92
93test "multiline string comments at end" {
94 const s1 =
95 \\one
96 \\two)
97 //\\three
98 ;
99 const s2 = "one\ntwo)";
100 try expect(mem.eql(u8, s1, s2));
101}
102
103test "multiline string comments in middle" {
104 const s1 =
105 \\one
106 //\\two)
107 \\three
108 ;
109 const s2 = "one\nthree";
110 try expect(mem.eql(u8, s1, s2));
111}
112
113test "multiline string comments at multiple places" {
114 const s1 =
115 \\one
116 //\\two
117 \\three
118 //\\four
119 \\five
120 ;
121 const s2 = "one\nthree\nfive";
122 try expect(mem.eql(u8, s1, s2));
123}
124
125test "multiline C string" {
126 const s1 =62 const s1 =
127 \\one63 \\one
128 \\two)64 \\two)
...@@ -177,20 +113,6 @@ fn outer() i64 {...@@ -177,20 +113,6 @@ fn outer() i64 {
177 return inner();113 return inner();
178}114}
179115
180test "call result of if else expression" {
181 try expect(mem.eql(u8, f2(true), "a"));
182 try expect(mem.eql(u8, f2(false), "b"));
183}
184fn f2(x: bool) []const u8 {
185 return (if (x) fA else fB)();
186}
187fn fA() []const u8 {
188 return "a";
189}
190fn fB() []const u8 {
191 return "b";
192}
193
194test "constant enum initialization with differing sizes" {116test "constant enum initialization with differing sizes" {
195 try test3_1(test3_foo);117 try test3_1(test3_foo);
196 try test3_2(test3_bar);118 try test3_2(test3_bar);
test/cases.zig+1-1
...@@ -1572,7 +1572,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1572,7 +1572,7 @@ pub fn addCases(ctx: *TestContext) !void {
1572 \\ const x = asm volatile ("syscall"1572 \\ const x = asm volatile ("syscall"
1573 \\ : [o] "{rax}" (-> number)1573 \\ : [o] "{rax}" (-> number)
1574 \\ : [number] "{rax}" (231),1574 \\ : [number] "{rax}" (231),
1575 \\ [arg1] "{rdi}" (code)1575 \\ [arg1] "{rdi}" (60)
1576 \\ : "rcx", "r11", "memory"1576 \\ : "rcx", "r11", "memory"
1577 \\ );1577 \\ );
1578 \\ _ = x;1578 \\ _ = x;