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) {
195195 none_or_ref,
196196 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
197197 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,
198201 /// The expression must store its result into this typed pointer. The result instruction
199202 /// from the expression must be ignored.
200203 ptr: Zir.Inst.Ref,
......@@ -225,7 +228,7 @@ pub const ResultLoc = union(enum) {
225228 fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy {
226229 switch (rl) {
227230 // 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 .{
229232 .tag = .break_operand,
230233 .elide_store_to_block_ptr_instructions = false,
231234 },
......@@ -260,13 +263,14 @@ pub const ResultLoc = union(enum) {
260263pub const align_rl: ResultLoc = .{ .ty = .u16_type };
261264pub const bool_rl: ResultLoc = .{ .ty = .bool_type };
262265pub const type_rl: ResultLoc = .{ .ty = .type_type };
266pub const coerced_type_rl: ResultLoc = .{ .coerced_ty = .type_type };
263267
264268fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref {
265269 const prev_force_comptime = gz.force_comptime;
266270 gz.force_comptime = true;
267271 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);
270274}
271275
272276/// Same as `expr` but fails with a compile error if the result type is `noreturn`.
......@@ -1079,16 +1083,19 @@ fn fnProtoExpr(
10791083 .param_anytype;
10801084 _ = try gz.addStrTok(tag, param_name, name_token);
10811085 } else {
1086 const gpa = astgen.gpa;
10821087 const param_type_node = param.type_expr;
10831088 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);
10851094 const main_tokens = tree.nodes.items(.main_token);
10861095 const name_token = param.name_token orelse main_tokens[param_type_node];
10871096 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
1088 _ = try gz.addPlTok(tag, name_token, Zir.Inst.Param{
1089 .name = param_name,
1090 .ty = param_type,
1091 });
1097 const param_inst = try gz.addParam(tag, name_token, param_name, param_gz.instructions.items);
1098 assert(param_inst_expected == param_inst);
10921099 }
10931100 }
10941101 break :is_var_args false;
......@@ -1219,7 +1226,7 @@ fn arrayInitExpr(
12191226 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
12201227 }
12211228 },
1222 .ty => |ty_inst| {
1229 .ty, .coerced_ty => |ty_inst| {
12231230 if (types.array != .none) {
12241231 const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, .array_init);
12251232 return rvalue(gz, rl, result, node);
......@@ -1388,7 +1395,7 @@ fn structInitExpr(
13881395 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon);
13891396 }
13901397 },
1391 .ty => |ty_inst| {
1398 .ty, .coerced_ty => |ty_inst| {
13921399 if (struct_init.ast.type_expr == 0) {
13931400 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
13941401 }
......@@ -2617,7 +2624,7 @@ fn assignOp(
26172624 const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
26182625 const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);
26192626 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
26222629 const result = try gz.addPlNode(op_inst_tag, infix_node, Zir.Inst.Bin{
26232630 .lhs = lhs,
......@@ -2953,14 +2960,18 @@ fn fnDecl(
29532960 } else param: {
29542961 const param_type_node = param.type_expr;
29552962 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
29572969 const main_tokens = tree.nodes.items(.main_token);
29582970 const name_token = param.name_token orelse main_tokens[param_type_node];
29592971 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{
2961 .name = param_name,
2962 .ty = param_type,
2963 });
2972 const param_inst = try decl_gz.addParam(tag, name_token, param_name, param_gz.instructions.items);
2973 assert(param_inst_expected == param_inst);
2974 break :param indexToRef(param_inst);
29642975 };
29652976
29662977 if (param_name == 0) continue;
......@@ -6758,7 +6769,7 @@ fn as(
67586769) InnerError!Zir.Inst.Ref {
67596770 const dest_type = try typeExpr(gz, scope, lhs);
67606771 switch (rl) {
6761 .none, .none_or_ref, .discard, .ref, .ty => {
6772 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty => {
67626773 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);
67636774 return rvalue(gz, rl, result, node);
67646775 },
......@@ -6781,7 +6792,7 @@ fn unionInit(
67816792 const union_type = try typeExpr(gz, scope, params[0]);
67826793 const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
67836794 switch (rl) {
6784 .none, .none_or_ref, .discard, .ref, .ty, .inferred_ptr => {
6795 .none, .none_or_ref, .discard, .ref, .ty, .coerced_ty, .inferred_ptr => {
67856796 _ = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{
67866797 .container_type = union_type,
67876798 .field_name = field_name,
......@@ -6867,7 +6878,7 @@ fn bitCast(
68676878 const astgen = gz.astgen;
68686879 const dest_type = try typeExpr(gz, scope, lhs);
68696880 switch (rl) {
6870 .none, .none_or_ref, .discard, .ty => {
6881 .none, .none_or_ref, .discard, .ty, .coerced_ty => {
68716882 const operand = try expr(gz, scope, .none, rhs);
68726883 const result = try gz.addPlNode(.bitcast, node, Zir.Inst.Bin{
68736884 .lhs = dest_type,
......@@ -7677,7 +7688,7 @@ fn callExpr(
76777688 .param_index = @intCast(u32, i),
76787689 } },
76797690 });
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);
76817692 }
76827693
76837694 const modifier: std.builtin.CallOptions.Modifier = blk: {
......@@ -8370,7 +8381,7 @@ fn rvalue(
83708381 src_node: ast.Node.Index,
83718382) InnerError!Zir.Inst.Ref {
83728383 switch (rl) {
8373 .none, .none_or_ref => return result,
8384 .none, .none_or_ref, .coerced_ty => return result,
83748385 .discard => {
83758386 // Emit a compile error for discarding error values.
83768387 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
......@@ -9042,7 +9053,7 @@ const GenZir = struct {
90429053 // we emit ZIR for the block break instructions to have the result values,
90439054 // and then rvalue() on that to pass the value to the result location.
90449055 switch (parent_rl) {
9045 .ty => |ty_inst| {
9056 .ty, .coerced_ty => |ty_inst| {
90469057 gz.rl_ty_inst = ty_inst;
90479058 gz.break_result_loc = parent_rl;
90489059 },
......@@ -9425,18 +9436,26 @@ const GenZir = struct {
94259436 return indexToRef(new_index);
94269437 }
94279438
9428 fn addPlTok(
9439 fn addParam(
94299440 gz: *GenZir,
94309441 tag: Zir.Inst.Tag,
94319442 /// Absolute token index. This function does the conversion to Decl offset.
94329443 abs_tok_index: ast.TokenIndex,
9433 extra: anytype,
9434 ) !Zir.Inst.Ref {
9444 name: u32,
9445 body: []const u32,
9446 ) !Zir.Inst.Index {
94359447 const gpa = gz.astgen.gpa;
94369448 try gz.instructions.ensureUnusedCapacity(gpa, 1);
94379449 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);
94409459 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
94419460 gz.astgen.instructions.appendAssumeCapacity(.{
94429461 .tag = tag,
......@@ -9446,7 +9465,7 @@ const GenZir = struct {
94469465 } },
94479466 });
94489467 gz.instructions.appendAssumeCapacity(new_index);
9449 return indexToRef(new_index);
9468 return new_index;
94509469 }
94519470
94529471 fn addExtendedPayload(
src/Compilation.zig+1-1
......@@ -2118,7 +2118,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
21182118 if (builtin.mode == .Debug and self.verbose_air) {
21192119 std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});
21202120 @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});
21222122 }
21232123
21242124 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 {
11731173 /// for the one that will be the same for all Block instances.
11741174 src_decl: *Decl,
11751175 instructions: ArrayListUnmanaged(Air.Inst.Index),
1176 // `param` instructions are collected here to be used by the `func` instruction.
1177 params: std.ArrayListUnmanaged(Param) = .{},
11761178 label: ?*Label = null,
11771179 inlining: ?*Inlining,
11781180 /// If runtime_index is not 0 then one of these is guaranteed to be non null.
......@@ -1187,6 +1189,12 @@ pub const Scope = struct {
11871189 /// when null, it is determined by build mode, changed by @setRuntimeSafety
11881190 want_safety: ?bool = null,
11891191
1192 const Param = struct {
1193 /// `noreturn` means `anytype`.
1194 ty: Type,
1195 is_comptime: bool,
1196 };
1197
11901198 /// This `Block` maps a block ZIR instruction to the corresponding
11911199 /// AIR instruction for break instruction analysis.
11921200 pub const Label = struct {
......@@ -1634,8 +1642,11 @@ pub const SrcLoc = struct {
16341642 .@"asm" => tree.asmFull(node),
16351643 else => unreachable,
16361644 };
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;
16371648 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];
16391650 const token_starts = tree.tokens.items(.start);
16401651 return token_starts[tok_index];
16411652 },
......@@ -2099,7 +2110,20 @@ pub const LazySrcLoc = union(enum) {
20992110};
21002111
21012112pub 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
21042128pub fn deinit(mod: *Module) void {
21052129 const gpa = mod.gpa;
......@@ -2796,14 +2820,16 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) SemaError!void {
27962820 }
27972821 return error.AnalysisFail;
27982822 },
2799 else => {
2823 error.NeededSourceLocation => unreachable,
2824 error.GenericPoison => unreachable,
2825 else => |e| {
28002826 decl.analysis = .sema_failure_retryable;
28012827 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
28022828 mod.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
28032829 mod.gpa,
28042830 decl.srcLoc(),
28052831 "unable to analyze: {s}",
2806 .{@errorName(err)},
2832 .{@errorName(e)},
28072833 ));
28082834 return error.AnalysisFail;
28092835 },
......@@ -2982,7 +3008,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
29823008 .inlining = null,
29833009 .is_comptime = true,
29843010 };
2985 defer block_scope.instructions.deinit(gpa);
3011 defer {
3012 block_scope.instructions.deinit(gpa);
3013 block_scope.params.deinit(gpa);
3014 }
29863015
29873016 const zir_block_index = decl.zirBlockIndex();
29883017 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 {
36693698 try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType`
36703699 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;
36733703 for (fn_info.param_body) |inst| {
36743704 const name = switch (zir_tags[inst]) {
36753705 .param, .param_comptime => blk: {
......@@ -3686,16 +3716,16 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
36863716 else => continue,
36873717 };
36883718 if (func.comptime_args) |comptime_args| {
3689 const arg_tv = comptime_args[param_index];
3719 const arg_tv = comptime_args[total_param_index];
36903720 if (arg_tv.val.tag() != .unreachable_value) {
36913721 // We have a comptime value for this parameter.
36923722 const arg = try sema.addConstant(arg_tv.ty, arg_tv.val);
36933723 sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
3694 param_index += 1;
3724 total_param_index += 1;
36953725 continue;
36963726 }
36973727 }
3698 const param_type = fn_ty.fnParamType(param_index);
3728 const param_type = fn_ty.fnParamType(runtime_param_index);
36993729 const ty_ref = try sema.addType(param_type);
37003730 const arg_index = @intCast(u32, sema.air_instructions.len);
37013731 inner_block.instructions.appendAssumeCapacity(arg_index);
......@@ -3707,7 +3737,8 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
37073737 } },
37083738 });
37093739 sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index));
3710 param_index += 1;
3740 total_param_index += 1;
3741 runtime_param_index += 1;
37113742 }
37123743
37133744 func.state = .in_progress;
......@@ -3715,6 +3746,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
37153746
37163747 _ = sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {
37173748 error.NeededSourceLocation => unreachable,
3749 error.GenericPoison => unreachable,
37183750 else => |e| return e,
37193751 };
37203752
src/Sema.zig+267-161
......@@ -37,13 +37,15 @@ branch_count: u32 = 0,
3737/// contain a mapped source location.
3838src: LazySrcLoc = .{ .token_offset = 0 },
3939decl_val_table: std.AutoHashMapUnmanaged(*Decl, Air.Inst.Ref) = .{},
40/// `param` instructions are collected here to be used by the `func` instruction.
41params: std.ArrayListUnmanaged(Param) = .{},
42/// When doing a generic function instantiation, this array collects a `Value` object for
43/// each parameter that is comptime known and thus elided from the generated function.
44/// This memory is allocated by a parent `Sema` and owned by the values arena of the owner_decl.
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.
4544comptime_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
4850const std = @import("std");
4951const mem = std.mem;
......@@ -67,13 +69,6 @@ const LazySrcLoc = Module.LazySrcLoc;
6769const RangeSet = @import("RangeSet.zig");
6870const 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
7772pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);
7873
7974pub fn deinit(sema: *Sema) void {
......@@ -83,7 +78,6 @@ pub fn deinit(sema: *Sema) void {
8378 sema.air_values.deinit(gpa);
8479 sema.inst_map.deinit(gpa);
8580 sema.decl_val_table.deinit(gpa);
86 sema.params.deinit(gpa);
8781 sema.* = undefined;
8882}
8983
......@@ -466,6 +460,26 @@ pub fn analyzeBody(
466460 i += 1;
467461 continue;
468462 },
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
470484 // Special case instructions to handle comptime control flow.
471485 .repeat_inline => {
......@@ -504,88 +518,6 @@ pub fn analyzeBody(
504518 return break_inst;
505519 }
506520 },
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 },
589521 };
590522 if (sema.typeOf(air_inst).isNoReturn())
591523 return always_noreturn;
......@@ -697,6 +629,7 @@ fn resolveValue(
697629 air_ref: Air.Inst.Ref,
698630) CompileError!Value {
699631 if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {
632 if (val.tag() == .generic_poison) return error.GenericPoison;
700633 return val;
701634 }
702635 return sema.failWithNeededComptime(block, src);
......@@ -714,6 +647,7 @@ fn resolveConstValue(
714647 switch (val.tag()) {
715648 .undef => return sema.failWithUseOfUndef(block, src),
716649 .variable => return sema.failWithNeededComptime(block, src),
650 .generic_poison => return error.GenericPoison,
717651 else => return val,
718652 }
719653 }
......@@ -2422,7 +2356,7 @@ fn analyzeCall(
24222356 call_src: LazySrcLoc,
24232357 modifier: std.builtin.CallOptions.Modifier,
24242358 ensure_result_used: bool,
2425 args: []const Air.Inst.Ref,
2359 uncasted_args: []const Air.Inst.Ref,
24262360) CompileError!Air.Inst.Ref {
24272361 const mod = sema.mod;
24282362
......@@ -2444,22 +2378,22 @@ fn analyzeCall(
24442378 const fn_params_len = func_ty_info.param_types.len;
24452379 if (func_ty_info.is_var_args) {
24462380 assert(cc == .C);
2447 if (args.len < fn_params_len) {
2381 if (uncasted_args.len < fn_params_len) {
24482382 // TODO add error note: declared here
24492383 return mod.fail(
24502384 &block.base,
24512385 func_src,
24522386 "expected at least {d} argument(s), found {d}",
2453 .{ fn_params_len, args.len },
2387 .{ fn_params_len, uncasted_args.len },
24542388 );
24552389 }
2456 } else if (fn_params_len != args.len) {
2390 } else if (fn_params_len != uncasted_args.len) {
24572391 // TODO add error note: declared here
24582392 return mod.fail(
24592393 &block.base,
24602394 func_src,
24612395 "expected {d} argument(s), found {d}",
2462 .{ fn_params_len, args.len },
2396 .{ fn_params_len, uncasted_args.len },
24632397 );
24642398 }
24652399
......@@ -2485,6 +2419,14 @@ fn analyzeCall(
24852419 const is_inline_call = is_comptime_call or modifier == .always_inline or
24862420 func_ty_info.cc == .Inline;
24872421 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
24882430 const func_val = try sema.resolveConstValue(block, func_src, func);
24892431 const module_fn = switch (func_val.tag()) {
24902432 .function => func_val.castTag(.function).?.data,
......@@ -2574,13 +2516,12 @@ fn analyzeCall(
25742516 const func_val = try sema.resolveConstValue(block, func_src, func);
25752517 const module_fn = func_val.castTag(.function).?.data;
25762518 // 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 Scope
2578 // only to junk it if it matches an existing instantiation.
2519 // can match against `uncasted_args` rather than doing the work below to create a
2520 // generic Scope only to junk it if it matches an existing instantiation.
25792521 // TODO
25802522
25812523 const fn_info = sema.code.getFnInfo(module_fn.zir_body_inst);
25822524 const zir_tags = sema.code.instructions.items(.tag);
2583 var non_comptime_args_len: u32 = 0;
25842525 const new_func = new_func: {
25852526 const namespace = module_fn.owner_decl.namespace;
25862527 try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);
......@@ -2622,7 +2563,8 @@ fn analyzeCall(
26222563 .namespace = namespace,
26232564 .func = null,
26242565 .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,
26262568 };
26272569 defer child_sema.deinit();
26282570
......@@ -2634,41 +2576,59 @@ fn analyzeCall(
26342576 .inlining = null,
26352577 .is_comptime = true,
26362578 };
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));
26402585 var arg_i: usize = 0;
26412586 for (fn_info.param_body) |inst| {
26422587 const is_comptime = switch (zir_tags[inst]) {
26432588 .param_comptime, .param_anytype_comptime => true,
2644 .param, .param_anytype => false, // TODO make true for always comptime types
2589 .param, .param_anytype => false,
26452590 else => continue,
26462591 };
2647 if (is_comptime) {
2648 // TODO: pass .unneeded to resolveConstValue and then if we get
2649 // error.NeededSourceLocation resolve the arg source location and
2650 // try again.
2651 const arg_src = call_src;
2652 const arg = args[arg_i];
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 };
2592 // TODO: pass .unneeded to resolveConstValue and then if we get
2593 // error.NeededSourceLocation resolve the arg source location and
2594 // try again.
2595 const arg_src = call_src;
2596 const arg = uncasted_args[arg_i];
2597 if (try sema.resolveMaybeUndefVal(block, arg_src, arg)) |arg_val| {
26582598 const child_arg = try child_sema.addConstant(sema.typeOf(arg), arg_val);
26592599 child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
2660 } else {
2661 non_comptime_args_len += 1;
2600 } else if (is_comptime) {
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) {
26622619 child_sema.comptime_args[arg_i] = .{
26632620 .ty = Type.initTag(.noreturn),
26642621 .val = Value.initTag(.unreachable_value),
26652622 };
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 };
26662628 }
2629
26672630 arg_i += 1;
26682631 }
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
26732633 // Populate the Decl ty/val with the function and its type.
26742634 new_decl.ty = try child_sema.typeOf(new_func_inst).copy(&new_decl_arena.allocator);
......@@ -2690,31 +2650,72 @@ fn analyzeCall(
26902650
26912651 // Make a runtime call to the new function, making sure to omit the comptime args.
26922652 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 }
26932694 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
2694 non_comptime_args_len);
2695 runtime_args_len);
26952696 const func_inst = try block.addInst(.{
26962697 .tag = .call,
26972698 .data = .{ .pl_op = .{
26982699 .operand = new_func,
26992700 .payload = sema.addExtraAssumeCapacity(Air.Call{
2700 .args_len = non_comptime_args_len,
2701 .args_len = runtime_args_len,
27012702 }),
27022703 } },
27032704 });
2704 var arg_i: usize = 0;
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 }
2705 sema.appendRefsAssumeCapacity(runtime_args);
27162706 break :res func_inst;
27172707 } 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
27182719 try sema.requireRuntimeBlock(block, call_src);
27192720 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
27202721 args.len);
......@@ -3416,7 +3417,7 @@ fn funcCommon(
34163417
34173418 const fn_ty: Type = fn_ty: {
34183419 // Hot path for some common function types.
3419 if (sema.params.items.len == 0 and !var_args and align_val.tag() == .null_value and
3420 if (block.params.items.len == 0 and !var_args and align_val.tag() == .null_value and
34203421 !inferred_error_set)
34213422 {
34223423 if (bare_return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
......@@ -3436,19 +3437,15 @@ fn funcCommon(
34363437 }
34373438 }
34383439
3439 var any_are_comptime = false;
3440 const param_types = try sema.arena.alloc(Type, sema.params.items.len);
3441 const comptime_params = try sema.arena.alloc(bool, sema.params.items.len);
3442 for (sema.params.items) |param, i| {
3443 if (param.ty.tag() == .noreturn) {
3444 param_types[i] = Type.initTag(.noreturn); // indicates anytype
3445 } else {
3446 param_types[i] = param.ty;
3447 }
3440 var is_generic = false;
3441 const param_types = try sema.arena.alloc(Type, block.params.items.len);
3442 const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
3443 for (block.params.items) |param, i| {
3444 param_types[i] = param.ty;
34483445 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();
34503448 }
3451 sema.params.clearRetainingCapacity();
34523449
34533450 if (align_val.tag() != .null_value) {
34543451 return mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
......@@ -3471,7 +3468,7 @@ fn funcCommon(
34713468 .return_type = return_type,
34723469 .cc = cc,
34733470 .is_var_args = var_args,
3474 .is_generic = any_are_comptime,
3471 .is_generic = is_generic,
34753472 });
34763473 };
34773474
......@@ -3530,12 +3527,16 @@ fn funcCommon(
35303527 const is_inline = fn_ty.fnCallingConvention() == .Inline;
35313528 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
35333534 const fn_payload = try sema.arena.create(Value.Payload.Function);
35343535 new_func.* = .{
35353536 .state = anal_state,
35363537 .zir_body_inst = body_inst,
35373538 .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,
35393540 .lbrace_line = src_locs.lbrace_line,
35403541 .rbrace_line = src_locs.rbrace_line,
35413542 .lbrace_column = @truncate(u16, src_locs.columns),
......@@ -3548,6 +3549,113 @@ fn funcCommon(
35483549 return sema.addConstant(fn_ty, Value.initPayload(&fn_payload.base));
35493550}
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
35513659fn zirAs(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
35523660 const tracy = trace(@src());
35533661 defer tracy.end();
......@@ -7618,8 +7726,10 @@ fn coerce(
76187726 inst: Air.Inst.Ref,
76197727 inst_src: LazySrcLoc,
76207728) CompileError!Air.Inst.Ref {
7621 if (dest_type_unresolved.tag() == .var_args_param) {
7622 return sema.coerceVarArgParam(block, inst, inst_src);
7729 switch (dest_type_unresolved.tag()) {
7730 .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src),
7731 .generic_poison => return inst,
7732 else => {},
76237733 }
76247734 const dest_type_src = inst_src; // TODO better source location
76257735 const dest_type = try sema.resolveTypeFields(block, dest_type_src, dest_type_unresolved);
......@@ -8820,6 +8930,7 @@ fn typeHasOnePossibleValue(
88208930
88218931 .inferred_alloc_const => unreachable,
88228932 .inferred_alloc_mut => unreachable,
8933 .generic_poison => unreachable,
88238934 };
88248935}
88258936
......@@ -8942,6 +9053,8 @@ pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
89429053 .fn_ccc_void_no_args => return .fn_ccc_void_no_args_type,
89439054 .single_const_pointer_to_comptime_int => return .single_const_pointer_to_comptime_int_type,
89449055 .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,
89459058 else => {},
89469059 }
89479060 try sema.air_instructions.append(sema.gpa, .{
......@@ -9015,10 +9128,3 @@ fn isComptimeKnown(
90159128) !bool {
90169129 return (try sema.resolveMaybeUndefVal(block, src, inst)) != null;
90179130}
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 {
17041704 fn_ccc_void_no_args_type,
17051705 single_const_pointer_to_comptime_int_type,
17061706 const_slice_u8_type,
1707 anyerror_void_error_union_type,
1708 generic_poison_type,
17071709
17081710 /// `undefined` (untyped)
17091711 undef,
......@@ -1731,6 +1733,9 @@ pub const Inst = struct {
17311733 calling_convention_c,
17321734 /// `std.builtin.CallingConvention.Inline`
17331735 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
17351740 _,
17361741
......@@ -1909,6 +1914,14 @@ pub const Inst = struct {
19091914 .ty = Type.initTag(.type),
19101915 .val = Value.initTag(.const_slice_u8_type),
19111916 },
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 },
19121925 .enum_literal_type = .{
19131926 .ty = Type.initTag(.type),
19141927 .val = Value.initTag(.enum_literal_type),
......@@ -2006,6 +2019,10 @@ pub const Inst = struct {
20062019 .ty = Type.initTag(.calling_convention),
20072020 .val = .{ .ptr_otherwise = &calling_convention_inline_payload.base },
20082021 },
2022 .generic_poison = .{
2023 .ty = Type.initTag(.generic_poison),
2024 .val = Value.initTag(.generic_poison),
2025 },
20092026 });
20102027 };
20112028
......@@ -2787,10 +2804,12 @@ pub const Inst = struct {
27872804 args: Ref,
27882805 };
27892806
2807 /// Trailing: inst: Index // for every body_len
27902808 pub const Param = struct {
27912809 /// Null-terminated string index.
27922810 name: u32,
2793 ty: Ref,
2811 /// The body contains the type of the parameter.
2812 body_len: u32,
27942813 };
27952814
27962815 /// Trailing:
......@@ -3348,11 +3367,16 @@ const Writer = struct {
33483367
33493368 fn writeParam(self: *Writer, stream: anytype, inst: Inst.Index) !void {
33503369 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];
33523372 try stream.print("\"{}\", ", .{
3353 std.zig.fmtEscapes(self.code.nullTerminatedString(extra.name)),
3373 std.zig.fmtEscapes(self.code.nullTerminatedString(extra.data.name)),
33543374 });
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);
33563380 try stream.writeAll(") ");
33573381 try self.writeSrc(stream, inst_data.src());
33583382 }
src/codegen/llvm.zig+4
......@@ -839,6 +839,10 @@ pub const DeclGen = struct {
839839 .False,
840840 );
841841 },
842 .ComptimeInt => unreachable,
843 .ComptimeFloat => unreachable,
844 .Type => unreachable,
845 .EnumLiteral => unreachable,
842846 else => return self.todo("implement const of type '{}'", .{tv.ty}),
843847 }
844848 }
src/type.zig+116
......@@ -130,6 +130,7 @@ pub const Type = extern union {
130130 => return .Union,
131131
132132 .var_args_param => unreachable, // can be any type
133 .generic_poison => unreachable, // must be handled earlier
133134 }
134135 }
135136
......@@ -699,6 +700,7 @@ pub const Type = extern union {
699700 .export_options,
700701 .extern_options,
701702 .@"anyframe",
703 .generic_poison,
702704 => unreachable,
703705
704706 .array_u8,
......@@ -1083,11 +1085,117 @@ pub const Type = extern union {
10831085 },
10841086 .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"),
10851087 .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"),
1088 .generic_poison => return writer.writeAll("(generic poison)"),
10861089 }
10871090 unreachable;
10881091 }
10891092 }
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
10911199 pub fn toValue(self: Type, allocator: *Allocator) Allocator.Error!Value {
10921200 switch (self.tag()) {
10931201 .u1 => return Value.initTag(.u1_type),
......@@ -1287,6 +1395,7 @@ pub const Type = extern union {
12871395 .inferred_alloc_const => unreachable,
12881396 .inferred_alloc_mut => unreachable,
12891397 .var_args_param => unreachable,
1398 .generic_poison => unreachable,
12901399 };
12911400 }
12921401
......@@ -1509,6 +1618,8 @@ pub const Type = extern union {
15091618 .@"opaque",
15101619 .var_args_param,
15111620 => unreachable,
1621
1622 .generic_poison => unreachable,
15121623 };
15131624 }
15141625
......@@ -1536,6 +1647,7 @@ pub const Type = extern union {
15361647 .inferred_alloc_mut => unreachable,
15371648 .@"opaque" => unreachable,
15381649 .var_args_param => unreachable,
1650 .generic_poison => unreachable,
15391651
15401652 .@"struct" => {
15411653 const s = self.castTag(.@"struct").?.data;
......@@ -1702,6 +1814,7 @@ pub const Type = extern union {
17021814 .inferred_alloc_mut => unreachable,
17031815 .@"opaque" => unreachable,
17041816 .var_args_param => unreachable,
1817 .generic_poison => unreachable,
17051818
17061819 .@"struct" => {
17071820 @panic("TODO bitSize struct");
......@@ -2626,6 +2739,7 @@ pub const Type = extern union {
26262739
26272740 .inferred_alloc_const => unreachable,
26282741 .inferred_alloc_mut => unreachable,
2742 .generic_poison => unreachable,
26292743 };
26302744 }
26312745
......@@ -3039,6 +3153,7 @@ pub const Type = extern union {
30393153 single_const_pointer_to_comptime_int,
30403154 const_slice_u8,
30413155 anyerror_void_error_union,
3156 generic_poison,
30423157 /// This is a special type for variadic parameters of a function call.
30433158 /// Casts to it will validate that the type can be passed to a c calling convetion function.
30443159 var_args_param,
......@@ -3136,6 +3251,7 @@ pub const Type = extern union {
31363251 .single_const_pointer_to_comptime_int,
31373252 .anyerror_void_error_union,
31383253 .const_slice_u8,
3254 .generic_poison,
31393255 .inferred_alloc_const,
31403256 .inferred_alloc_mut,
31413257 .var_args_param,
src/value.zig+15-40
......@@ -76,6 +76,8 @@ pub const Value = extern union {
7676 fn_ccc_void_no_args_type,
7777 single_const_pointer_to_comptime_int_type,
7878 const_slice_u8_type,
79 anyerror_void_error_union_type,
80 generic_poison_type,
7981
8082 undef,
8183 zero,
......@@ -85,6 +87,7 @@ pub const Value = extern union {
8587 null_value,
8688 bool_true,
8789 bool_false,
90 generic_poison,
8891
8992 abi_align_default,
9093 empty_struct_value,
......@@ -188,6 +191,8 @@ pub const Value = extern union {
188191 .single_const_pointer_to_comptime_int_type,
189192 .anyframe_type,
190193 .const_slice_u8_type,
194 .anyerror_void_error_union_type,
195 .generic_poison_type,
191196 .enum_literal_type,
192197 .undef,
193198 .zero,
......@@ -210,6 +215,7 @@ pub const Value = extern union {
210215 .call_options_type,
211216 .export_options_type,
212217 .extern_options_type,
218 .generic_poison,
213219 => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),
214220
215221 .int_big_positive,
......@@ -366,6 +372,8 @@ pub const Value = extern union {
366372 .single_const_pointer_to_comptime_int_type,
367373 .anyframe_type,
368374 .const_slice_u8_type,
375 .anyerror_void_error_union_type,
376 .generic_poison_type,
369377 .enum_literal_type,
370378 .undef,
371379 .zero,
......@@ -388,6 +396,7 @@ pub const Value = extern union {
388396 .call_options_type,
389397 .export_options_type,
390398 .extern_options_type,
399 .generic_poison,
391400 => unreachable,
392401
393402 .ty => {
......@@ -556,6 +565,9 @@ pub const Value = extern union {
556565 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
557566 .anyframe_type => return out_stream.writeAll("anyframe"),
558567 .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)"),
559571 .enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
560572 .manyptr_u8_type => return out_stream.writeAll("[*]u8"),
561573 .manyptr_const_u8_type => return out_stream.writeAll("[*]const u8"),
......@@ -709,6 +721,8 @@ pub const Value = extern union {
709721 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
710722 .anyframe_type => Type.initTag(.@"anyframe"),
711723 .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),
712726 .enum_literal_type => Type.initTag(.enum_literal),
713727 .manyptr_u8_type => Type.initTag(.manyptr_u8),
714728 .manyptr_const_u8_type => Type.initTag(.manyptr_const_u8),
......@@ -732,46 +746,7 @@ pub const Value = extern union {
732746 return Type.initPayload(&buffer.base);
733747 },
734748
735 .undef,
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,
749 else => unreachable,
775750 };
776751 }
777752
test/cases.zig+1-1
......@@ -1572,7 +1572,7 @@ pub fn addCases(ctx: *TestContext) !void {
15721572 \\ const x = asm volatile ("syscall"
15731573 \\ : [o] "{rax}" (-> number)
15741574 \\ : [number] "{rax}" (231),
1575 \\ [arg1] "{rdi}" (code)
1575 \\ [arg1] "{rdi}" (60)
15761576 \\ : "rcx", "r11", "memory"
15771577 \\ );
15781578 \\ _ = x;