authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-10-28 20:15:13+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-10-28 20:15:13+02:00
logbd32206b4449e329c9ef6ba4fd19746234f474f8
tree19dd0223be1ff7a95d8ad5b88811ac329fa8aa33
parentf28e4e03eeb622d1cfd391cf9f0c7e45f4d80681
parent6fc71835c3075aff4792b63bc38698cbe542f028
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13322 from Vexu/comptime-reason

Further enhance explanation of why expression is evaluated at comptime

8 files changed, 191 insertions(+), 73 deletions(-)

src/Sema.zig+115-70
...@@ -151,6 +151,8 @@ pub const Block = struct {...@@ -151,6 +151,8 @@ pub const Block = struct {
151 runtime_index: Value.RuntimeIndex = .zero,151 runtime_index: Value.RuntimeIndex = .zero,
152 inline_block: Zir.Inst.Index = 0,152 inline_block: Zir.Inst.Index = 0,
153153
154 comptime_reason: ?*const ComptimeReason = null,
155 // TODO is_comptime and comptime_reason should probably be merged together.
154 is_comptime: bool,156 is_comptime: bool,
155 is_typeof: bool = false,157 is_typeof: bool = false,
156 is_coerce_result_ptr: bool = false,158 is_coerce_result_ptr: bool = false,
...@@ -173,6 +175,49 @@ pub const Block = struct {...@@ -173,6 +175,49 @@ pub const Block = struct {
173 /// Value for switch_capture in an inline case175 /// Value for switch_capture in an inline case
174 inline_case_capture: Air.Inst.Ref = .none,176 inline_case_capture: Air.Inst.Ref = .none,
175177
178 const ComptimeReason = union(enum) {
179 c_import: struct {
180 block: *Block,
181 src: LazySrcLoc,
182 },
183 comptime_ret_ty: struct {
184 block: *Block,
185 func: Air.Inst.Ref,
186 func_src: LazySrcLoc,
187 return_ty: Type,
188 },
189
190 fn explain(cr: ComptimeReason, sema: *Sema, msg: ?*Module.ErrorMsg) !void {
191 const parent = msg orelse return;
192 const prefix = "expression is evaluated at comptime because ";
193 switch (cr) {
194 .c_import => |ci| {
195 try sema.errNote(ci.block, ci.src, parent, prefix ++ "it is inside a @cImport", .{});
196 },
197 .comptime_ret_ty => |rt| {
198 const src_loc = if (try sema.funcDeclSrc(rt.block, rt.func_src, rt.func)) |capture| blk: {
199 var src_loc = capture;
200 src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 };
201 break :blk src_loc;
202 } else blk: {
203 const src_decl = sema.mod.declPtr(rt.block.src_decl);
204 break :blk rt.func_src.toSrcLoc(src_decl);
205 };
206 if (rt.return_ty.tag() == .generic_poison) {
207 return sema.mod.errNoteNonLazy(src_loc, parent, prefix ++ "the generic function was instantiated with a comptime-only return type", .{});
208 }
209 try sema.mod.errNoteNonLazy(
210 src_loc,
211 parent,
212 prefix ++ "the function returns a comptime-only type '{}'",
213 .{rt.return_ty.fmt(sema.mod)},
214 );
215 try sema.explainWhyTypeIsComptime(rt.block, rt.func_src, parent, src_loc, rt.return_ty);
216 },
217 }
218 }
219 };
220
176 const Param = struct {221 const Param = struct {
177 /// `noreturn` means `anytype`.222 /// `noreturn` means `anytype`.
178 ty: Type,223 ty: Type,
...@@ -224,6 +269,7 @@ pub const Block = struct {...@@ -224,6 +269,7 @@ pub const Block = struct {
224 .label = null,269 .label = null,
225 .inlining = parent.inlining,270 .inlining = parent.inlining,
226 .is_comptime = parent.is_comptime,271 .is_comptime = parent.is_comptime,
272 .comptime_reason = parent.comptime_reason,
227 .is_typeof = parent.is_typeof,273 .is_typeof = parent.is_typeof,
228 .runtime_cond = parent.runtime_cond,274 .runtime_cond = parent.runtime_cond,
229 .runtime_loop = parent.runtime_loop,275 .runtime_loop = parent.runtime_loop,
...@@ -1420,7 +1466,10 @@ fn analyzeBodyInner(...@@ -1420,7 +1466,10 @@ fn analyzeBodyInner(
1420 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);1466 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
1421 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];1467 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
1422 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];1468 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
1423 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime-known");1469 const cond = sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime-known") catch |err| {
1470 if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
1471 return err;
1472 };
1424 const inline_body = if (cond.val.toBool()) then_body else else_body;1473 const inline_body = if (cond.val.toBool()) then_body else else_body;
14251474
1426 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);1475 try sema.maybeErrorUnwrapCondbr(block, inline_body, extra.data.condition, cond_src);
...@@ -1438,7 +1487,10 @@ fn analyzeBodyInner(...@@ -1438,7 +1487,10 @@ fn analyzeBodyInner(
1438 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);1487 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
1439 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];1488 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
1440 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];1489 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
1441 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime-known");1490 const cond = sema.resolveInstConst(block, cond_src, extra.data.condition, "condition in comptime branch must be comptime-known") catch |err| {
1491 if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
1492 return err;
1493 };
1442 const inline_body = if (cond.val.toBool()) then_body else else_body;1494 const inline_body = if (cond.val.toBool()) then_body else else_body;
1443 const old_runtime_index = block.runtime_index;1495 const old_runtime_index = block.runtime_index;
1444 defer block.runtime_index = old_runtime_index;1496 defer block.runtime_index = old_runtime_index;
...@@ -1460,7 +1512,10 @@ fn analyzeBodyInner(...@@ -1460,7 +1512,10 @@ fn analyzeBodyInner(
1460 const err_union = try sema.resolveInst(extra.data.operand);1512 const err_union = try sema.resolveInst(extra.data.operand);
1461 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);1513 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
1462 assert(is_non_err != .none);1514 assert(is_non_err != .none);
1463 const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known");1515 const is_non_err_tv = sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| {
1516 if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
1517 return err;
1518 };
1464 if (is_non_err_tv.val.toBool()) {1519 if (is_non_err_tv.val.toBool()) {
1465 const err_union_ty = sema.typeOf(err_union);1520 const err_union_ty = sema.typeOf(err_union);
1466 break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false);1521 break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false);
...@@ -1516,7 +1571,10 @@ fn analyzeBodyInner(...@@ -1516,7 +1571,10 @@ fn analyzeBodyInner(
1516 const err_union = try sema.analyzeLoad(block, src, operand, operand_src);1571 const err_union = try sema.analyzeLoad(block, src, operand, operand_src);
1517 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);1572 const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
1518 assert(is_non_err != .none);1573 assert(is_non_err != .none);
1519 const is_non_err_tv = try sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known");1574 const is_non_err_tv = sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| {
1575 if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
1576 return err;
1577 };
1520 if (is_non_err_tv.val.toBool()) {1578 if (is_non_err_tv.val.toBool()) {
1521 break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);1579 break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
1522 }1580 }
...@@ -1675,8 +1733,8 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)...@@ -1675,8 +1733,8 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
1675 return;1733 return;
1676 }1734 }
16771735
1736 assert(!block.is_comptime);
1678 var err_trace_block = block.makeSubBlock();1737 var err_trace_block = block.makeSubBlock();
1679 err_trace_block.is_comptime = false;
1680 defer err_trace_block.instructions.deinit(sema.gpa);1738 defer err_trace_block.instructions.deinit(sema.gpa);
16811739
1682 const src: LazySrcLoc = .unneeded;1740 const src: LazySrcLoc = .unneeded;
...@@ -4944,6 +5002,10 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -4944,6 +5002,10 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
4944 var c_import_buf = std.ArrayList(u8).init(sema.gpa);5002 var c_import_buf = std.ArrayList(u8).init(sema.gpa);
4945 defer c_import_buf.deinit();5003 defer c_import_buf.deinit();
49465004
5005 var comptime_reason = .{ .c_import = .{
5006 .block = parent_block,
5007 .src = src,
5008 } };
4947 var child_block: Block = .{5009 var child_block: Block = .{
4948 .parent = parent_block,5010 .parent = parent_block,
4949 .sema = sema,5011 .sema = sema,
...@@ -4952,7 +5014,8 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -4952,7 +5014,8 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
4952 .wip_capture_scope = parent_block.wip_capture_scope,5014 .wip_capture_scope = parent_block.wip_capture_scope,
4953 .instructions = .{},5015 .instructions = .{},
4954 .inlining = parent_block.inlining,5016 .inlining = parent_block.inlining,
4955 .is_comptime = parent_block.is_comptime,5017 .is_comptime = true,
5018 .comptime_reason = &comptime_reason,
4956 .c_import_buf = &c_import_buf,5019 .c_import_buf = &c_import_buf,
4957 .runtime_cond = parent_block.runtime_cond,5020 .runtime_cond = parent_block.runtime_cond,
4958 .runtime_loop = parent_block.runtime_loop,5021 .runtime_loop = parent_block.runtime_loop,
...@@ -5053,6 +5116,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -5053,6 +5116,7 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErro
5053 .label = &label,5116 .label = &label,
5054 .inlining = parent_block.inlining,5117 .inlining = parent_block.inlining,
5055 .is_comptime = parent_block.is_comptime,5118 .is_comptime = parent_block.is_comptime,
5119 .comptime_reason = parent_block.comptime_reason,
5056 .is_typeof = parent_block.is_typeof,5120 .is_typeof = parent_block.is_typeof,
5057 .want_safety = parent_block.want_safety,5121 .want_safety = parent_block.want_safety,
5058 .float_mode = parent_block.float_mode,5122 .float_mode = parent_block.float_mode,
...@@ -5926,6 +5990,7 @@ fn zirCall(...@@ -5926,6 +5990,7 @@ fn zirCall(
5926 defer block.is_comptime = parent_comptime;5990 defer block.is_comptime = parent_comptime;
5927 if (arg_index < fn_params_len and func_ty_info.comptime_params[arg_index]) {5991 if (arg_index < fn_params_len and func_ty_info.comptime_params[arg_index]) {
5928 block.is_comptime = true;5992 block.is_comptime = true;
5993 // TODO set comptime_reason
5929 }5994 }
59305995
5931 const param_ty_inst = try sema.addType(param_ty);5996 const param_ty_inst = try sema.addType(param_ty);
...@@ -6056,37 +6121,6 @@ const GenericCallAdapter = struct {...@@ -6056,37 +6121,6 @@ const GenericCallAdapter = struct {
6056 }6121 }
6057};6122};
60586123
6059fn addComptimeReturnTypeNote(
6060 sema: *Sema,
6061 block: *Block,
6062 func: Air.Inst.Ref,
6063 func_src: LazySrcLoc,
6064 return_ty: Type,
6065 parent: *Module.ErrorMsg,
6066 requires_comptime: bool,
6067) !void {
6068 if (!requires_comptime) return;
6069
6070 const src_loc = if (try sema.funcDeclSrc(block, func_src, func)) |capture| blk: {
6071 var src_loc = capture;
6072 src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 };
6073 break :blk src_loc;
6074 } else blk: {
6075 const src_decl = sema.mod.declPtr(block.src_decl);
6076 break :blk func_src.toSrcLoc(src_decl);
6077 };
6078 if (return_ty.tag() == .generic_poison) {
6079 return sema.mod.errNoteNonLazy(src_loc, parent, "generic function is instantiated with a comptime-only return type", .{});
6080 }
6081 try sema.mod.errNoteNonLazy(
6082 src_loc,
6083 parent,
6084 "function is being called at comptime because it returns a comptime-only type '{}'",
6085 .{return_ty.fmt(sema.mod)},
6086 );
6087 try sema.explainWhyTypeIsComptime(block, func_src, parent, src_loc, return_ty);
6088}
6089
6090fn analyzeCall(6124fn analyzeCall(
6091 sema: *Sema,6125 sema: *Sema,
6092 block: *Block,6126 block: *Block,
...@@ -6177,11 +6211,21 @@ fn analyzeCall(...@@ -6177,11 +6211,21 @@ fn analyzeCall(
61776211
6178 var is_generic_call = func_ty_info.is_generic;6212 var is_generic_call = func_ty_info.is_generic;
6179 var is_comptime_call = block.is_comptime or modifier == .compile_time;6213 var is_comptime_call = block.is_comptime or modifier == .compile_time;
6180 var comptime_only_ret_ty = false;6214 var comptime_reason_buf: Block.ComptimeReason = undefined;
6215 var comptime_reason: ?*const Block.ComptimeReason = null;
6181 if (!is_comptime_call) {6216 if (!is_comptime_call) {
6182 if (sema.typeRequiresComptime(func_ty_info.return_type)) |ct| {6217 if (sema.typeRequiresComptime(func_ty_info.return_type)) |ct| {
6183 is_comptime_call = ct;6218 is_comptime_call = ct;
6184 comptime_only_ret_ty = ct;6219 if (ct) {
6220 // stage1 can't handle doing this directly
6221 comptime_reason_buf = .{ .comptime_ret_ty = .{
6222 .block = block,
6223 .func = func,
6224 .func_src = func_src,
6225 .return_ty = func_ty_info.return_type,
6226 } };
6227 comptime_reason = &comptime_reason_buf;
6228 }
6185 } else |err| switch (err) {6229 } else |err| switch (err) {
6186 error.GenericPoison => is_generic_call = true,6230 error.GenericPoison => is_generic_call = true,
6187 else => |e| return e,6231 else => |e| return e,
...@@ -6210,7 +6254,14 @@ fn analyzeCall(...@@ -6210,7 +6254,14 @@ fn analyzeCall(
6210 error.ComptimeReturn => {6254 error.ComptimeReturn => {
6211 is_inline_call = true;6255 is_inline_call = true;
6212 is_comptime_call = true;6256 is_comptime_call = true;
6213 comptime_only_ret_ty = true;6257 // stage1 can't handle doing this directly
6258 comptime_reason_buf = .{ .comptime_ret_ty = .{
6259 .block = block,
6260 .func = func,
6261 .func_src = func_src,
6262 .return_ty = func_ty_info.return_type,
6263 } };
6264 comptime_reason = &comptime_reason_buf;
6214 },6265 },
6215 else => |e| return e,6266 else => |e| return e,
6216 }6267 }
...@@ -6222,9 +6273,7 @@ fn analyzeCall(...@@ -6222,9 +6273,7 @@ fn analyzeCall(
62226273
6223 const result: Air.Inst.Ref = if (is_inline_call) res: {6274 const result: Air.Inst.Ref = if (is_inline_call) res: {
6224 const func_val = sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime-known") catch |err| {6275 const func_val = sema.resolveConstValue(block, func_src, func, "function being called at comptime must be comptime-known") catch |err| {
6225 if (err == error.AnalysisFail and sema.err != null) {6276 if (err == error.AnalysisFail and comptime_reason != null) try comptime_reason.?.explain(sema, sema.err);
6226 try sema.addComptimeReturnTypeNote(block, func, func_src, func_ty_info.return_type, sema.err.?, comptime_only_ret_ty);
6227 }
6228 return err;6277 return err;
6229 };6278 };
6230 const module_fn = switch (func_val.tag()) {6279 const module_fn = switch (func_val.tag()) {
...@@ -6292,6 +6341,7 @@ fn analyzeCall(...@@ -6292,6 +6341,7 @@ fn analyzeCall(
6292 .label = null,6341 .label = null,
6293 .inlining = &inlining,6342 .inlining = &inlining,
6294 .is_comptime = is_comptime_call,6343 .is_comptime = is_comptime_call,
6344 .comptime_reason = comptime_reason,
6295 .error_return_trace_index = block.error_return_trace_index,6345 .error_return_trace_index = block.error_return_trace_index,
6296 };6346 };
62976347
...@@ -6344,11 +6394,6 @@ fn analyzeCall(...@@ -6344,11 +6394,6 @@ fn analyzeCall(
6344 is_comptime_call,6394 is_comptime_call,
6345 &should_memoize,6395 &should_memoize,
6346 memoized_call_key,6396 memoized_call_key,
6347 // last 4 arguments are only used when reporting errors
6348 undefined,
6349 undefined,
6350 undefined,
6351 undefined,
6352 ) catch |err| switch (err) {6397 ) catch |err| switch (err) {
6353 error.NeededSourceLocation => {6398 error.NeededSourceLocation => {
6354 _ = sema.inst_map.remove(inst);6399 _ = sema.inst_map.remove(inst);
...@@ -6364,10 +6409,6 @@ fn analyzeCall(...@@ -6364,10 +6409,6 @@ fn analyzeCall(
6364 is_comptime_call,6409 is_comptime_call,
6365 &should_memoize,6410 &should_memoize,
6366 memoized_call_key,6411 memoized_call_key,
6367 func,
6368 func_src,
6369 func_ty_info.return_type,
6370 comptime_only_ret_ty,
6371 );6412 );
6372 return error.AnalysisFail;6413 return error.AnalysisFail;
6373 },6414 },
...@@ -6604,10 +6645,6 @@ fn analyzeInlineCallArg(...@@ -6604,10 +6645,6 @@ fn analyzeInlineCallArg(
6604 is_comptime_call: bool,6645 is_comptime_call: bool,
6605 should_memoize: *bool,6646 should_memoize: *bool,
6606 memoized_call_key: Module.MemoizedCall.Key,6647 memoized_call_key: Module.MemoizedCall.Key,
6607 func: Air.Inst.Ref,
6608 func_src: LazySrcLoc,
6609 ret_ty: Type,
6610 comptime_only_ret_ty: bool,
6611) !void {6648) !void {
6612 const zir_tags = sema.code.instructions.items(.tag);6649 const zir_tags = sema.code.instructions.items(.tag);
6613 switch (zir_tags[inst]) {6650 switch (zir_tags[inst]) {
...@@ -6624,9 +6661,7 @@ fn analyzeInlineCallArg(...@@ -6624,9 +6661,7 @@ fn analyzeInlineCallArg(
6624 const uncasted_arg = uncasted_args[arg_i.*];6661 const uncasted_arg = uncasted_args[arg_i.*];
6625 if (try sema.typeRequiresComptime(param_ty)) {6662 if (try sema.typeRequiresComptime(param_ty)) {
6626 _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime-only type must be comptime-known") catch |err| {6663 _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime-only type must be comptime-known") catch |err| {
6627 if (err == error.AnalysisFail and sema.err != null) {6664 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
6628 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
6629 }
6630 return err;6665 return err;
6631 };6666 };
6632 }6667 }
...@@ -6635,9 +6670,7 @@ fn analyzeInlineCallArg(...@@ -6635,9 +6670,7 @@ fn analyzeInlineCallArg(
6635 if (is_comptime_call) {6670 if (is_comptime_call) {
6636 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);6671 try sema.inst_map.putNoClobber(sema.gpa, inst, casted_arg);
6637 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {6672 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, casted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
6638 if (err == error.AnalysisFail and sema.err != null) {6673 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
6639 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
6640 }
6641 return err;6674 return err;
6642 };6675 };
6643 switch (arg_val.tag()) {6676 switch (arg_val.tag()) {
...@@ -6679,9 +6712,7 @@ fn analyzeInlineCallArg(...@@ -6679,9 +6712,7 @@ fn analyzeInlineCallArg(
6679 if (is_comptime_call) {6712 if (is_comptime_call) {
6680 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);6713 try sema.inst_map.putNoClobber(sema.gpa, inst, uncasted_arg);
6681 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {6714 const arg_val = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to function being called at comptime must be comptime-known") catch |err| {
6682 if (err == error.AnalysisFail and sema.err != null) {6715 if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
6683 try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
6684 }
6685 return err;6716 return err;
6686 };6717 };
6687 switch (arg_val.tag()) {6718 switch (arg_val.tag()) {
...@@ -10223,6 +10254,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10223,6 +10254,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10223 .label = &label,10254 .label = &label,
10224 .inlining = block.inlining,10255 .inlining = block.inlining,
10225 .is_comptime = block.is_comptime,10256 .is_comptime = block.is_comptime,
10257 .comptime_reason = block.comptime_reason,
10226 .is_typeof = block.is_typeof,10258 .is_typeof = block.is_typeof,
10227 .switch_else_err_ty = else_error_ty,10259 .switch_else_err_ty = else_error_ty,
10228 .runtime_cond = block.runtime_cond,10260 .runtime_cond = block.runtime_cond,
...@@ -10333,7 +10365,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10333,7 +10365,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10333 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);10365 return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
10334 }10366 }
1033510367
10336 try sema.requireRuntimeBlock(block, src, operand_src);10368 if (child_block.is_comptime) {
10369 _ = sema.resolveConstValue(&child_block, operand_src, operand, "condition in comptime switch must be comptime-known") catch |err| {
10370 if (err == error.AnalysisFail and child_block.comptime_reason != null) try child_block.comptime_reason.?.explain(sema, sema.err);
10371 return err;
10372 };
10373 unreachable;
10374 }
1033710375
10338 const estimated_cases_extra = (scalar_cases_len + multi_cases_len) *10376 const estimated_cases_extra = (scalar_cases_len + multi_cases_len) *
10339 @typeInfo(Air.SwitchBr.Case).Struct.fields.len + 2;10377 @typeInfo(Air.SwitchBr.Case).Struct.fields.len + 2;
...@@ -21469,6 +21507,9 @@ fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src:...@@ -21469,6 +21507,9 @@ fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src:
21469 if (runtime_src) |some| {21507 if (runtime_src) |some| {
21470 try sema.errNote(block, some, msg, "operation is runtime due to this operand", .{});21508 try sema.errNote(block, some, msg, "operation is runtime due to this operand", .{});
21471 }21509 }
21510 if (block.comptime_reason) |some| {
21511 try some.explain(sema, msg);
21512 }
21472 break :msg msg;21513 break :msg msg;
21473 };21514 };
21474 return sema.failWithOwnedErrorMsg(msg);21515 return sema.failWithOwnedErrorMsg(msg);
...@@ -21940,6 +21981,7 @@ fn addSafetyCheck(...@@ -21940,6 +21981,7 @@ fn addSafetyCheck(
21940 panic_id: PanicId,21981 panic_id: PanicId,
21941) !void {21982) !void {
21942 const gpa = sema.gpa;21983 const gpa = sema.gpa;
21984 assert(!parent_block.is_comptime);
2194321985
21944 var fail_block: Block = .{21986 var fail_block: Block = .{
21945 .parent = parent_block,21987 .parent = parent_block,
...@@ -21949,7 +21991,7 @@ fn addSafetyCheck(...@@ -21949,7 +21991,7 @@ fn addSafetyCheck(
21949 .wip_capture_scope = parent_block.wip_capture_scope,21991 .wip_capture_scope = parent_block.wip_capture_scope,
21950 .instructions = .{},21992 .instructions = .{},
21951 .inlining = parent_block.inlining,21993 .inlining = parent_block.inlining,
21952 .is_comptime = parent_block.is_comptime,21994 .is_comptime = false,
21953 };21995 };
2195421996
21955 defer fail_block.instructions.deinit(gpa);21997 defer fail_block.instructions.deinit(gpa);
...@@ -22061,6 +22103,7 @@ fn panicUnwrapError(...@@ -22061,6 +22103,7 @@ fn panicUnwrapError(
22061 unwrap_err_tag: Air.Inst.Tag,22103 unwrap_err_tag: Air.Inst.Tag,
22062 is_non_err_tag: Air.Inst.Tag,22104 is_non_err_tag: Air.Inst.Tag,
22063) !void {22105) !void {
22106 assert(!parent_block.is_comptime);
22064 const ok = try parent_block.addUnOp(is_non_err_tag, operand);22107 const ok = try parent_block.addUnOp(is_non_err_tag, operand);
22065 const gpa = sema.gpa;22108 const gpa = sema.gpa;
2206622109
...@@ -22072,7 +22115,7 @@ fn panicUnwrapError(...@@ -22072,7 +22115,7 @@ fn panicUnwrapError(
22072 .wip_capture_scope = parent_block.wip_capture_scope,22115 .wip_capture_scope = parent_block.wip_capture_scope,
22073 .instructions = .{},22116 .instructions = .{},
22074 .inlining = parent_block.inlining,22117 .inlining = parent_block.inlining,
22075 .is_comptime = parent_block.is_comptime,22118 .is_comptime = false,
22076 };22119 };
2207722120
22078 defer fail_block.instructions.deinit(gpa);22121 defer fail_block.instructions.deinit(gpa);
...@@ -22104,6 +22147,7 @@ fn panicIndexOutOfBounds(...@@ -22104,6 +22147,7 @@ fn panicIndexOutOfBounds(
22104 len: Air.Inst.Ref,22147 len: Air.Inst.Ref,
22105 cmp_op: Air.Inst.Tag,22148 cmp_op: Air.Inst.Tag,
22106) !void {22149) !void {
22150 assert(!parent_block.is_comptime);
22107 const ok = try parent_block.addBinOp(cmp_op, index, len);22151 const ok = try parent_block.addBinOp(cmp_op, index, len);
22108 const gpa = sema.gpa;22152 const gpa = sema.gpa;
2210922153
...@@ -22115,7 +22159,7 @@ fn panicIndexOutOfBounds(...@@ -22115,7 +22159,7 @@ fn panicIndexOutOfBounds(
22115 .wip_capture_scope = parent_block.wip_capture_scope,22159 .wip_capture_scope = parent_block.wip_capture_scope,
22116 .instructions = .{},22160 .instructions = .{},
22117 .inlining = parent_block.inlining,22161 .inlining = parent_block.inlining,
22118 .is_comptime = parent_block.is_comptime,22162 .is_comptime = false,
22119 };22163 };
2212022164
22121 defer fail_block.instructions.deinit(gpa);22165 defer fail_block.instructions.deinit(gpa);
...@@ -22146,6 +22190,7 @@ fn panicSentinelMismatch(...@@ -22146,6 +22190,7 @@ fn panicSentinelMismatch(
22146 ptr: Air.Inst.Ref,22190 ptr: Air.Inst.Ref,
22147 sentinel_index: Air.Inst.Ref,22191 sentinel_index: Air.Inst.Ref,
22148) !void {22192) !void {
22193 assert(!parent_block.is_comptime);
22149 const expected_sentinel_val = maybe_sentinel orelse return;22194 const expected_sentinel_val = maybe_sentinel orelse return;
22150 const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val);22195 const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val);
2215122196
...@@ -22186,7 +22231,7 @@ fn panicSentinelMismatch(...@@ -22186,7 +22231,7 @@ fn panicSentinelMismatch(
22186 .wip_capture_scope = parent_block.wip_capture_scope,22231 .wip_capture_scope = parent_block.wip_capture_scope,
22187 .instructions = .{},22232 .instructions = .{},
22188 .inlining = parent_block.inlining,22233 .inlining = parent_block.inlining,
22189 .is_comptime = parent_block.is_comptime,22234 .is_comptime = false,
22190 };22235 };
2219122236
22192 defer fail_block.instructions.deinit(gpa);22237 defer fail_block.instructions.deinit(gpa);
src/value.zig+1
...@@ -2621,6 +2621,7 @@ pub const Value = extern union {...@@ -2621,6 +2621,7 @@ pub const Value = extern union {
26212621
2622 .zero,2622 .zero,
2623 .one,2623 .one,
2624 .null_value,
2624 .int_u64,2625 .int_u64,
2625 .int_i64,2626 .int_i64,
2626 .int_big_positive,2627 .int_big_positive,
test/behavior/generics.zig+9
...@@ -396,3 +396,12 @@ test "slice as parameter type" {...@@ -396,3 +396,12 @@ test "slice as parameter type" {
396 try expect(S.internComptimeString(source_a[1..2]) == S.internComptimeString(source_a[1..2]));396 try expect(S.internComptimeString(source_a[1..2]) == S.internComptimeString(source_a[1..2]));
397 try expect(S.internComptimeString(source_a[2..4]) != S.internComptimeString(source_a[5..7]));397 try expect(S.internComptimeString(source_a[2..4]) != S.internComptimeString(source_a[5..7]));
398}398}
399
400test "null sentinel pointer passed as generic argument" {
401 const S = struct {
402 fn doTheTest(a: anytype) !void {
403 try std.testing.expect(@ptrToInt(a) == 8);
404 }
405 };
406 try S.doTheTest((@intToPtr([*:null]const [*c]const u8, 8)));
407}
test/cases/compile_errors/condition_comptime_reason_explained.zig created+48
...@@ -0,0 +1,48 @@
1const S = struct {
2 fnPtr: fn () void,
3};
4fn bar() void {}
5fn baz() void {}
6var runtime: bool = true;
7fn ifExpr() S {
8 if (runtime) {
9 return .{
10 .fnPtr = bar,
11 };
12 } else {
13 return .{
14 .fnPtr = baz,
15 };
16 }
17}
18pub export fn entry1() void {
19 _ = ifExpr();
20}
21fn switchExpr() S {
22 switch (runtime) {
23 true => return .{
24 .fnPtr = bar,
25 },
26 false => return .{
27 .fnPtr = baz,
28 },
29 }
30}
31pub export fn entry2() void {
32 _ = switchExpr();
33}
34
35// error
36// backend=stage2
37// target=native
38//
39// :8:9: error: unable to resolve comptime value
40// :8:9: note: condition in comptime branch must be comptime-known
41// :7:13: note: expression is evaluated at comptime because the function returns a comptime-only type 'tmp.S'
42// :2:12: note: struct requires comptime because of this field
43// :2:12: note: use '*const fn() void' for a function pointer type
44// :19:15: note: called from here
45// :22:13: error: unable to resolve comptime value
46// :22:13: note: condition in comptime switch must be comptime-known
47// :21:17: note: expression is evaluated at comptime because the function returns a comptime-only type 'tmp.S'
48// :32:19: note: called from here
test/cases/compile_errors/explain_why_fn_is_called_at_comptime.zig+1-1
...@@ -18,6 +18,6 @@ pub export fn entry() void {...@@ -18,6 +18,6 @@ pub export fn entry() void {
18//18//
19// :12:13: error: unable to resolve comptime value19// :12:13: error: unable to resolve comptime value
20// :12:13: note: argument to function being called at comptime must be comptime-known20// :12:13: note: argument to function being called at comptime must be comptime-known
21// :7:25: note: function is being called at comptime because it returns a comptime-only type 'tmp.S'21// :7:25: note: expression is evaluated at comptime because the function returns a comptime-only type 'tmp.S'
22// :2:12: note: struct requires comptime because of this field22// :2:12: note: struct requires comptime because of this field
23// :2:12: note: use '*const fn() void' for a function pointer type23// :2:12: note: use '*const fn() void' for a function pointer type
test/cases/compile_errors/explain_why_generic_fn_is_called_at_comptime.zig+1-1
...@@ -19,4 +19,4 @@ pub export fn entry() void {...@@ -19,4 +19,4 @@ pub export fn entry() void {
19//19//
20// :14:13: error: unable to resolve comptime value20// :14:13: error: unable to resolve comptime value
21// :14:13: note: argument to function being called at comptime must be comptime-known21// :14:13: note: argument to function being called at comptime must be comptime-known
22// :9:38: note: generic function is instantiated with a comptime-only return type22// :9:38: note: expression is evaluated at comptime because the generic function was instantiated with a comptime-only return type
test/cases/compile_errors/unable_to_evaluate_expr_inside_cimport.zig created+15
...@@ -0,0 +1,15 @@
1const c = @cImport({
2 _ = 1 + foo;
3});
4extern var foo: i32;
5export fn entry() void {
6 _ = c;
7}
8
9// error
10// backend=llvm
11// target=native
12//
13// :2:11: error: unable to evaluate comptime expression
14// :2:13: note: operation is runtime due to this operand
15// :1:11: note: expression is evaluated at comptime because it is inside a @cImport
test/compile_errors.zig+1-1
...@@ -204,7 +204,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -204,7 +204,7 @@ pub fn addCases(ctx: *TestContext) !void {
204 , &[_][]const u8{204 , &[_][]const u8{
205 ":3:12: error: unable to resolve comptime value",205 ":3:12: error: unable to resolve comptime value",
206 ":3:12: note: argument to function being called at comptime must be comptime-known",206 ":3:12: note: argument to function being called at comptime must be comptime-known",
207 ":2:55: note: generic function is instantiated with a comptime-only return type",207 ":2:55: note: expression is evaluated at comptime because the generic function was instantiated with a comptime-only return type",
208 });208 });
209 }209 }
210210