Sema: panic at comptime + misc error message improvements
This commit is contained in:
@@ -2464,6 +2464,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
|
||||
.repeat,
|
||||
.repeat_inline,
|
||||
.panic,
|
||||
.panic_comptime,
|
||||
=> {
|
||||
noreturn_src_node = statement;
|
||||
break :b true;
|
||||
@@ -7358,7 +7359,7 @@ fn builtinCall(
|
||||
.bool_to_int => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .bool_to_int),
|
||||
.embed_file => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .embed_file),
|
||||
.error_name => return simpleUnOp(gz, scope, rl, node, .{ .ty = .anyerror_type }, params[0], .error_name),
|
||||
.panic => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], .panic),
|
||||
.panic => return simpleUnOp(gz, scope, rl, node, .{ .ty = .const_slice_u8_type }, params[0], if (gz.force_comptime) .panic_comptime else .panic),
|
||||
.set_cold => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_cold),
|
||||
.set_runtime_safety => return simpleUnOp(gz, scope, rl, node, bool_rl, params[0], .set_runtime_safety),
|
||||
.sqrt => return simpleUnOp(gz, scope, rl, node, .none, params[0], .sqrt),
|
||||
|
||||
49
src/Sema.zig
49
src/Sema.zig
@@ -903,7 +903,8 @@ fn analyzeBodyInner(
|
||||
.ret_load => break sema.zirRetLoad(block, inst),
|
||||
.ret_err_value => break sema.zirRetErrValue(block, inst),
|
||||
.@"unreachable" => break sema.zirUnreachable(block, inst),
|
||||
.panic => break sema.zirPanic(block, inst),
|
||||
.panic => break sema.zirPanic(block, inst, false),
|
||||
.panic_comptime => break sema.zirPanic(block, inst, true),
|
||||
// zig fmt: on
|
||||
|
||||
.extended => ext: {
|
||||
@@ -3870,10 +3871,26 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
|
||||
.Slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(sema.mod)}),
|
||||
}
|
||||
|
||||
const elem_ty = operand_ty.elemType2();
|
||||
if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
|
||||
if (val.isUndef()) {
|
||||
return sema.fail(block, src, "cannot dereference undefined value", .{});
|
||||
}
|
||||
} else if (!(try sema.validateRunTimeType(block, src, elem_ty, false))) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(
|
||||
block,
|
||||
src,
|
||||
"values of type '{}' must be comptime known, but operand value is runtime known",
|
||||
.{elem_ty.fmt(sema.mod)},
|
||||
);
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
const src_decl = sema.mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(src_decl), elem_ty);
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(block, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4308,11 +4325,15 @@ fn zirCompileLog(
|
||||
return Air.Inst.Ref.void_value;
|
||||
}
|
||||
|
||||
fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Index {
|
||||
fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bool) CompileError!Zir.Inst.Index {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
const src: LazySrcLoc = inst_data.src();
|
||||
const src = inst_data.src();
|
||||
const msg_inst = try sema.resolveInst(inst_data.operand);
|
||||
|
||||
if (block.is_comptime or force_comptime) {
|
||||
return sema.fail(block, src, "encountered @panic at comptime", .{});
|
||||
}
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
return sema.panicWithMsg(block, src, msg_inst);
|
||||
}
|
||||
|
||||
@@ -8357,7 +8378,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
return sema.fail(
|
||||
block,
|
||||
src,
|
||||
"switch must handle all possibilities",
|
||||
"else prong required when switching on type 'anyerror'",
|
||||
.{},
|
||||
);
|
||||
}
|
||||
@@ -17416,7 +17437,7 @@ fn zirVarExtended(
|
||||
const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand);
|
||||
const src = sema.src;
|
||||
const ty_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at type
|
||||
const mut_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at mut token
|
||||
const name_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at the name token
|
||||
const init_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at init expr
|
||||
const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small);
|
||||
|
||||
@@ -17460,7 +17481,7 @@ fn zirVarExtended(
|
||||
return sema.failWithNeededComptime(block, init_src);
|
||||
} else Value.initTag(.unreachable_value);
|
||||
|
||||
try sema.validateVarType(block, mut_src, var_ty, small.is_extern);
|
||||
try sema.validateVarType(block, name_src, var_ty, small.is_extern);
|
||||
|
||||
const new_var = try sema.gpa.create(Module.Var);
|
||||
errdefer sema.gpa.destroy(new_var);
|
||||
@@ -17957,6 +17978,9 @@ fn validateVarType(
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(src_decl), var_ty);
|
||||
if (var_ty.zigTypeTag() == .ComptimeInt or var_ty.zigTypeTag() == .ComptimeFloat) {
|
||||
try sema.errNote(block, src, msg, "to modify this variable at runtime, it must be given an explicit fixed-size number type", .{});
|
||||
}
|
||||
|
||||
break :msg msg;
|
||||
};
|
||||
@@ -20041,6 +20065,15 @@ fn coerce(
|
||||
});
|
||||
return sema.addConstant(dest_ty, slice_val);
|
||||
}
|
||||
|
||||
if (inst_ty.zigTypeTag() == .Array) {
|
||||
return sema.fail(
|
||||
block,
|
||||
inst_src,
|
||||
"array literal requires address-of operator (&) to coerce to slice type '{}'",
|
||||
.{dest_ty.fmt(sema.mod)},
|
||||
);
|
||||
}
|
||||
},
|
||||
.Many => p: {
|
||||
if (!inst_ty.isSlice()) break :p;
|
||||
@@ -24433,6 +24466,10 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
|
||||
} else {
|
||||
// The provided type is the enum tag type.
|
||||
union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator);
|
||||
if (union_obj.tag_ty.zigTypeTag() != .Enum) {
|
||||
const tag_ty_src = src; // TODO better source location
|
||||
return sema.fail(block, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(sema.mod)});
|
||||
}
|
||||
// The fields of the union must match the enum exactly.
|
||||
// Store a copy of the enum field names so we can check for
|
||||
// missing or extraneous fields later.
|
||||
|
||||
@@ -798,6 +798,8 @@ pub const Inst = struct {
|
||||
error_name,
|
||||
/// Implement builtin `@panic`. Uses `un_node`.
|
||||
panic,
|
||||
/// Same as `panic` but forces comptime.
|
||||
panic_comptime,
|
||||
/// Implement builtin `@setCold`. Uses `un_node`.
|
||||
set_cold,
|
||||
/// Implement builtin `@setRuntimeSafety`. Uses `un_node`.
|
||||
@@ -1260,6 +1262,7 @@ pub const Inst = struct {
|
||||
.repeat,
|
||||
.repeat_inline,
|
||||
.panic,
|
||||
.panic_comptime,
|
||||
=> true,
|
||||
};
|
||||
}
|
||||
@@ -1533,6 +1536,7 @@ pub const Inst = struct {
|
||||
.repeat,
|
||||
.repeat_inline,
|
||||
.panic,
|
||||
.panic_comptime,
|
||||
.@"try",
|
||||
.try_ptr,
|
||||
//.try_inline,
|
||||
@@ -1726,6 +1730,7 @@ pub const Inst = struct {
|
||||
.embed_file = .un_node,
|
||||
.error_name = .un_node,
|
||||
.panic = .un_node,
|
||||
.panic_comptime = .un_node,
|
||||
.set_cold = .un_node,
|
||||
.set_runtime_safety = .un_node,
|
||||
.sqrt = .un_node,
|
||||
|
||||
@@ -197,6 +197,7 @@ const Writer = struct {
|
||||
.embed_file,
|
||||
.error_name,
|
||||
.panic,
|
||||
.panic_comptime,
|
||||
.set_cold,
|
||||
.set_runtime_safety,
|
||||
.sqrt,
|
||||
|
||||
@@ -15,7 +15,7 @@ export fn f() void {
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:14:5: error: expected type 'i32', found 'Foo'
|
||||
// :14:9: error: type 'tmp.Foo' has no field or member function named 'init'
|
||||
@@ -24,7 +24,7 @@ export fn foo() void {
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// backend=llvm
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:23:5: error: expected type '*Allocator', found '*List'
|
||||
// :23:6: error: type 'tmp.List' has no field or member function named 'init'
|
||||
@@ -12,7 +12,7 @@ export fn entry() void {
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// backend=llvm
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:4:30: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32'
|
||||
// :4:30: error: array literal requires address-of operator (&) to coerce to slice type '[][2]f32'
|
||||
@@ -0,0 +1,14 @@
|
||||
const y = mul(300, 6000);
|
||||
fn mul(a: u16, b: u16) u16 {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(&y)); }
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :3:14: error: overflow of integer type 'u16' with value '1800000'
|
||||
// :1:14: note: called from here
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
const y = neg(-128);
|
||||
fn neg(x: i8) i8 {
|
||||
return -x;
|
||||
}
|
||||
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(&y)); }
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :3:12: error: overflow of integer type 'i8' with value '128'
|
||||
// :1:14: note: called from here
|
||||
@@ -8,7 +8,7 @@ fn foo(a: anyerror) void {
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:5:5: error: else prong required when switching on type 'anyerror'
|
||||
// :5:5: error: else prong required when switching on type 'anyerror'
|
||||
@@ -0,0 +1,44 @@
|
||||
export fn entry1() void {
|
||||
var m2 = &2;
|
||||
_ = m2;
|
||||
}
|
||||
export fn entry2() void {
|
||||
var a = undefined;
|
||||
_ = a;
|
||||
}
|
||||
export fn entry3() void {
|
||||
var b = 1;
|
||||
_ = b;
|
||||
}
|
||||
export fn entry4() void {
|
||||
var c = 1.0;
|
||||
_ = c;
|
||||
}
|
||||
export fn entry5() void {
|
||||
var d = null;
|
||||
_ = d;
|
||||
}
|
||||
export fn entry6(opaque_: *Opaque) void {
|
||||
var e = opaque_.*;
|
||||
_ = e;
|
||||
}
|
||||
export fn entry7() void {
|
||||
var f = i32;
|
||||
_ = f;
|
||||
}
|
||||
const Opaque = opaque {};
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :2:8: error: variable of type '*const comptime_int' must be const or comptime
|
||||
// :6:8: error: variable of type '@TypeOf(undefined)' must be const or comptime
|
||||
// :10:8: error: variable of type 'comptime_int' must be const or comptime
|
||||
// :10:8: note: to modify this variable at runtime, it must be given an explicit fixed-size number type
|
||||
// :14:8: error: variable of type 'comptime_float' must be const or comptime
|
||||
// :14:8: note: to modify this variable at runtime, it must be given an explicit fixed-size number type
|
||||
// :18:8: error: variable of type '@TypeOf(null)' must be const or comptime
|
||||
// :22:19: error: values of type 'tmp.Opaque' must be comptime known, but operand value is runtime known
|
||||
// :26:8: error: variable of type 'type' must be const or comptime
|
||||
// :26:8: note: types are not available at runtime
|
||||
@@ -0,0 +1,15 @@
|
||||
export fn foo() void {
|
||||
const Errors = u8 || u16;
|
||||
_ = Errors;
|
||||
}
|
||||
export fn bar() void {
|
||||
const Errors = error{} || u16;
|
||||
_ = Errors;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :2:20: error: expected error set type, found 'u8'
|
||||
// :6:31: error: expected error set type, found 'u16'
|
||||
@@ -5,7 +5,7 @@ export fn entry() void {
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:9: error: encountered @panic at compile-time
|
||||
// :3:9: error: encountered @panic at comptime
|
||||
@@ -1,12 +0,0 @@
|
||||
const y = mul(300, 6000);
|
||||
fn mul(a: u16, b: u16) u16 {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(y)); }
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:14: error: operation caused overflow
|
||||
@@ -1,12 +0,0 @@
|
||||
const y = neg(-128);
|
||||
fn neg(x: i8) i8 {
|
||||
return -x;
|
||||
}
|
||||
|
||||
export fn entry() usize { return @sizeOf(@TypeOf(y)); }
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:12: error: negation caused overflow
|
||||
@@ -1,51 +0,0 @@
|
||||
export fn entry1() void {
|
||||
var m2 = &2;
|
||||
_ = m2;
|
||||
}
|
||||
export fn entry2() void {
|
||||
var a = undefined;
|
||||
_ = a;
|
||||
}
|
||||
export fn entry3() void {
|
||||
var b = 1;
|
||||
_ = b;
|
||||
}
|
||||
export fn entry4() void {
|
||||
var c = 1.0;
|
||||
_ = c;
|
||||
}
|
||||
export fn entry5() void {
|
||||
var d = null;
|
||||
_ = d;
|
||||
}
|
||||
export fn entry6(opaque_: *Opaque) void {
|
||||
var e = opaque_.*;
|
||||
_ = e;
|
||||
}
|
||||
export fn entry7() void {
|
||||
var f = i32;
|
||||
_ = f;
|
||||
}
|
||||
export fn entry8() void {
|
||||
var h = (Foo {}).bar;
|
||||
_ = h;
|
||||
}
|
||||
const Opaque = opaque {};
|
||||
const Foo = struct {
|
||||
fn bar(self: *const Foo) void {_ = self;}
|
||||
};
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:4: error: variable of type '*const comptime_int' must be const or comptime
|
||||
// tmp.zig:6:4: error: variable of type '@Type(.Undefined)' must be const or comptime
|
||||
// tmp.zig:10:4: error: variable of type 'comptime_int' must be const or comptime
|
||||
// tmp.zig:10:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type
|
||||
// tmp.zig:14:4: error: variable of type 'comptime_float' must be const or comptime
|
||||
// tmp.zig:14:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type
|
||||
// tmp.zig:18:4: error: variable of type '@Type(.Null)' must be const or comptime
|
||||
// tmp.zig:22:4: error: variable of type 'Opaque' not allowed
|
||||
// tmp.zig:26:4: error: variable of type 'type' must be const or comptime
|
||||
// tmp.zig:30:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime
|
||||
@@ -1,17 +0,0 @@
|
||||
export fn foo() void {
|
||||
const Errors = u8 || u16;
|
||||
_ = Errors;
|
||||
}
|
||||
export fn bar() void {
|
||||
const Errors = error{} || u16;
|
||||
_ = Errors;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:2:20: error: expected error set type, found type 'u8'
|
||||
// tmp.zig:2:23: note: `||` merges error sets; `or` performs boolean OR
|
||||
// tmp.zig:6:31: error: expected error set type, found type 'u16'
|
||||
// tmp.zig:6:28: note: `||` merges error sets; `or` performs boolean OR
|
||||
@@ -9,3 +9,4 @@ export fn entry() void {
|
||||
// target=native
|
||||
//
|
||||
// :1:1: error: variable of type 'comptime_int' must be const or comptime
|
||||
// :1:1: note: to modify this variable at runtime, it must be given an explicit fixed-size number type
|
||||
|
||||
Reference in New Issue
Block a user