authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-04 21:11:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-04 21:11:31-07:00
logd4468affb751668e156230c32b29c84684825b4f
tree3394fc54a11c8c6c01783d7e5ee753c87ce0feda
parent382d201781eb57d9e950ad07ce814adc5a68b329

stage2 generics improvements: anytype and param type exprs

AstGen result locations now have a `coerced_ty` tag which is the same as `ty` except it assumes that Sema will do a coercion, so it does not redundantly add an `as` instruction into the ZIR code. This results in cleaner ZIR and about a 14% reduction of ZIR bytes. param and param_comptime ZIR instructions now have a block body for their type expressions. This allows Sema to skip evaluation of the block in the case that the parameter is comptime-provided. It also allows a new mechanism to function: when evaluating type expressions of generic functions, if it would depend on another parameter, it returns `error.GenericPoison` which bubbles up and then is caught by the param/param_comptime instruction and then handled. This allows parameters to be evaluated independently so that the type info for functions which have comptime or anytype parameters will still have types populated for parameters that do not depend on values of previous parameters (because evaluation of their param blocks will return successfully instead of `error.GenericPoison`). It also makes iteration over the block that contains function parameters slightly more efficient since it now only contains the param instructions. Finally, it fixes the case where a generic function type expression contains a function prototype. Formerly, this situation would cause shared state to clobber each other; now it is in a proper tree structure so that can't happen. This fix also required adding a field to Sema `comptime_args_fn_inst` to make sure that the `comptime_args` field passed into Sema is applied to the correct `func` instruction. Source location for `node_offset_asm_ret_ty` is fixed; it was pointing at the asm output name rather than the return type as intended. Generic function instantiation is fixed, notably with respect to parameter type expressions that depend on previous parameters, and with respect to types which must be always comptime-known. This involves passing all the comptime arguments at a callsite of a generic function, and allowing the generic function semantic analysis to coerce the values to the proper types (since it has access to the evaluated parameter type expressions) and then decide based on the type whether the parameter is runtime known or not. In the case of explicitly marked `comptime` parameters, there is a check at the semantic analysis of the `call` instruction. Semantic analysis of `call` instructions does type coercion on the arguments, which is needed both for generic functions and to make up for using `coerced_ty` result locations (mentioned above). Tasks left in this branch: * Implement the memoization table. * Add test coverage. * Improve error reporting and source locations for compile errors.

10 files changed, 519 insertions(+), 247 deletions(-)

BRANCH_TODO deleted-4
...@@ -1,4 +0,0 @@
1* memoize the instantiation in a table
2* expressions that depend on comptime stuff need a poison value to use for
3 types when generating the generic function type
4* comptime anytype
src/AstGen.zig+45-26
...@@ -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 },
...@@ -260,13 +263,14 @@ pub const ResultLoc = union(enum) {...@@ -260,13 +263,14 @@ pub const ResultLoc = union(enum) {
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 };
262pub const type_rl: ResultLoc = .{ .ty = .type_type };265pub const type_rl: ResultLoc = .{ .ty = .type_type };
266pub const coerced_type_rl: ResultLoc = .{ .coerced_ty = .type_type };
263267
264fn 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 {
265 const prev_force_comptime = gz.force_comptime;269 const prev_force_comptime = gz.force_comptime;
266 gz.force_comptime = true;270 gz.force_comptime = true;
267 defer gz.force_comptime = prev_force_comptime;271 defer gz.force_comptime = prev_force_comptime;
268272
269 return expr(gz, scope, .{ .ty = .type_type }, type_node);273 return expr(gz, scope, coerced_type_rl, type_node);
270}274}
271275
272/// 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`.
...@@ -1079,16 +1083,19 @@ fn fnProtoExpr(...@@ -1079,16 +1083,19 @@ fn fnProtoExpr(
1079 .param_anytype;1083 .param_anytype;
1080 _ = try gz.addStrTok(tag, param_name, name_token);1084 _ = try gz.addStrTok(tag, param_name, name_token);
1081 } else {1085 } else {
1086 const gpa = astgen.gpa;
1082 const param_type_node = param.type_expr;1087 const param_type_node = param.type_expr;
1083 assert(param_type_node != 0);1088 assert(param_type_node != 0);
1084 const param_type = try expr(gz, scope, type_rl, param_type_node);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);
1085 const main_tokens = tree.nodes.items(.main_token);1094 const main_tokens = tree.nodes.items(.main_token);
1086 const name_token = param.name_token orelse main_tokens[param_type_node];1095 const name_token = param.name_token orelse main_tokens[param_type_node];
1087 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;1096 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
1088 _ = try gz.addPlTok(tag, name_token, Zir.Inst.Param{1097 const param_inst = try gz.addParam(tag, name_token, param_name, param_gz.instructions.items);
1089 .name = param_name,1098 assert(param_inst_expected == param_inst);
1090 .ty = param_type,
1091 });
1092 }1099 }
1093 }1100 }
1094 break :is_var_args false;1101 break :is_var_args false;
...@@ -1219,7 +1226,7 @@ fn arrayInitExpr(...@@ -1219,7 +1226,7 @@ fn arrayInitExpr(
1219 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);1226 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
1220 }1227 }
1221 },1228 },
1222 .ty => |ty_inst| {1229 .ty, .coerced_ty => |ty_inst| {
1223 if (types.array != .none) {1230 if (types.array != .none) {
1224 const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);1231 const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);
1225 return rvalue(gz, rl, result, node);1232 return rvalue(gz, rl, result, node);
...@@ -1388,7 +1395,7 @@ fn structInitExpr(...@@ -1388,7 +1395,7 @@ fn structInitExpr(
1388 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon);1395 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon);
1389 }1396 }
1390 },1397 },
1391 .ty => |ty_inst| {1398 .ty, .coerced_ty => |ty_inst| {
1392 if (struct_init.ast.type_expr == 0) {1399 if (struct_init.ast.type_expr == 0) {
1393 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);1400 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
1394 }1401 }
...@@ -2617,7 +2624,7 @@ fn assignOp(...@@ -2617,7 +2624,7 @@ fn assignOp(
2617 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);2624 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
2618 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);2625 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);
2619 const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node);2626 const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node);
2620 const rhs = try expr(gz, scope, .{ .ty = lhs_type }, node_datas[infix_node].rhs);2627 const rhs = try expr(gz, scope, .{ .coerced_ty = lhs_type }, node_datas[infix_node].rhs);
26212628
2622 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{2629 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{
2623 .lhs = lhs,2630 .lhs = lhs,
...@@ -2953,14 +2960,18 @@ fn fnDecl(...@@ -2953,14 +2960,18 @@ fn fnDecl(
2953 } else param: {2960 } else param: {
2954 const param_type_node = param.type_expr;2961 const param_type_node = param.type_expr;
2955 assert(param_type_node != 0);2962 assert(param_type_node != 0);
2956 const param_type = try expr(&decl_gz, params_scope, type_rl, param_type_node);2963 var param_gz = decl_gz.makeSubBlock(scope);
2964 defer param_gz.instructions.deinit(gpa);
2965 const param_type = try expr(&param_gz, params_scope, coerced_type_rl, param_type_node);
2966 const param_inst_expected = @intCast(u32, astgen.instructions.len + 1);
2967 _ = try param_gz.addBreak(.break_inline, param_inst_expected, param_type);
2968
2957 const main_tokens = tree.nodes.items(.main_token);2969 const main_tokens = tree.nodes.items(.main_token);
2958 const name_token = param.name_token orelse main_tokens[param_type_node];2970 const name_token = param.name_token orelse main_tokens[param_type_node];
2959 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;2971 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
2960 break :param try decl_gz.addPlTok(tag, name_token, Zir.Inst.Param{2972 const param_inst = try decl_gz.addParam(tag, name_token, param_name, param_gz.instructions.items);
2961 .name = param_name,2973 assert(param_inst_expected == param_inst);
2962 .ty = param_type,2974 break :param indexToRef(param_inst);
2963 });
2964 };2975 };
29652976
2966 if (param_name == 0) continue;2977 if (param_name == 0) continue;
...@@ -6758,7 +6769,7 @@ fn as(...@@ -6758,7 +6769,7 @@ fn as(
6758) InnerError!Zir.Inst.Ref {6769) InnerError!Zir.Inst.Ref {
6759 const dest_type = try typeExpr(gz, scope, lhs);6770 const dest_type = try typeExpr(gz, scope, lhs);
6760 switch (rl) {6771 switch (rl) {
6761 .none, .none_or_ref, .discard, .ref, .ty => {6772 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty => {
6762 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);6773 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);
6763 return rvalue(gz, rl, result, node);6774 return rvalue(gz, rl, result, node);
6764 },6775 },
...@@ -6781,7 +6792,7 @@ fn unionInit(...@@ -6781,7 +6792,7 @@ fn unionInit(
6781 const union_type = try typeExpr(gz, scope, params[0]);6792 const union_type = try typeExpr(gz, scope, params[0]);
6782 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]);
6783 switch (rl) {6794 switch (rl) {
6784 .none, .none_or_ref, .discard, .ref, .ty, .inferred_ptr => {6795 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => {
6785 _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{6796 _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{
6786 .container_type = union_type,6797 .container_type = union_type,
6787 .field_name = field_name,6798 .field_name = field_name,
...@@ -6867,7 +6878,7 @@ fn bitCast(...@@ -6867,7 +6878,7 @@ fn bitCast(
6867 const astgen = gz.astgen;6878 const astgen = gz.astgen;
6868 const dest_type = try typeExpr(gz, scope, lhs);6879 const dest_type = try typeExpr(gz, scope, lhs);
6869 switch (rl) {6880 switch (rl) {
6870 .none, .none_or_ref, .discard, .ty => {6881 .none, .none_or_ref, .discard, .ty, .coerced_ty => {
6871 const operand = try expr(gz, scope, .none, rhs);6882 const operand = try expr(gz, scope, .none, rhs);
6872 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{6883 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{
6873 .lhs = dest_type,6884 .lhs = dest_type,
...@@ -7677,7 +7688,7 @@ fn callExpr(...@@ -7677,7 +7688,7 @@ fn callExpr(
7677 .param_index = @intCast(u32, i),7688 .param_index = @intCast(u32, i),
7678 } },7689 } },
7679 });7690 });
7680 args[i] = try expr(gz, scope, .{ .ty = param_type }, param_node);7691 args[i] = try expr(gz, scope, .{ .coerced_ty = param_type }, param_node);
7681 }7692 }
76827693
7683 const modifier: std.builtin.CallOptions.Modifier = blk: {7694 const modifier: std.builtin.CallOptions.Modifier = blk: {
...@@ -8370,7 +8381,7 @@ fn rvalue(...@@ -8370,7 +8381,7 @@ fn rvalue(
8370 src_node: ast.Node.Index,8381 src_node: ast.Node.Index,
8371) InnerError!Zir.Inst.Ref {8382) InnerError!Zir.Inst.Ref {
8372 switch (rl) {8383 switch (rl) {
8373 .none, .none_or_ref => return result,8384 .none, .none_or_ref, .coerced_ty => return result,
8374 .discard => {8385 .discard => {
8375 // Emit a compile error for discarding error values.8386 // Emit a compile error for discarding error values.
8376 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);8387 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
...@@ -9042,7 +9053,7 @@ const GenZir = struct {...@@ -9042,7 +9053,7 @@ const GenZir = struct {
9042 // 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,
9043 // 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.
9044 switch (parent_rl) {9055 switch (parent_rl) {
9045 .ty => |ty_inst| {9056 .ty, .coerced_ty => |ty_inst| {
9046 gz.rl_ty_inst = ty_inst;9057 gz.rl_ty_inst = ty_inst;
9047 gz.break_result_loc = parent_rl;9058 gz.break_result_loc = parent_rl;
9048 },9059 },
...@@ -9425,18 +9436,26 @@ const GenZir = struct {...@@ -9425,18 +9436,26 @@ const GenZir = struct {
9425 return indexToRef(new_index);9436 return indexToRef(new_index);
9426 }9437 }
94279438
9428 fn addPlTok(9439 fn addParam(
9429 gz: *GenZir,9440 gz: *GenZir,
9430 tag: Zir.Inst.Tag,9441 tag: Zir.Inst.Tag,
9431 /// Absolute token index. This function does the conversion to Decl offset.9442 /// Absolute token index. This function does the conversion to Decl offset.
9432 abs_tok_index: ast.TokenIndex,9443 abs_tok_index: ast.TokenIndex,
9433 extra: anytype,9444 name: u32,
9434 ) !Zir.Inst.Ref {9445 body: []const u32,
9446 ) !Zir.Inst.Index {
9435 const gpa = gz.astgen.gpa;9447 const gpa = gz.astgen.gpa;
9436 try gz.instructions.ensureUnusedCapacity(gpa, 1);9448 try gz.instructions.ensureUnusedCapacity(gpa, 1);
9437 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);9449 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
9450 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).Struct.fields.len +
9451 body.len);
9452
9453 const payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Param{
9454 .name = name,
9455 .body_len = @intCast(u32, body.len),
9456 });
9457 gz.astgen.extra.appendSliceAssumeCapacity(body);
94389458
9439 const payload_index = try gz.astgen.addExtra(extra);
9440 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);9459 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
9441 gz.astgen.instructions.appendAssumeCapacity(.{9460 gz.astgen.instructions.appendAssumeCapacity(.{
9442 .tag = tag,9461 .tag = tag,
...@@ -9446,7 +9465,7 @@ const GenZir = struct {...@@ -9446,7 +9465,7 @@ const GenZir = struct {
9446 } },9465 } },
9447 });9466 });
9448 gz.instructions.appendAssumeCapacity(new_index);9467 gz.instructions.appendAssumeCapacity(new_index);
9449 return indexToRef(new_index);9468 return new_index;
9450 }9469 }
94519470
9452 fn addExtendedPayload(9471 fn addExtendedPayload(
src/Compilation.zig+1-1
...@@ -2118,7 +2118,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -2118,7 +2118,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
2118 if (builtin.mode == .Debug and self.verbose_air) {2118 if (builtin.mode == .Debug and self.verbose_air) {
2119 std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});2119 std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});
2120 @import("print_air.zig").dump(gpa, air, decl.namespace.file_scope.zir, liveness);2120 @import("print_air.zig").dump(gpa, air, decl.namespace.file_scope.zir, liveness);
2121 std.debug.print("# End Function AIR: {s}:\n", .{decl.name});2121 std.debug.print("# End Function AIR: {s}\n\n", .{decl.name});
2122 }2122 }
21232123
2124 self.bin_file.updateFunc(module, func, air, liveness) catch |err| switch (err) {2124 self.bin_file.updateFunc(module, func, air, liveness) catch |err| switch (err) {
src/Module.zig+42-10
...@@ -1173,6 +1173,8 @@ pub const Scope = struct {...@@ -1173,6 +1173,8 @@ pub const Scope = struct {
1173 /// for the one that will be the same for all Block instances.1173 /// for the one that will be the same for all Block instances.
1174 src_decl: *Decl,1174 src_decl: *Decl,
1175 instructions: ArrayListUnmanaged(Air.Inst.Index),1175 instructions: ArrayListUnmanaged(Air.Inst.Index),
1176 // `param` instructions are collected here to be used by the `func` instruction.
1177 params: std.ArrayListUnmanaged(Param) = .{},
1176 label: ?*Label = null,1178 label: ?*Label = null,
1177 inlining: ?*Inlining,1179 inlining: ?*Inlining,
1178 /// If runtime_index is not 0 then one of these is guaranteed to be non null.1180 /// If runtime_index is not 0 then one of these is guaranteed to be non null.
...@@ -1187,6 +1189,12 @@ pub const Scope = struct {...@@ -1187,6 +1189,12 @@ pub const Scope = struct {
1187 /// when null, it is determined by build mode, changed by @setRuntimeSafety1189 /// when null, it is determined by build mode, changed by @setRuntimeSafety
1188 want_safety: ?bool = null,1190 want_safety: ?bool = null,
11891191
1192 const Param = struct {
1193 /// `noreturn` means `anytype`.
1194 ty: Type,
1195 is_comptime: bool,
1196 };
1197
1190 /// This `Block` maps a block ZIR instruction to the corresponding1198 /// This `Block` maps a block ZIR instruction to the corresponding
1191 /// AIR instruction for break instruction analysis.1199 /// AIR instruction for break instruction analysis.
1192 pub const Label = struct {1200 pub const Label = struct {
...@@ -1634,8 +1642,11 @@ pub const SrcLoc = struct {...@@ -1634,8 +1642,11 @@ pub const SrcLoc = struct {
1634 .@"asm" => tree.asmFull(node),1642 .@"asm" => tree.asmFull(node),
1635 else => unreachable,1643 else => unreachable,
1636 };1644 };
1645 const asm_output = full.outputs[0];
1646 const node_datas = tree.nodes.items(.data);
1647 const ret_ty_node = node_datas[asm_output].lhs;
1637 const main_tokens = tree.nodes.items(.main_token);1648 const main_tokens = tree.nodes.items(.main_token);
1638 const tok_index = main_tokens[full.outputs[0]];1649 const tok_index = main_tokens[ret_ty_node];
1639 const token_starts = tree.tokens.items(.start);1650 const token_starts = tree.tokens.items(.start);
1640 return token_starts[tok_index];1651 return token_starts[tok_index];
1641 },1652 },
...@@ -2099,7 +2110,20 @@ pub const LazySrcLoc = union(enum) {...@@ -2099,7 +2110,20 @@ pub const LazySrcLoc = union(enum) {
2099};2110};
21002111
2101pub const SemaError = error{ OutOfMemory, AnalysisFail };2112pub const SemaError = error{ OutOfMemory, AnalysisFail };
2102pub const CompileError = error{ OutOfMemory, AnalysisFail, NeededSourceLocation };2113pub const CompileError = error{
2114 OutOfMemory,
2115 /// When this is returned, the compile error for the failure has already been recorded.
2116 AnalysisFail,
2117 /// Returned when a compile error needed to be reported but a provided LazySrcLoc was set
2118 /// to the `unneeded` tag. The source location was, in fact, needed. It is expected that
2119 /// somewhere up the call stack, the operation will be retried after doing expensive work
2120 /// to compute a source location.
2121 NeededSourceLocation,
2122 /// A Type or Value was needed to be used during semantic analysis, but it was not available
2123 /// because the function is generic. This is only seen when analyzing the body of a param
2124 /// instruction.
2125 GenericPoison,
2126};
21032127
2104pub fn deinit(mod: *Module) void {2128pub fn deinit(mod: *Module) void {
2105 const gpa = mod.gpa;2129 const gpa = mod.gpa;
...@@ -2796,14 +2820,16 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) SemaError!void {...@@ -2796,14 +2820,16 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) SemaError!void {
2796 }2820 }
2797 return error.AnalysisFail;2821 return error.AnalysisFail;
2798 },2822 },
2799 else => {2823 error.NeededSourceLocation => unreachable,
2824 error.GenericPoison => unreachable,
2825 else => |e| {
2800 decl.analysis = .sema_failure_retryable;2826 decl.analysis = .sema_failure_retryable;
2801 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);2827 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
2802 mod.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(2828 mod.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
2803 mod.gpa,2829 mod.gpa,
2804 decl.srcLoc(),2830 decl.srcLoc(),
2805 "unable to analyze: {s}",2831 "unable to analyze: {s}",
2806 .{@errorName(err)},2832 .{@errorName(e)},
2807 ));2833 ));
2808 return error.AnalysisFail;2834 return error.AnalysisFail;
2809 },2835 },
...@@ -2982,7 +3008,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2982,7 +3008,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
2982 .inlining = null,3008 .inlining = null,
2983 .is_comptime = true,3009 .is_comptime = true,
2984 };3010 };
2985 defer block_scope.instructions.deinit(gpa);3011 defer {
3012 block_scope.instructions.deinit(gpa);
3013 block_scope.params.deinit(gpa);
3014 }
29863015
2987 const zir_block_index = decl.zirBlockIndex();3016 const zir_block_index = decl.zirBlockIndex();
2988 const inst_data = zir_datas[zir_block_index].pl_node;3017 const inst_data = zir_datas[zir_block_index].pl_node;
...@@ -3669,7 +3698,8 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {...@@ -3669,7 +3698,8 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3669 try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType`3698 try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType`
3670 try sema.inst_map.ensureUnusedCapacity(gpa, fn_info.total_params_len);3699 try sema.inst_map.ensureUnusedCapacity(gpa, fn_info.total_params_len);
36713700
3672 var param_index: usize = 0;3701 var runtime_param_index: usize = 0;
3702 var total_param_index: usize = 0;
3673 for (fn_info.param_body) |inst| {3703 for (fn_info.param_body) |inst| {
3674 const name = switch (zir_tags[inst]) {3704 const name = switch (zir_tags[inst]) {
3675 .param, .param_comptime => blk: {3705 .param, .param_comptime => blk: {
...@@ -3686,16 +3716,16 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {...@@ -3686,16 +3716,16 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3686 else => continue,3716 else => continue,
3687 };3717 };
3688 if (func.comptime_args) |comptime_args| {3718 if (func.comptime_args) |comptime_args| {
3689 const arg_tv = comptime_args[param_index];3719 const arg_tv = comptime_args[total_param_index];
3690 if (arg_tv.val.tag() != .unreachable_value) {3720 if (arg_tv.val.tag() != .unreachable_value) {
3691 // We have a comptime value for this parameter.3721 // We have a comptime value for this parameter.
3692 const arg = try sema.addConstant(arg_tv.ty, arg_tv.val);3722 const arg = try sema.addConstant(arg_tv.ty, arg_tv.val);
3693 sema.inst_map.putAssumeCapacityNoClobber(inst, arg);3723 sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
3694 param_index += 1;3724 total_param_index += 1;
3695 continue;3725 continue;
3696 }3726 }
3697 }3727 }
3698 const param_type = fn_ty.fnParamType(param_index);3728 const param_type = fn_ty.fnParamType(runtime_param_index);
3699 const ty_ref = try sema.addType(param_type);3729 const ty_ref = try sema.addType(param_type);
3700 const arg_index = @intCast(u32, sema.air_instructions.len);3730 const arg_index = @intCast(u32, sema.air_instructions.len);
3701 inner_block.instructions.appendAssumeCapacity(arg_index);3731 inner_block.instructions.appendAssumeCapacity(arg_index);
...@@ -3707,7 +3737,8 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {...@@ -3707,7 +3737,8 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3707 } },3737 } },
3708 });3738 });
3709 sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index));3739 sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index));
3710 param_index += 1;3740 total_param_index += 1;
3741 runtime_param_index += 1;
3711 }3742 }
37123743
3713 func.state = .in_progress;3744 func.state = .in_progress;
...@@ -3715,6 +3746,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {...@@ -3715,6 +3746,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
37153746
3716 _ = sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {3747 _ = sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {
3717 error.NeededSourceLocation => unreachable,3748 error.NeededSourceLocation => unreachable,
3749 error.GenericPoison => unreachable,
3718 else => |e| return e,3750 else => |e| return e,
3719 };3751 };
37203752
src/Sema.zig+267-161
...@@ -37,13 +37,15 @@ branch_count: u32 = 0,...@@ -37,13 +37,15 @@ branch_count: u32 = 0,
37/// contain a mapped source location.37/// contain a mapped source location.
38src: LazySrcLoc = .{ .token_offset = 0 },38src: LazySrcLoc = .{ .token_offset = 0 },
39decl_val_table: std.AutoHashMapUnmanaged(*Decl, Air.Inst.Ref) = .{},39decl_val_table: std.AutoHashMapUnmanaged(*Decl, Air.Inst.Ref) = .{},
40/// `param` instructions are collected here to be used by the `func` instruction.40/// When doing a generic function instantiation, this array collects a
41params: std.ArrayListUnmanaged(Param) = .{},41/// `Value` object for each parameter that is comptime known and thus elided
42/// When doing a generic function instantiation, this array collects a `Value` object for42/// from the generated function. This memory is allocated by a parent `Sema` and
43/// each parameter that is comptime known and thus elided from the generated function.43/// owned by the values arena of the Sema owner_decl.
44/// This memory is allocated by a parent `Sema` and owned by the values arena of the owner_decl.
45comptime_args: []TypedValue = &.{},44comptime_args: []TypedValue = &.{},
46next_arg_index: usize = 0,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,
4749
48const std = @import("std");50const std = @import("std");
49const mem = std.mem;51const mem = std.mem;
...@@ -67,13 +69,6 @@ const LazySrcLoc = Module.LazySrcLoc;...@@ -67,13 +69,6 @@ const LazySrcLoc = Module.LazySrcLoc;
67const RangeSet = @import("RangeSet.zig");69const RangeSet = @import("RangeSet.zig");
68const target_util = @import("target.zig");70const target_util = @import("target.zig");
6971
70const Param = struct {
71 name: [:0]const u8,
72 /// `noreturn` means `anytype`.
73 ty: Type,
74 is_comptime: bool,
75};
76
77pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);72pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);
7873
79pub fn deinit(sema: *Sema) void {74pub fn deinit(sema: *Sema) void {
...@@ -83,7 +78,6 @@ pub fn deinit(sema: *Sema) void {...@@ -83,7 +78,6 @@ pub fn deinit(sema: *Sema) void {
83 sema.air_values.deinit(gpa);78 sema.air_values.deinit(gpa);
84 sema.inst_map.deinit(gpa);79 sema.inst_map.deinit(gpa);
85 sema.decl_val_table.deinit(gpa);80 sema.decl_val_table.deinit(gpa);
86 sema.params.deinit(gpa);
87 sema.* = undefined;81 sema.* = undefined;
88}82}
8983
...@@ -466,6 +460,26 @@ pub fn analyzeBody(...@@ -466,6 +460,26 @@ pub fn analyzeBody(
466 i += 1;460 i += 1;
467 continue;461 continue;
468 },462 },
463 .param => {
464 try sema.zirParam(block, inst, false);
465 i += 1;
466 continue;
467 },
468 .param_comptime => {
469 try sema.zirParam(block, inst, true);
470 i += 1;
471 continue;
472 },
473 .param_anytype => {
474 try sema.zirParamAnytype(block, inst, false);
475 i += 1;
476 continue;
477 },
478 .param_anytype_comptime => {
479 try sema.zirParamAnytype(block, inst, true);
480 i += 1;
481 continue;
482 },
469483
470 // Special case instructions to handle comptime control flow.484 // Special case instructions to handle comptime control flow.
471 .repeat_inline => {485 .repeat_inline => {
...@@ -504,88 +518,6 @@ pub fn analyzeBody(...@@ -504,88 +518,6 @@ pub fn analyzeBody(
504 return break_inst;518 return break_inst;
505 }519 }
506 },520 },
507 .param => blk: {
508 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
509 const src = inst_data.src();
510 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index).data;
511 const param_name = sema.code.nullTerminatedString(extra.name);
512
513 if (sema.nextArgIsComptimeElided()) {
514 i += 1;
515 continue;
516 }
517
518 // TODO check if param_name shadows a Decl. This only needs to be done if
519 // usingnamespace is implemented.
520
521 const param_ty = try sema.resolveType(block, src, extra.ty);
522 try sema.params.append(sema.gpa, .{
523 .name = param_name,
524 .ty = param_ty,
525 .is_comptime = false,
526 });
527 break :blk try sema.addConstUndef(param_ty);
528 },
529 .param_comptime => blk: {
530 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
531 const src = inst_data.src();
532 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index).data;
533 const param_name = sema.code.nullTerminatedString(extra.name);
534
535 if (sema.nextArgIsComptimeElided()) {
536 i += 1;
537 continue;
538 }
539
540 // TODO check if param_name shadows a Decl. This only needs to be done if
541 // usingnamespace is implemented.
542
543 const param_ty = try sema.resolveType(block, src, extra.ty);
544 try sema.params.append(sema.gpa, .{
545 .name = param_name,
546 .ty = param_ty,
547 .is_comptime = true,
548 });
549 break :blk try sema.addConstUndef(param_ty);
550 },
551 .param_anytype => blk: {
552 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
553 const param_name = inst_data.get(sema.code);
554
555 if (sema.nextArgIsComptimeElided()) {
556 i += 1;
557 continue;
558 }
559
560 // TODO check if param_name shadows a Decl. This only needs to be done if
561 // usingnamespace is implemented.
562
563 try sema.params.append(sema.gpa, .{
564 .name = param_name,
565 .ty = Type.initTag(.noreturn),
566 .is_comptime = false,
567 });
568 break :blk try sema.addConstUndef(Type.initTag(.@"undefined"));
569 },
570 .param_anytype_comptime => blk: {
571 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
572 const param_name = inst_data.get(sema.code);
573
574 if (sema.nextArgIsComptimeElided()) {
575 i += 1;
576 continue;
577 }
578
579 // TODO check if param_name shadows a Decl. This only needs to be done if
580 // usingnamespace is implemented.
581
582 try sema.params.append(sema.gpa, .{
583 .name = param_name,
584 .ty = Type.initTag(.noreturn),
585 .is_comptime = true,
586 });
587 break :blk try sema.addConstUndef(Type.initTag(.@"undefined"));
588 },
589 };521 };
590 if (sema.typeOf(air_inst).isNoReturn())522 if (sema.typeOf(air_inst).isNoReturn())
591 return always_noreturn;523 return always_noreturn;
...@@ -697,6 +629,7 @@ fn resolveValue(...@@ -697,6 +629,7 @@ fn resolveValue(
697 air_ref: Air.Inst.Ref,629 air_ref: Air.Inst.Ref,
698) CompileError!Value {630) CompileError!Value {
699 if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {631 if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {
632 if (val.tag() == .generic_poison) return error.GenericPoison;
700 return val;633 return val;
701 }634 }
702 return sema.failWithNeededComptime(block, src);635 return sema.failWithNeededComptime(block, src);
...@@ -714,6 +647,7 @@ fn resolveConstValue(...@@ -714,6 +647,7 @@ fn resolveConstValue(
714 switch (val.tag()) {647 switch (val.tag()) {
715 .undef => return sema.failWithUseOfUndef(block, src),648 .undef => return sema.failWithUseOfUndef(block, src),
716 .variable => return sema.failWithNeededComptime(block, src),649 .variable => return sema.failWithNeededComptime(block, src),
650 .generic_poison => return error.GenericPoison,
717 else => return val,651 else => return val,
718 }652 }
719 }653 }
...@@ -2422,7 +2356,7 @@ fn analyzeCall(...@@ -2422,7 +2356,7 @@ fn analyzeCall(
2422 call_src: LazySrcLoc,2356 call_src: LazySrcLoc,
2423 modifier: std.builtin.CallOptions.Modifier,2357 modifier: std.builtin.CallOptions.Modifier,
2424 ensure_result_used: bool,2358 ensure_result_used: bool,
2425 args: []const Air.Inst.Ref,2359 uncasted_args: []const Air.Inst.Ref,
2426) CompileError!Air.Inst.Ref {2360) CompileError!Air.Inst.Ref {
2427 const mod = sema.mod;2361 const mod = sema.mod;
24282362
...@@ -2444,22 +2378,22 @@ fn analyzeCall(...@@ -2444,22 +2378,22 @@ fn analyzeCall(
2444 const fn_params_len = func_ty_info.param_types.len;2378 const fn_params_len = func_ty_info.param_types.len;
2445 if (func_ty_info.is_var_args) {2379 if (func_ty_info.is_var_args) {
2446 assert(cc == .C);2380 assert(cc == .C);
2447 if (args.len < fn_params_len) {2381 if (uncasted_args.len < fn_params_len) {
2448 // TODO add error note: declared here2382 // TODO add error note: declared here
2449 return mod.fail(2383 return mod.fail(
2450 &block.base,2384 &block.base,
2451 func_src,2385 func_src,
2452 "expected at least {d} argument(s), found {d}",2386 "expected at least {d} argument(s), found {d}",
2453 .{ fn_params_len, args.len },2387 .{ fn_params_len, uncasted_args.len },
2454 );2388 );
2455 }2389 }
2456 } else if (fn_params_len != args.len) {2390 } else if (fn_params_len != uncasted_args.len) {
2457 // TODO add error note: declared here2391 // TODO add error note: declared here
2458 return mod.fail(2392 return mod.fail(
2459 &block.base,2393 &block.base,
2460 func_src,2394 func_src,
2461 "expected {d} argument(s), found {d}",2395 "expected {d} argument(s), found {d}",
2462 .{ fn_params_len, args.len },2396 .{ fn_params_len, uncasted_args.len },
2463 );2397 );
2464 }2398 }
24652399
...@@ -2485,6 +2419,14 @@ fn analyzeCall(...@@ -2485,6 +2419,14 @@ fn analyzeCall(
2485 const is_inline_call = is_comptime_call or modifier == .always_inline or2419 const is_inline_call = is_comptime_call or modifier == .always_inline or
2486 func_ty_info.cc == .Inline;2420 func_ty_info.cc == .Inline;
2487 const result: Air.Inst.Ref = if (is_inline_call) res: {2421 const result: Air.Inst.Ref = if (is_inline_call) res: {
2422 // TODO look into not allocating this args array
2423 const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
2424 for (uncasted_args) |uncasted_arg, i| {
2425 const param_ty = func_ty.fnParamType(i);
2426 const arg_src = call_src; // TODO: better source location
2427 args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
2428 }
2429
2488 const func_val = try sema.resolveConstValue(block, func_src, func);2430 const func_val = try sema.resolveConstValue(block, func_src, func);
2489 const module_fn = switch (func_val.tag()) {2431 const module_fn = switch (func_val.tag()) {
2490 .function => func_val.castTag(.function).?.data,2432 .function => func_val.castTag(.function).?.data,
...@@ -2574,13 +2516,12 @@ fn analyzeCall(...@@ -2574,13 +2516,12 @@ fn analyzeCall(
2574 const func_val = try sema.resolveConstValue(block, func_src, func);2516 const func_val = try sema.resolveConstValue(block, func_src, func);
2575 const module_fn = func_val.castTag(.function).?.data;2517 const module_fn = func_val.castTag(.function).?.data;
2576 // Check the Module's generic function map with an adapted context, so that we2518 // Check the Module's generic function map with an adapted context, so that we
2577 // can match against `args` rather than doing the work below to create a generic Scope2519 // can match against `uncasted_args` rather than doing the work below to create a
2578 // only to junk it if it matches an existing instantiation.2520 // generic Scope only to junk it if it matches an existing instantiation.
2579 // TODO2521 // TODO
25802522
2581 const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst);2523 const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst);
2582 const zir_tags = sema.code.instructions.items(.tag);2524 const zir_tags = sema.code.instructions.items(.tag);
2583 var non_comptime_args_len: u32 = 0;
2584 const new_func = new_func: {2525 const new_func = new_func: {
2585 const namespace = module_fn.owner_decl.namespace;2526 const namespace = module_fn.owner_decl.namespace;
2586 try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);2527 try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);
...@@ -2622,7 +2563,8 @@ fn analyzeCall(...@@ -2622,7 +2563,8 @@ fn analyzeCall(
2622 .namespace = namespace,2563 .namespace = namespace,
2623 .func = null,2564 .func = null,
2624 .owner_func = null,2565 .owner_func = null,
2625 .comptime_args = try new_decl_arena.allocator.alloc(TypedValue, args.len),2566 .comptime_args = try new_decl_arena.allocator.alloc(TypedValue, uncasted_args.len),
2567 .comptime_args_fn_inst = module_fn.zir_body_inst,
2626 };2568 };
2627 defer child_sema.deinit();2569 defer child_sema.deinit();
26282570
...@@ -2634,41 +2576,59 @@ fn analyzeCall(...@@ -2634,41 +2576,59 @@ fn analyzeCall(
2634 .inlining = null,2576 .inlining = null,
2635 .is_comptime = true,2577 .is_comptime = true,
2636 };2578 };
2637 defer child_block.instructions.deinit(gpa);2579 defer {
2580 child_block.instructions.deinit(gpa);
2581 child_block.params.deinit(gpa);
2582 }
26382583
2639 try child_sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, args.len));2584 try child_sema.inst_map.ensureUnusedCapacity(gpa, @intCast(u32, uncasted_args.len));
2640 var arg_i: usize = 0;2585 var arg_i: usize = 0;
2641 for (fn_info.param_body) |inst| {2586 for (fn_info.param_body) |inst| {
2642 const is_comptime = switch (zir_tags[inst]) {2587 const is_comptime = switch (zir_tags[inst]) {
2643 .param_comptime, .param_anytype_comptime => true,2588 .param_comptime, .param_anytype_comptime => true,
2644 .param, .param_anytype => false, // TODO make true for always comptime types2589 .param, .param_anytype => false,
2645 else => continue,2590 else => continue,
2646 };2591 };
2647 if (is_comptime) {2592 // TODO: pass .unneeded to resolveConstValue and then if we get
2648 // TODO: pass .unneeded to resolveConstValue and then if we get2593 // error.NeededSourceLocation resolve the arg source location and
2649 // error.NeededSourceLocation resolve the arg source location and2594 // try again.
2650 // try again.2595 const arg_src = call_src;
2651 const arg_src = call_src;2596 const arg = uncasted_args[arg_i];
2652 const arg = args[arg_i];2597 if (try sema.resolveMaybeUndefVal(block, arg_src, arg)) |arg_val| {
2653 const arg_val = try sema.resolveConstValue(block, arg_src, arg);
2654 child_sema.comptime_args[arg_i] = .{
2655 .ty = try sema.typeOf(arg).copy(&new_decl_arena.allocator),
2656 .val = try arg_val.copy(&new_decl_arena.allocator),
2657 };
2658 const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val);2598 const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val);
2659 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);2599 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
2660 } else {2600 } else if (is_comptime) {
2661 non_comptime_args_len += 1;2601 return sema.failWithNeededComptime(block, arg_src);
2602 }
2603 arg_i += 1;
2604 }
2605 const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body);
2606 const new_func_val = try child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst);
2607 const new_func = new_func_val.castTag(.function).?.data;
2608
2609 arg_i = 0;
2610 for (fn_info.param_body) |inst| {
2611 switch (zir_tags[inst]) {
2612 .param_comptime, .param_anytype_comptime, .param, .param_anytype => {},
2613 else => continue,
2614 }
2615 const arg = child_sema.inst_map.get(inst).?;
2616 const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(&child_block, .unneeded, arg) catch unreachable).?;
2617
2618 if (arg_val.tag() == .generic_poison) {
2662 child_sema.comptime_args[arg_i] = .{2619 child_sema.comptime_args[arg_i] = .{
2663 .ty = Type.initTag(.noreturn),2620 .ty = Type.initTag(.noreturn),
2664 .val = Value.initTag(.unreachable_value),2621 .val = Value.initTag(.unreachable_value),
2665 };2622 };
2623 } else {
2624 child_sema.comptime_args[arg_i] = .{
2625 .ty = try child_sema.typeOf(arg).copy(&new_decl_arena.allocator),
2626 .val = try arg_val.copy(&new_decl_arena.allocator),
2627 };
2666 }2628 }
2629
2667 arg_i += 1;2630 arg_i += 1;
2668 }2631 }
2669 const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body);
2670 const new_func_val = try child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst);
2671 const new_func = new_func_val.castTag(.function).?.data;
26722632
2673 // Populate the Decl ty/val with the function and its type.2633 // Populate the Decl ty/val with the function and its type.
2674 new_decl.ty = try child_sema.typeOf(new_func_inst).copy(&new_decl_arena.allocator);2634 new_decl.ty = try child_sema.typeOf(new_func_inst).copy(&new_decl_arena.allocator);
...@@ -2690,31 +2650,72 @@ fn analyzeCall(...@@ -2690,31 +2650,72 @@ fn analyzeCall(
26902650
2691 // Make a runtime call to the new function, making sure to omit the comptime args.2651 // Make a runtime call to the new function, making sure to omit the comptime args.
2692 try sema.requireRuntimeBlock(block, call_src);2652 try sema.requireRuntimeBlock(block, call_src);
2653 const new_func_val = sema.resolveConstValue(block, .unneeded, new_func) catch unreachable;
2654 const new_module_func = new_func_val.castTag(.function).?.data;
2655 const comptime_args = new_module_func.comptime_args.?;
2656 const runtime_args_len = count: {
2657 var count: u32 = 0;
2658 var arg_i: usize = 0;
2659 for (fn_info.param_body) |inst| {
2660 switch (zir_tags[inst]) {
2661 .param_comptime, .param_anytype_comptime, .param, .param_anytype => {
2662 if (comptime_args[arg_i].val.tag() == .unreachable_value) {
2663 count += 1;
2664 }
2665 arg_i += 1;
2666 },
2667 else => continue,
2668 }
2669 }
2670 break :count count;
2671 };
2672 const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len);
2673 {
2674 const new_fn_ty = new_module_func.owner_decl.ty;
2675 var runtime_i: u32 = 0;
2676 var total_i: u32 = 0;
2677 for (fn_info.param_body) |inst| {
2678 switch (zir_tags[inst]) {
2679 .param_comptime, .param_anytype_comptime, .param, .param_anytype => {},
2680 else => continue,
2681 }
2682 const is_runtime = comptime_args[total_i].val.tag() == .unreachable_value;
2683 if (is_runtime) {
2684 const param_ty = new_fn_ty.fnParamType(runtime_i);
2685 const arg_src = call_src; // TODO: better source location
2686 const uncasted_arg = uncasted_args[total_i];
2687 const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
2688 runtime_args[runtime_i] = casted_arg;
2689 runtime_i += 1;
2690 }
2691 total_i += 1;
2692 }
2693 }
2693 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +2694 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
2694 non_comptime_args_len);2695 runtime_args_len);
2695 const func_inst = try block.addInst(.{2696 const func_inst = try block.addInst(.{
2696 .tag = .call,2697 .tag = .call,
2697 .data = .{ .pl_op = .{2698 .data = .{ .pl_op = .{
2698 .operand = new_func,2699 .operand = new_func,
2699 .payload = sema.addExtraAssumeCapacity(Air.Call{2700 .payload = sema.addExtraAssumeCapacity(Air.Call{
2700 .args_len = non_comptime_args_len,2701 .args_len = runtime_args_len,
2701 }),2702 }),
2702 } },2703 } },
2703 });2704 });
2704 var arg_i: usize = 0;2705 sema.appendRefsAssumeCapacity(runtime_args);
2705 for (fn_info.param_body) |inst| {
2706 const is_comptime = switch (zir_tags[inst]) {
2707 .param_comptime, .param_anytype_comptime => true,
2708 .param, .param_anytype => false, // TODO make true for always comptime types
2709 else => continue,
2710 };
2711 if (is_comptime) {
2712 sema.air_extra.appendAssumeCapacity(@enumToInt(args[arg_i]));
2713 }
2714 arg_i += 1;
2715 }
2716 break :res func_inst;2706 break :res func_inst;
2717 } else res: {2707 } else res: {
2708 const args = try sema.arena.alloc(Air.Inst.Ref, uncasted_args.len);
2709 for (uncasted_args) |uncasted_arg, i| {
2710 if (i < fn_params_len) {
2711 const param_ty = func_ty.fnParamType(i);
2712 const arg_src = call_src; // TODO: better source location
2713 args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
2714 } else {
2715 args[i] = uncasted_arg;
2716 }
2717 }
2718
2718 try sema.requireRuntimeBlock(block, call_src);2719 try sema.requireRuntimeBlock(block, call_src);
2719 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +2720 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
2720 args.len);2721 args.len);
...@@ -3416,7 +3417,7 @@ fn funcCommon(...@@ -3416,7 +3417,7 @@ fn funcCommon(
34163417
3417 const fn_ty: Type = fn_ty: {3418 const fn_ty: Type = fn_ty: {
3418 // Hot path for some common function types.3419 // Hot path for some common function types.
3419 if (sema.params.items.len == 0 and !var_args and align_val.tag() == .null_value and3420 if (block.params.items.len == 0 and !var_args and align_val.tag() == .null_value and
3420 !inferred_error_set)3421 !inferred_error_set)
3421 {3422 {
3422 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {3423 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
...@@ -3436,19 +3437,15 @@ fn funcCommon(...@@ -3436,19 +3437,15 @@ fn funcCommon(
3436 }3437 }
3437 }3438 }
34383439
3439 var any_are_comptime = false;3440 var is_generic = false;
3440 const param_types = try sema.arena.alloc(Type, sema.params.items.len);3441 const param_types = try sema.arena.alloc(Type, block.params.items.len);
3441 const comptime_params = try sema.arena.alloc(bool, sema.params.items.len);3442 const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
3442 for (sema.params.items) |param, i| {3443 for (block.params.items) |param, i| {
3443 if (param.ty.tag() == .noreturn) {3444 param_types[i] = param.ty;
3444 param_types[i] = Type.initTag(.noreturn); // indicates anytype
3445 } else {
3446 param_types[i] = param.ty;
3447 }
3448 comptime_params[i] = param.is_comptime;3445 comptime_params[i] = param.is_comptime;
3449 any_are_comptime = any_are_comptime or param.is_comptime;3446 is_generic = is_generic or param.is_comptime or
3447 param.ty.tag() == .generic_poison or param.ty.requiresComptime();
3450 }3448 }
3451 sema.params.clearRetainingCapacity();
34523449
3453 if (align_val.tag() != .null_value) {3450 if (align_val.tag() != .null_value) {
3454 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});3451 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
...@@ -3471,7 +3468,7 @@ fn funcCommon(...@@ -3471,7 +3468,7 @@ fn funcCommon(
3471 .return_type = return_type,3468 .return_type = return_type,
3472 .cc = cc,3469 .cc = cc,
3473 .is_var_args = var_args,3470 .is_var_args = var_args,
3474 .is_generic = any_are_comptime,3471 .is_generic = is_generic,
3475 });3472 });
3476 };3473 };
34773474
...@@ -3530,12 +3527,16 @@ fn funcCommon(...@@ -3530,12 +3527,16 @@ fn funcCommon(
3530 const is_inline = fn_ty.fnCallingConvention() == .Inline;3527 const is_inline = fn_ty.fnCallingConvention() == .Inline;
3531 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;3528 const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;
35323529
3530 const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == body_inst) blk: {
3531 break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;
3532 } else null;
3533
3533 const fn_payload = try sema.arena.create(Value.Payload.Function);3534 const fn_payload = try sema.arena.create(Value.Payload.Function);
3534 new_func.* = .{3535 new_func.* = .{
3535 .state = anal_state,3536 .state = anal_state,
3536 .zir_body_inst = body_inst,3537 .zir_body_inst = body_inst,
3537 .owner_decl = sema.owner_decl,3538 .owner_decl = sema.owner_decl,
3538 .comptime_args = if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr,3539 .comptime_args = comptime_args,
3539 .lbrace_line = src_locs.lbrace_line,3540 .lbrace_line = src_locs.lbrace_line,
3540 .rbrace_line = src_locs.rbrace_line,3541 .rbrace_line = src_locs.rbrace_line,
3541 .lbrace_column = @truncate(u16, src_locs.columns),3542 .lbrace_column = @truncate(u16, src_locs.columns),
...@@ -3548,6 +3549,113 @@ fn funcCommon(...@@ -3548,6 +3549,113 @@ fn funcCommon(
3548 return sema.addConstant(fn_ty, Value.initPayload(&fn_payload.base));3549 return sema.addConstant(fn_ty, Value.initPayload(&fn_payload.base));
3549}3550}
35503551
3552fn zirParam(
3553 sema: *Sema,
3554 block: *Scope.Block,
3555 inst: Zir.Inst.Index,
3556 is_comptime: bool,
3557) CompileError!void {
3558 const inst_data = sema.code.instructions.items(.data)[inst].pl_tok;
3559 const src = inst_data.src();
3560 const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
3561 const param_name = sema.code.nullTerminatedString(extra.data.name);
3562 const body = sema.code.extra[extra.end..][0..extra.data.body_len];
3563
3564 // TODO check if param_name shadows a Decl. This only needs to be done if
3565 // usingnamespace is implemented.
3566 _ = param_name;
3567
3568 // We could be in a generic function instantiation, or we could be evaluating a generic
3569 // function without any comptime args provided.
3570 const param_ty = param_ty: {
3571 const err = err: {
3572 // Make sure any nested param instructions don't clobber our work.
3573 const prev_params = block.params;
3574 block.params = .{};
3575 defer {
3576 block.params.deinit(sema.gpa);
3577 block.params = prev_params;
3578 }
3579
3580 if (sema.resolveBody(block, body)) |param_ty_inst| {
3581 if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| {
3582 break :param_ty param_ty;
3583 } else |err| break :err err;
3584 } else |err| break :err err;
3585 };
3586 switch (err) {
3587 error.GenericPoison => {
3588 // The type is not available until the generic instantiation.
3589 // We result the param instruction with a poison value and
3590 // insert an anytype parameter.
3591 try block.params.append(sema.gpa, .{
3592 .ty = Type.initTag(.generic_poison),
3593 .is_comptime = is_comptime,
3594 });
3595 try sema.inst_map.putNoClobber(sema.gpa, inst, .generic_poison);
3596 return;
3597 },
3598 else => |e| return e,
3599 }
3600 };
3601 if (sema.inst_map.get(inst)) |arg| {
3602 if (is_comptime or param_ty.requiresComptime()) {
3603 // We have a comptime value for this parameter so it should be elided from the
3604 // function type of the function instruction in this block.
3605 const coerced_arg = try sema.coerce(block, param_ty, arg, src);
3606 sema.inst_map.putAssumeCapacity(inst, coerced_arg);
3607 return;
3608 }
3609 // Even though a comptime argument is provided, the generic function wants to treat
3610 // this as a runtime parameter.
3611 assert(sema.inst_map.remove(inst));
3612 }
3613
3614 try block.params.append(sema.gpa, .{
3615 .ty = param_ty,
3616 .is_comptime = is_comptime,
3617 });
3618 const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
3619 try sema.inst_map.putNoClobber(sema.gpa, inst, result);
3620}
3621
3622fn zirParamAnytype(
3623 sema: *Sema,
3624 block: *Scope.Block,
3625 inst: Zir.Inst.Index,
3626 is_comptime: bool,
3627) CompileError!void {
3628 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
3629 const param_name = inst_data.get(sema.code);
3630
3631 // TODO check if param_name shadows a Decl. This only needs to be done if
3632 // usingnamespace is implemented.
3633 _ = param_name;
3634
3635 if (sema.inst_map.get(inst)) |air_ref| {
3636 const param_ty = sema.typeOf(air_ref);
3637 if (is_comptime or param_ty.requiresComptime()) {
3638 // We have a comptime value for this parameter so it should be elided from the
3639 // function type of the function instruction in this block.
3640 return;
3641 }
3642 // The map is already populated but we do need to add a runtime parameter.
3643 try block.params.append(sema.gpa, .{
3644 .ty = param_ty,
3645 .is_comptime = false,
3646 });
3647 return;
3648 }
3649
3650 // We are evaluating a generic function without any comptime args provided.
3651
3652 try block.params.append(sema.gpa, .{
3653 .ty = Type.initTag(.generic_poison),
3654 .is_comptime = is_comptime,
3655 });
3656 try sema.inst_map.put(sema.gpa, inst, .generic_poison);
3657}
3658
3551fn zirAs(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {3659fn zirAs(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
3552 const tracy = trace(@src());3660 const tracy = trace(@src());
3553 defer tracy.end();3661 defer tracy.end();
...@@ -7618,8 +7726,10 @@ fn coerce(...@@ -7618,8 +7726,10 @@ fn coerce(
7618 inst: Air.Inst.Ref,7726 inst: Air.Inst.Ref,
7619 inst_src: LazySrcLoc,7727 inst_src: LazySrcLoc,
7620) CompileError!Air.Inst.Ref {7728) CompileError!Air.Inst.Ref {
7621 if (dest_type_unresolved.tag() == .var_args_param) {7729 switch (dest_type_unresolved.tag()) {
7622 return sema.coerceVarArgParam(block, inst, inst_src);7730 .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src),
7731 .generic_poison => return inst,
7732 else => {},
7623 }7733 }
7624 const dest_type_src = inst_src; // TODO better source location7734 const dest_type_src = inst_src; // TODO better source location
7625 const dest_type = try sema.resolveTypeFields(block, dest_type_src, dest_type_unresolved);7735 const dest_type = try sema.resolveTypeFields(block, dest_type_src, dest_type_unresolved);
...@@ -8820,6 +8930,7 @@ fn typeHasOnePossibleValue(...@@ -8820,6 +8930,7 @@ fn typeHasOnePossibleValue(
88208930
8821 .inferred_alloc_const => unreachable,8931 .inferred_alloc_const => unreachable,
8822 .inferred_alloc_mut => unreachable,8932 .inferred_alloc_mut => unreachable,
8933 .generic_poison => unreachable,
8823 };8934 };
8824}8935}
88258936
...@@ -8942,6 +9053,8 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {...@@ -8942,6 +9053,8 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
8942 .fn_ccc_void_no_args => return .fn_ccc_void_no_args_type,9053 .fn_ccc_void_no_args => return .fn_ccc_void_no_args_type,
8943 .single_const_pointer_to_comptime_int => return .single_const_pointer_to_comptime_int_type,9054 .single_const_pointer_to_comptime_int => return .single_const_pointer_to_comptime_int_type,
8944 .const_slice_u8 => return .const_slice_u8_type,9055 .const_slice_u8 => return .const_slice_u8_type,
9056 .anyerror_void_error_union => return .anyerror_void_error_union_type,
9057 .generic_poison => return .generic_poison_type,
8945 else => {},9058 else => {},
8946 }9059 }
8947 try sema.air_instructions.append(sema.gpa, .{9060 try sema.air_instructions.append(sema.gpa, .{
...@@ -9015,10 +9128,3 @@ fn isComptimeKnown(...@@ -9015,10 +9128,3 @@ fn isComptimeKnown(
9015) !bool {9128) !bool {
9016 return (try sema.resolveMaybeUndefVal(block, src, inst)) != null;9129 return (try sema.resolveMaybeUndefVal(block, src, inst)) != null;
9017}9130}
9018
9019fn nextArgIsComptimeElided(sema: *Sema) bool {
9020 if (sema.comptime_args.len == 0) return false;
9021 const result = sema.comptime_args[sema.next_arg_index].val.tag() != .unreachable_value;
9022 sema.next_arg_index += 1;
9023 return result;
9024}
src/Zir.zig+28-4
...@@ -1704,6 +1704,8 @@ pub const Inst = struct {...@@ -1704,6 +1704,8 @@ pub const Inst = struct {
1704 fn_ccc_void_no_args_type,1704 fn_ccc_void_no_args_type,
1705 single_const_pointer_to_comptime_int_type,1705 single_const_pointer_to_comptime_int_type,
1706 const_slice_u8_type,1706 const_slice_u8_type,
1707 anyerror_void_error_union_type,
1708 generic_poison_type,
17071709
1708 /// `undefined` (untyped)1710 /// `undefined` (untyped)
1709 undef,1711 undef,
...@@ -1731,6 +1733,9 @@ pub const Inst = struct {...@@ -1731,6 +1733,9 @@ pub const Inst = struct {
1731 calling_convention_c,1733 calling_convention_c,
1732 /// `std.builtin.CallingConvention.Inline`1734 /// `std.builtin.CallingConvention.Inline`
1733 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,
17341739
1735 _,1740 _,
17361741
...@@ -1909,6 +1914,14 @@ pub const Inst = struct {...@@ -1909,6 +1914,14 @@ pub const Inst = struct {
1909 .ty = Type.initTag(.type),1914 .ty = Type.initTag(.type),
1910 .val = Value.initTag(.const_slice_u8_type),1915 .val = Value.initTag(.const_slice_u8_type),
1911 },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 },
1912 .enum_literal_type = .{1925 .enum_literal_type = .{
1913 .ty = Type.initTag(.type),1926 .ty = Type.initTag(.type),
1914 .val = Value.initTag(.enum_literal_type),1927 .val = Value.initTag(.enum_literal_type),
...@@ -2006,6 +2019,10 @@ pub const Inst = struct {...@@ -2006,6 +2019,10 @@ pub const Inst = struct {
2006 .ty = Type.initTag(.calling_convention),2019 .ty = Type.initTag(.calling_convention),
2007 .val = .{ .ptr_otherwise = &calling_convention_inline_payload.base },2020 .val = .{ .ptr_otherwise = &calling_convention_inline_payload.base },
2008 },2021 },
2022 .generic_poison = .{
2023 .ty = Type.initTag(.generic_poison),
2024 .val = Value.initTag(.generic_poison),
2025 },
2009 });2026 });
2010 };2027 };
20112028
...@@ -2787,10 +2804,12 @@ pub const Inst = struct {...@@ -2787,10 +2804,12 @@ pub const Inst = struct {
2787 args: Ref,2804 args: Ref,
2788 };2805 };
27892806
2807 /// Trailing: inst: Index // for every body_len
2790 pub const Param = struct {2808 pub const Param = struct {
2791 /// Null-terminated string index.2809 /// Null-terminated string index.
2792 name: u32,2810 name: u32,
2793 ty: Ref,2811 /// The body contains the type of the parameter.
2812 body_len: u32,
2794 };2813 };
27952814
2796 /// Trailing:2815 /// Trailing:
...@@ -3348,11 +3367,16 @@ const Writer = struct {...@@ -3348,11 +3367,16 @@ const Writer = struct {
33483367
3349 fn writeParam(self: *Writer, stream: anytype, inst: Inst.Index) !void {3368 fn writeParam(self: *Writer, stream: anytype, inst: Inst.Index) !void {
3350 const inst_data = self.code.instructions.items(.data)[inst].pl_tok;3369 const inst_data = self.code.instructions.items(.data)[inst].pl_tok;
3351 const extra = self.code.extraData(Inst.Param, inst_data.payload_index).data;3370 const extra = self.code.extraData(Inst.Param, inst_data.payload_index);
3371 const body = self.code.extra[extra.end..][0..extra.data.body_len];
3352 try stream.print("\"{}\", ", .{3372 try stream.print("\"{}\", ", .{
3353 std.zig.fmtEscapes(self.code.nullTerminatedString(extra.name)),3373 std.zig.fmtEscapes(self.code.nullTerminatedString(extra.data.name)),
3354 });3374 });
3355 try self.writeInstRef(stream, extra.ty);3375 try stream.writeAll("{\n");
3376 self.indent += 2;
3377 try self.writeBody(stream, body);
3378 self.indent -= 2;
3379 try stream.writeByteNTimes(' ', self.indent);
3356 try stream.writeAll(") ");3380 try stream.writeAll(") ");
3357 try self.writeSrc(stream, inst_data.src());3381 try self.writeSrc(stream, inst_data.src());
3358 }3382 }
src/codegen/llvm.zig+4
...@@ -839,6 +839,10 @@ pub const DeclGen = struct {...@@ -839,6 +839,10 @@ pub const DeclGen = struct {
839 .False,839 .False,
840 );840 );
841 },841 },
842 .ComptimeInt => unreachable,
843 .ComptimeFloat => unreachable,
844 .Type => unreachable,
845 .EnumLiteral => unreachable,
842 else => return self.todo("implement const of type '{}'", .{tv.ty}),846 else => return self.todo("implement const of type '{}'", .{tv.ty}),
843 }847 }
844 }848 }
src/type.zig+116
...@@ -130,6 +130,7 @@ pub const Type = extern union {...@@ -130,6 +130,7 @@ pub const Type = extern union {
130 => return .Union,130 => return .Union,
131131
132 .var_args_param => unreachable, // can be any type132 .var_args_param => unreachable, // can be any type
133 .generic_poison => unreachable, // must be handled earlier
133 }134 }
134 }135 }
135136
...@@ -699,6 +700,7 @@ pub const Type = extern union {...@@ -699,6 +700,7 @@ pub const Type = extern union {
699 .export_options,700 .export_options,
700 .extern_options,701 .extern_options,
701 .@"anyframe",702 .@"anyframe",
703 .generic_poison,
702 => unreachable,704 => unreachable,
703705
704 .array_u8,706 .array_u8,
...@@ -1083,11 +1085,117 @@ pub const Type = extern union {...@@ -1083,11 +1085,117 @@ pub const Type = extern union {
1083 },1085 },
1084 .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"),1086 .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"),
1085 .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"),1087 .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"),
1088 .generic_poison => return writer.writeAll("(generic poison)"),
1086 }1089 }
1087 unreachable;1090 unreachable;
1088 }1091 }
1089 }1092 }
10901093
1094 /// Anything that reports hasCodeGenBits() false returns false here as well.
1095 pub fn requiresComptime(ty: Type) bool {
1096 return switch (ty.tag()) {
1097 .u1,
1098 .u8,
1099 .i8,
1100 .u16,
1101 .i16,
1102 .u32,
1103 .i32,
1104 .u64,
1105 .i64,
1106 .u128,
1107 .i128,
1108 .usize,
1109 .isize,
1110 .c_short,
1111 .c_ushort,
1112 .c_int,
1113 .c_uint,
1114 .c_long,
1115 .c_ulong,
1116 .c_longlong,
1117 .c_ulonglong,
1118 .c_longdouble,
1119 .f16,
1120 .f32,
1121 .f64,
1122 .f128,
1123 .c_void,
1124 .bool,
1125 .void,
1126 .anyerror,
1127 .noreturn,
1128 .@"anyframe",
1129 .@"null",
1130 .@"undefined",
1131 .atomic_ordering,
1132 .atomic_rmw_op,
1133 .calling_convention,
1134 .float_mode,
1135 .reduce_op,
1136 .call_options,
1137 .export_options,
1138 .extern_options,
1139 .manyptr_u8,
1140 .manyptr_const_u8,
1141 .fn_noreturn_no_args,
1142 .fn_void_no_args,
1143 .fn_naked_noreturn_no_args,
1144 .fn_ccc_void_no_args,
1145 .single_const_pointer_to_comptime_int,
1146 .const_slice_u8,
1147 .anyerror_void_error_union,
1148 .empty_struct_literal,
1149 .function,
1150 .empty_struct,
1151 .error_set,
1152 .error_set_single,
1153 .error_set_inferred,
1154 .@"opaque",
1155 => false,
1156
1157 .type,
1158 .comptime_int,
1159 .comptime_float,
1160 .enum_literal,
1161 => true,
1162
1163 .var_args_param => unreachable,
1164 .inferred_alloc_mut => unreachable,
1165 .inferred_alloc_const => unreachable,
1166 .generic_poison => unreachable,
1167
1168 .array_u8,
1169 .array_u8_sentinel_0,
1170 .array,
1171 .array_sentinel,
1172 .vector,
1173 .pointer,
1174 .single_const_pointer,
1175 .single_mut_pointer,
1176 .many_const_pointer,
1177 .many_mut_pointer,
1178 .c_const_pointer,
1179 .c_mut_pointer,
1180 .const_slice,
1181 .mut_slice,
1182 .int_signed,
1183 .int_unsigned,
1184 .optional,
1185 .optional_single_mut_pointer,
1186 .optional_single_const_pointer,
1187 .error_union,
1188 .anyframe_T,
1189 .@"struct",
1190 .@"union",
1191 .union_tagged,
1192 .enum_simple,
1193 .enum_full,
1194 .enum_nonexhaustive,
1195 => false, // TODO some of these should be `true` depending on their child types
1196 };
1197 }
1198
1091 pub fn toValue(self: Type, allocator: *Allocator) Allocator.Error!Value {1199 pub fn toValue(self: Type, allocator: *Allocator) Allocator.Error!Value {
1092 switch (self.tag()) {1200 switch (self.tag()) {
1093 .u1 => return Value.initTag(.u1_type),1201 .u1 => return Value.initTag(.u1_type),
...@@ -1287,6 +1395,7 @@ pub const Type = extern union {...@@ -1287,6 +1395,7 @@ pub const Type = extern union {
1287 .inferred_alloc_const => unreachable,1395 .inferred_alloc_const => unreachable,
1288 .inferred_alloc_mut => unreachable,1396 .inferred_alloc_mut => unreachable,
1289 .var_args_param => unreachable,1397 .var_args_param => unreachable,
1398 .generic_poison => unreachable,
1290 };1399 };
1291 }1400 }
12921401
...@@ -1509,6 +1618,8 @@ pub const Type = extern union {...@@ -1509,6 +1618,8 @@ pub const Type = extern union {
1509 .@"opaque",1618 .@"opaque",
1510 .var_args_param,1619 .var_args_param,
1511 => unreachable,1620 => unreachable,
1621
1622 .generic_poison => unreachable,
1512 };1623 };
1513 }1624 }
15141625
...@@ -1536,6 +1647,7 @@ pub const Type = extern union {...@@ -1536,6 +1647,7 @@ pub const Type = extern union {
1536 .inferred_alloc_mut => unreachable,1647 .inferred_alloc_mut => unreachable,
1537 .@"opaque" => unreachable,1648 .@"opaque" => unreachable,
1538 .var_args_param => unreachable,1649 .var_args_param => unreachable,
1650 .generic_poison => unreachable,
15391651
1540 .@"struct" => {1652 .@"struct" => {
1541 const s = self.castTag(.@"struct").?.data;1653 const s = self.castTag(.@"struct").?.data;
...@@ -1702,6 +1814,7 @@ pub const Type = extern union {...@@ -1702,6 +1814,7 @@ pub const Type = extern union {
1702 .inferred_alloc_mut => unreachable,1814 .inferred_alloc_mut => unreachable,
1703 .@"opaque" => unreachable,1815 .@"opaque" => unreachable,
1704 .var_args_param => unreachable,1816 .var_args_param => unreachable,
1817 .generic_poison => unreachable,
17051818
1706 .@"struct" => {1819 .@"struct" => {
1707 @panic("TODO bitSize struct");1820 @panic("TODO bitSize struct");
...@@ -2626,6 +2739,7 @@ pub const Type = extern union {...@@ -2626,6 +2739,7 @@ pub const Type = extern union {
26262739
2627 .inferred_alloc_const => unreachable,2740 .inferred_alloc_const => unreachable,
2628 .inferred_alloc_mut => unreachable,2741 .inferred_alloc_mut => unreachable,
2742 .generic_poison => unreachable,
2629 };2743 };
2630 }2744 }
26312745
...@@ -3039,6 +3153,7 @@ pub const Type = extern union {...@@ -3039,6 +3153,7 @@ pub const Type = extern union {
3039 single_const_pointer_to_comptime_int,3153 single_const_pointer_to_comptime_int,
3040 const_slice_u8,3154 const_slice_u8,
3041 anyerror_void_error_union,3155 anyerror_void_error_union,
3156 generic_poison,
3042 /// This is a special type for variadic parameters of a function call.3157 /// This is a special type for variadic parameters of a function call.
3043 /// Casts to it will validate that the type can be passed to a c calling convetion function.3158 /// Casts to it will validate that the type can be passed to a c calling convetion function.
3044 var_args_param,3159 var_args_param,
...@@ -3136,6 +3251,7 @@ pub const Type = extern union {...@@ -3136,6 +3251,7 @@ pub const Type = extern union {
3136 .single_const_pointer_to_comptime_int,3251 .single_const_pointer_to_comptime_int,
3137 .anyerror_void_error_union,3252 .anyerror_void_error_union,
3138 .const_slice_u8,3253 .const_slice_u8,
3254 .generic_poison,
3139 .inferred_alloc_const,3255 .inferred_alloc_const,
3140 .inferred_alloc_mut,3256 .inferred_alloc_mut,
3141 .var_args_param,3257 .var_args_param,
src/value.zig+15-40
...@@ -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
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;