aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-06-30 18:39:46 -0400
committerGitHub <noreply@github.com>2022-06-30 18:39:46 -0400
commit1951051e3d692d8257e46fc23a7dff9447828fd7 (patch)
tree24d1e8ec92fcc47c7774a6ed35b3e228796d1158 /src/Sema.zig
parent77a334451f1329110d6c1bd07b46813cef10e97c (diff)
parent4cde6dd10902ebeec3b3000b76d6395c49f5a241 (diff)
downloadzig-1951051e3d692d8257e46fc23a7dff9447828fd7.tar.gz
zig-1951051e3d692d8257e46fc23a7dff9447828fd7.zip
Merge pull request #11942 from Vexu/stage2-compile-errors
Move passing stage1 compile error tests to stage2
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig438
1 files changed, 314 insertions, 124 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index a071c97df3..862d5cbf48 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -139,6 +139,7 @@ pub const Block = struct {
is_comptime: bool,
is_typeof: bool = false,
+ is_coerce_result_ptr: bool = false,
/// when null, it is determined by build mode, changed by @setRuntimeSafety
want_safety: ?bool = null,
@@ -1707,7 +1708,7 @@ fn failWithModRemNegative(sema: *Sema, block: *Block, src: LazySrcLoc, lhs_ty: T
}
fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, optional_ty: Type) CompileError {
- return sema.fail(block, src, "expected optional type, found {}", .{optional_ty.fmt(sema.mod)});
+ return sema.fail(block, src, "expected optional type, found '{}'", .{optional_ty.fmt(sema.mod)});
}
fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
@@ -1734,9 +1735,20 @@ fn failWithErrorSetCodeMissing(
});
}
-fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value) CompileError {
+fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError {
+ if (int_ty.zigTypeTag() == .Vector) {
+ const msg = msg: {
+ const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{
+ int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod),
+ });
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(block, src, msg, "when computing vector element at index '{d}'", .{vector_index});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(block, msg);
+ }
return sema.fail(block, src, "overflow of integer type '{}' with value '{}'", .{
- int_ty.fmt(sema.mod), val.fmtValue(Type.@"comptime_int", sema.mod),
+ int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod),
});
}
@@ -1844,7 +1856,7 @@ pub fn resolveAlign(
const alignment = @intCast(u32, alignment_big); // We coerce to u16 in the prev line.
if (alignment == 0) return sema.fail(block, src, "alignment must be >= 1", .{});
if (!std.math.isPowerOfTwo(alignment)) {
- return sema.fail(block, src, "alignment value {d} is not a power of two", .{
+ return sema.fail(block, src, "alignment value '{d}' is not a power of two", .{
alignment,
});
}
@@ -1901,10 +1913,11 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const tracy = trace(@src());
defer tracy.end();
- const src: LazySrcLoc = sema.src;
- const bin_inst = sema.code.instructions.items(.data)[inst].bin;
- const pointee_ty = try sema.resolveType(block, src, bin_inst.lhs);
- const ptr = try sema.resolveInst(bin_inst.rhs);
+ const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+ const src = inst_data.src();
+ const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
+ const pointee_ty = try sema.resolveType(block, src, extra.lhs);
+ const ptr = try sema.resolveInst(extra.rhs);
const target = sema.mod.getTarget();
const addr_space = target_util.defaultAddressSpace(target, .local);
@@ -1971,6 +1984,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
// kind of transformations to make on the result pointer.
var trash_block = block.makeSubBlock();
trash_block.is_comptime = false;
+ trash_block.is_coerce_result_ptr = true;
defer trash_block.instructions.deinit(sema.gpa);
const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr));
@@ -2376,6 +2390,12 @@ fn zirEnumDecl(
}
}
+ if (small.nonexhaustive) {
+ if (fields_len > 1 and std.math.log2_int(u64, fields_len) == enum_obj.tag_ty.bitSize(sema.mod.getTarget())) {
+ return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
+ }
+ }
+
try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
if (bag != 0) break true;
@@ -4540,6 +4560,7 @@ fn analyzeBlockBody(
// to emit a jump instruction to after the block when it encounters the break.
try parent_block.instructions.append(gpa, merges.block_inst);
const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .none);
+ // TODO add note "missing else causes void value"
const type_src = src; // TODO: better source location
const valid_rt = try sema.validateRunTimeType(child_block, type_src, resolved_ty, false);
@@ -4761,7 +4782,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
const msg = msg: {
const msg = try sema.errMsg(block, src, "multiple @setAlignStack in the same function body", .{});
errdefer msg.destroy(sema.gpa);
- try sema.errNote(block, src, msg, "other instance here", .{});
+ try sema.errNote(block, gop.value_ptr.src, msg, "other instance here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(block, msg);
@@ -5224,6 +5245,10 @@ fn analyzeCall(
.async_kw => return sema.fail(block, call_src, "TODO implement async call", .{}),
};
+ if (modifier == .never_inline and func_ty_info.cc == .Inline) {
+ return sema.fail(block, call_src, "no-inline call of inline function", .{});
+ }
+
const gpa = sema.gpa;
var is_generic_call = func_ty_info.is_generic;
@@ -5263,6 +5288,10 @@ fn analyzeCall(
}
}
+ if (is_comptime_call and modifier == .never_inline) {
+ return sema.fail(block, call_src, "unable to perform 'never_inline' call at compile-time", .{});
+ }
+
const result: Air.Inst.Ref = if (is_inline_call) res: {
const func_val = try sema.resolveConstValue(block, func_src, func);
const module_fn = switch (func_val.tag()) {
@@ -6155,7 +6184,7 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
const payload = try sema.resolveType(block, rhs_src, extra.rhs);
if (error_set.zigTypeTag() != .ErrorSet) {
- return sema.fail(block, lhs_src, "expected error set type, found {}", .{
+ return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{
error_set.fmt(sema.mod),
});
}
@@ -6243,7 +6272,7 @@ fn zirIntToError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {
const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(target));
if (int > sema.mod.global_error_set.count() or int == 0)
- return sema.fail(block, operand_src, "integer value {d} represents no error", .{int});
+ return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int});
const payload = try sema.arena.create(Value.Payload.Error);
payload.* = .{
.base = .{ .tag = .@"error" },
@@ -6288,9 +6317,9 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs);
const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs);
if (lhs_ty.zigTypeTag() != .ErrorSet)
- return sema.fail(block, lhs_src, "expected error set type, found {}", .{lhs_ty.fmt(sema.mod)});
+ return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(sema.mod)});
if (rhs_ty.zigTypeTag() != .ErrorSet)
- return sema.fail(block, rhs_src, "expected error set type, found {}", .{rhs_ty.fmt(sema.mod)});
+ return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(sema.mod)});
// Anything merged with anyerror is anyerror.
if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror) {
@@ -6351,7 +6380,7 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
break :blk try sema.unionToTag(block, tag_ty, operand, operand_src);
},
else => {
- return sema.fail(block, operand_src, "expected enum or tagged union, found {}", .{
+ return sema.fail(block, operand_src, "expected enum or tagged union, found '{}'", .{
operand_ty.fmt(sema.mod),
});
},
@@ -6385,7 +6414,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const operand = try sema.resolveInst(extra.rhs);
if (dest_ty.zigTypeTag() != .Enum) {
- return sema.fail(block, dest_ty_src, "expected enum, found {}", .{dest_ty.fmt(sema.mod)});
+ return sema.fail(block, dest_ty_src, "expected enum, found '{}'", .{dest_ty.fmt(sema.mod)});
}
if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |int_val| {
@@ -6400,7 +6429,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const msg = try sema.errMsg(
block,
src,
- "enum '{}' has no tag with value {}",
+ "enum '{}' has no tag with value '{}'",
.{ dest_ty.fmt(sema.mod), int_val.fmtValue(sema.typeOf(operand), sema.mod) },
);
errdefer msg.destroy(sema.gpa);
@@ -6452,7 +6481,7 @@ fn analyzeOptionalPayloadPtr(
const opt_type = optional_ptr_ty.elemType();
if (opt_type.zigTypeTag() != .Optional) {
- return sema.fail(block, src, "expected optional type, found {}", .{opt_type.fmt(sema.mod)});
+ return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(sema.mod)});
}
const child_type = try opt_type.optionalChildAlloc(sema.arena);
@@ -6640,7 +6669,7 @@ fn analyzeErrUnionPayloadPtr(
assert(operand_ty.zigTypeTag() == .Pointer);
if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) {
- return sema.fail(block, src, "expected error union type, found {}", .{
+ return sema.fail(block, src, "expected error union type, found '{}'", .{
operand_ty.elemType().fmt(sema.mod),
});
}
@@ -6739,7 +6768,7 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
assert(operand_ty.zigTypeTag() == .Pointer);
if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) {
- return sema.fail(block, src, "expected error union type, found {}", .{
+ return sema.fail(block, src, "expected error union type, found '{}'", .{
operand_ty.elemType().fmt(sema.mod),
});
}
@@ -7639,7 +7668,6 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
@@ -7674,7 +7702,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
return sema.addConstant(dest_ty, try operand_val.floatCast(sema.arena, dest_ty, target));
}
if (dest_is_comptime_float) {
- return sema.fail(block, src, "unable to cast runtime value to 'comptime_float'", .{});
+ return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_float'", .{});
}
const src_bits = operand_ty.floatBits(target);
const dst_bits = dest_ty.floatBits(target);
@@ -9000,6 +9028,10 @@ fn validateSwitchRange(
) CompileError!void {
const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val;
const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val;
+ if (first_val.compare(.gt, last_val, operand_ty, sema.mod)) {
+ const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), src_node_offset, .first);
+ return sema.fail(block, src, "range start value is greater than the end value", .{});
+ }
const maybe_prev_src = try range_set.add(first_val, last_val, operand_ty, switch_prong_src);
return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
}
@@ -9347,9 +9379,34 @@ fn zirShl(
if (rhs_val.isUndef()) {
return sema.addConstUndef(sema.typeOf(lhs));
}
+ // If rhs is 0, return lhs without doing any calculations.
if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
return lhs;
}
+ if (scalar_ty.zigTypeTag() != .ComptimeInt and air_tag != .shl_sat) {
+ var bits_payload = Value.Payload.U64{
+ .base = .{ .tag = .int_u64 },
+ .data = scalar_ty.intInfo(target).bits,
+ };
+ const bit_value = Value.initPayload(&bits_payload.base);
+ if (rhs_ty.zigTypeTag() == .Vector) {
+ var i: usize = 0;
+ while (i < rhs_ty.vectorLen()) : (i += 1) {
+ if (rhs_val.indexVectorlike(i).compareHetero(.gte, bit_value, target)) {
+ return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
+ rhs_val.indexVectorlike(i).fmtValue(scalar_ty, sema.mod),
+ i,
+ scalar_ty.fmt(sema.mod),
+ });
+ }
+ }
+ } else if (rhs_val.compareHetero(.gte, bit_value, target)) {
+ return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
+ rhs_val.fmtValue(scalar_ty, sema.mod),
+ scalar_ty.fmt(sema.mod),
+ });
+ }
+ }
}
const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
@@ -9461,16 +9518,44 @@ fn zirShr(
const rhs_ty = sema.typeOf(rhs);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
const target = sema.mod.getTarget();
+ const scalar_ty = lhs_ty.scalarType();
const runtime_src = if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| rs: {
+ if (rhs_val.isUndef()) {
+ return sema.addConstUndef(lhs_ty);
+ }
+ // If rhs is 0, return lhs without doing any calculations.
+ if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
+ return lhs;
+ }
+ if (scalar_ty.zigTypeTag() != .ComptimeInt) {
+ var bits_payload = Value.Payload.U64{
+ .base = .{ .tag = .int_u64 },
+ .data = scalar_ty.intInfo(target).bits,
+ };
+ const bit_value = Value.initPayload(&bits_payload.base);
+ if (rhs_ty.zigTypeTag() == .Vector) {
+ var i: usize = 0;
+ while (i < rhs_ty.vectorLen()) : (i += 1) {
+ if (rhs_val.indexVectorlike(i).compareHetero(.gte, bit_value, target)) {
+ return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
+ rhs_val.indexVectorlike(i).fmtValue(scalar_ty, sema.mod),
+ i,
+ scalar_ty.fmt(sema.mod),
+ });
+ }
+ }
+ } else if (rhs_val.compareHetero(.gte, bit_value, target)) {
+ return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
+ rhs_val.fmtValue(scalar_ty, sema.mod),
+ scalar_ty.fmt(sema.mod),
+ });
+ }
+ }
if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
- if (lhs_val.isUndef() or rhs_val.isUndef()) {
+ if (lhs_val.isUndef()) {
return sema.addConstUndef(lhs_ty);
}
- // If rhs is 0, return lhs without doing any calculations.
- if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
- return sema.addConstant(lhs_ty, lhs_val);
- }
if (air_tag == .shr_exact) {
// Detect if any ones would be shifted out.
const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target);
@@ -9481,12 +9566,6 @@ fn zirShr(
const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, target);
return sema.addConstant(lhs_ty, val);
} else {
- // Even if lhs is not comptime known, we can still deduce certain things based
- // on rhs.
- // If rhs is 0, return lhs without doing any calculations.
- if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
- return lhs;
- }
break :rs lhs_src;
}
} else rhs_src;
@@ -10065,7 +10144,10 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const rhs_ty = sema.typeOf(rhs);
const rhs_scalar_ty = rhs_ty.scalarType();
- if (rhs_scalar_ty.isUnsignedInt()) {
+ if (rhs_scalar_ty.isUnsignedInt() or switch (rhs_scalar_ty.zigTypeTag()) {
+ .Int, .ComptimeInt, .Float, .ComptimeFloat => false,
+ else => true,
+ }) {
return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)});
}
@@ -10096,6 +10178,12 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
const rhs = try sema.resolveInst(inst_data.operand);
const rhs_ty = sema.typeOf(rhs);
+ const rhs_scalar_ty = rhs_ty.scalarType();
+
+ switch (rhs_scalar_ty.zigTypeTag()) {
+ .Int, .ComptimeInt, .Float, .ComptimeFloat => {},
+ else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}),
+ }
const lhs = if (rhs_ty.zigTypeTag() == .Vector)
try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero))
@@ -10441,8 +10529,9 @@ fn analyzeArithmetic(
if (maybe_rhs_val) |rhs_val| {
if (is_int) {
const sum = try sema.intAdd(block, src, lhs_val, rhs_val, resolved_type);
- if (!(try sema.intFitsInType(block, src, sum, resolved_type))) {
- return sema.failWithIntegerOverflow(block, src, resolved_type, sum);
+ var vector_index: usize = undefined;
+ if (!(try sema.intFitsInType(block, src, sum, resolved_type, &vector_index))) {
+ return sema.failWithIntegerOverflow(block, src, resolved_type, sum, vector_index);
}
return sema.addConstant(resolved_type, sum);
} else {
@@ -10535,8 +10624,9 @@ fn analyzeArithmetic(
if (maybe_rhs_val) |rhs_val| {
if (is_int) {
const diff = try sema.intSub(block, src, lhs_val, rhs_val, resolved_type);
- if (!(try sema.intFitsInType(block, src, diff, resolved_type))) {
- return sema.failWithIntegerOverflow(block, src, resolved_type, diff);
+ var vector_index: usize = undefined;
+ if (!(try sema.intFitsInType(block, src, diff, resolved_type, &vector_index))) {
+ return sema.failWithIntegerOverflow(block, src, resolved_type, diff, vector_index);
}
return sema.addConstant(resolved_type, diff);
} else {
@@ -10909,8 +10999,9 @@ fn analyzeArithmetic(
}
if (is_int) {
const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target);
- if (!(try sema.intFitsInType(block, src, product, resolved_type))) {
- return sema.failWithIntegerOverflow(block, src, resolved_type, product);
+ var vector_index: usize = undefined;
+ if (!(try sema.intFitsInType(block, src, product, resolved_type, &vector_index))) {
+ return sema.failWithIntegerOverflow(block, src, resolved_type, product, vector_index);
}
return sema.addConstant(resolved_type, product);
} else {
@@ -11608,8 +11699,13 @@ fn analyzeCmpUnionTag(
) CompileError!Air.Inst.Ref {
const union_ty = try sema.resolveTypeFields(block, un_src, sema.typeOf(un));
const union_tag_ty = union_ty.unionTagType() orelse {
- // TODO note at declaration site that says "union foo is not tagged"
- return sema.fail(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
+ const msg = msg: {
+ const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
+ errdefer msg.destroy(sema.gpa);
+ try sema.mod.errNoteNonLazy(union_ty.declSrcLoc(sema.mod), msg, "union '{}' is not a tagged union", .{union_ty.fmt(sema.mod)});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(block, msg);
};
// Coerce both the union and the tag to the union's tag type, and then execute the
// enum comparison codepath.
@@ -11666,8 +11762,8 @@ fn analyzeCmp(
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]LazySrcLoc{ lhs_src, rhs_src } });
if (!resolved_type.isSelfComparable(is_equality_cmp)) {
- return sema.fail(block, src, "{s} operator not allowed for type '{}'", .{
- @tagName(op), resolved_type.fmt(sema.mod),
+ return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{
+ compareOperatorName(op), resolved_type.fmt(sema.mod),
});
}
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
@@ -11675,6 +11771,17 @@ fn analyzeCmp(
return sema.cmpSelf(block, casted_lhs, casted_rhs, op, lhs_src, rhs_src);
}
+fn compareOperatorName(comp: std.math.CompareOperator) []const u8 {
+ return switch (comp) {
+ .lt => "<",
+ .lte => "<=",
+ .eq => "==",
+ .gte => ">=",
+ .gt => ">",
+ .neq => "!=",
+ };
+}
+
fn cmpSelf(
sema: *Sema,
block: *Block,
@@ -13098,7 +13205,6 @@ fn zirCondbr(
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
@@ -13108,7 +13214,7 @@ fn zirCondbr(
const uncasted_cond = try sema.resolveInst(extra.data.condition);
const cond = try sema.coerce(parent_block, Type.bool, uncasted_cond, cond_src);
- if (try sema.resolveDefinedValue(parent_block, src, cond)) |cond_val| {
+ if (try sema.resolveDefinedValue(parent_block, cond_src, cond)) |cond_val| {
const body = if (cond_val.toBool()) then_body else else_body;
// We use `analyzeBodyInner` since we want to propagate any possible
// `error.ComptimeBreak` to the caller.
@@ -14384,7 +14490,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
};
return sema.failWithOwnedErrorMsg(block, msg);
},
- else => return sema.fail(block, operand_src, "expected enum or union; found {}", .{
+ else => return sema.fail(block, operand_src, "expected enum or union; found '{}'", .{
operand_ty.fmt(mod),
}),
};
@@ -14394,8 +14500,8 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const field_index = enum_ty.enumTagFieldIndex(val, mod) orelse {
const enum_decl = mod.declPtr(enum_decl_index);
const msg = msg: {
- const msg = try sema.errMsg(block, src, "no field with value {} in enum '{s}'", .{
- casted_operand, enum_decl.name,
+ const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{s}'", .{
+ val.fmtValue(enum_ty, sema.mod), enum_decl.name,
});
errdefer msg.destroy(sema.gpa);
try mod.errNoteNonLazy(enum_decl.srcLoc(), msg, "declared here", .{});
@@ -14460,6 +14566,8 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
var buffer: Value.ToTypeBuffer = undefined;
const child_ty = child_val.toType(&buffer);
+ try sema.checkVectorElemType(block, src, child_ty);
+
const ty = try Type.vector(sema.arena, len, try child_ty.copy(sema.arena));
return sema.addType(ty);
},
@@ -14837,7 +14945,7 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
union_obj.tag_ty = if (tag_type_val.optionalValue()) |payload_val| blk: {
var buffer: Value.ToTypeBuffer = undefined;
break :blk try payload_val.toType(&buffer).copy(new_decl_arena_allocator);
- } else try sema.generateUnionTagTypeSimple(block, fields_len);
+ } else try sema.generateUnionTagTypeSimple(block, fields_len, null);
// Fields
if (fields_len > 0) {
@@ -15101,6 +15209,8 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
const result_val = try sema.floatToInt(block, operand_src, val, operand_ty, dest_ty);
return sema.addConstant(dest_ty, result_val);
+ } else if (dest_ty.zigTypeTag() == .ComptimeInt) {
+ return sema.failWithNeededComptime(block, operand_src);
}
try sema.requireRuntimeBlock(block, operand_src);
@@ -15123,6 +15233,8 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
const target = sema.mod.getTarget();
const result_val = try val.intToFloat(sema.arena, operand_ty, dest_ty, target);
return sema.addConstant(dest_ty, result_val);
+ } else if (dest_ty.zigTypeTag() == .ComptimeFloat) {
+ return sema.failWithNeededComptime(block, operand_src);
}
try sema.requireRuntimeBlock(block, operand_src);
@@ -15244,7 +15356,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
const msg = try sema.errMsg(
block,
src,
- "error.{s} not a member of error set '{}'",
+ "'error.{s}' not a member of error set '{}'",
.{ error_name, dest_ty.fmt(sema.mod) },
);
errdefer msg.destroy(sema.gpa);
@@ -15635,22 +15747,29 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
try sema.resolveTypeLayout(block, lhs_src, ty);
if (ty.tag() != .@"struct") {
- return sema.fail(
- block,
- lhs_src,
- "expected struct type, found '{}'",
- .{ty.fmt(sema.mod)},
- );
+ const msg = msg: {
+ const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(sema.mod)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.addDeclaredHereNote(msg, ty);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(block, msg);
}
const fields = ty.structFields();
const index = fields.getIndex(field_name) orelse {
- return sema.fail(
- block,
- rhs_src,
- "struct '{}' has no field '{s}'",
- .{ ty.fmt(sema.mod), field_name },
- );
+ const msg = msg: {
+ const msg = try sema.errMsg(
+ block,
+ rhs_src,
+ "struct '{}' has no field '{s}'",
+ .{ ty.fmt(sema.mod), field_name },
+ );
+ errdefer msg.destroy(sema.gpa);
+ try sema.addDeclaredHereNote(msg, ty);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(block, msg);
};
switch (ty.containerLayout()) {
@@ -15703,7 +15822,7 @@ fn checkPtrOperand(
const msg = try sema.errMsg(
block,
ty_src,
- "expected pointer, found {}",
+ "expected pointer, found '{}'",
.{ty.fmt(sema.mod)},
);
errdefer msg.destroy(sema.gpa);
@@ -15819,7 +15938,7 @@ fn checkAtomicPtrOperand(
error.BadType => return sema.fail(
block,
elem_ty_src,
- "expected bool, integer, float, enum, or pointer type; found {}",
+ "expected bool, integer, float, enum, or pointer type; found '{}'",
.{elem_ty.fmt(sema.mod)},
),
};
@@ -16028,7 +16147,7 @@ fn checkVectorizableBinaryOperands(
}
} else {
const msg = msg: {
- const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: {} and {}", .{
+ const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: '{}' and '{}'", .{
lhs_ty.fmt(sema.mod), rhs_ty.fmt(sema.mod),
});
errdefer msg.destroy(sema.gpa);
@@ -16071,6 +16190,10 @@ fn resolveExportOptions(
const visibility_val = try sema.resolveConstValue(block, src, visibility_operand);
const visibility = visibility_val.toEnum(std.builtin.SymbolVisibility);
+ if (name.len < 1) {
+ return sema.fail(block, src, "exported symbol name cannot be empty", .{});
+ }
+
if (visibility != .default and linkage == .Internal) {
return sema.fail(block, src, "symbol '{s}' exported with internal linkage has non-default visibility {s}", .{
name, @tagName(visibility),
@@ -16249,7 +16372,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const target = sema.mod.getTarget();
if (operand_ty.zigTypeTag() != .Vector) {
- return sema.fail(block, operand_src, "expected vector, found {}", .{operand_ty.fmt(sema.mod)});
+ return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(sema.mod)});
}
const scalar_ty = operand_ty.childType();
@@ -16258,13 +16381,13 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
switch (operation) {
.And, .Or, .Xor => switch (scalar_ty.zigTypeTag()) {
.Int, .Bool => {},
- else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found {}", .{
+ else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{}'", .{
@tagName(operation), operand_ty.fmt(sema.mod),
}),
},
.Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag()) {
.Int, .Float => {},
- else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found {}", .{
+ else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{}'", .{
@tagName(operation), operand_ty.fmt(sema.mod),
}),
},
@@ -16323,7 +16446,7 @@ fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const mask_len = switch (sema.typeOf(mask).zigTypeTag()) {
.Array, .Vector => sema.typeOf(mask).arrayLen(),
- else => return sema.fail(block, mask_src, "expected vector or array, found {}", .{sema.typeOf(mask).fmt(sema.mod)}),
+ else => return sema.fail(block, mask_src, "expected vector or array, found '{}'", .{sema.typeOf(mask).fmt(sema.mod)}),
};
mask_ty = try Type.Tag.vector.create(sema.arena, .{
.len = mask_len,
@@ -16358,7 +16481,7 @@ fn analyzeShuffle(
var maybe_a_len = switch (sema.typeOf(a).zigTypeTag()) {
.Array, .Vector => sema.typeOf(a).arrayLen(),
.Undefined => null,
- else => return sema.fail(block, a_src, "expected vector or array with element type {}, found {}", .{
+ else => return sema.fail(block, a_src, "expected vector or array with element type '{}', found '{}'", .{
elem_ty.fmt(sema.mod),
sema.typeOf(a).fmt(sema.mod),
}),
@@ -16366,7 +16489,7 @@ fn analyzeShuffle(
var maybe_b_len = switch (sema.typeOf(b).zigTypeTag()) {
.Array, .Vector => sema.typeOf(b).arrayLen(),
.Undefined => null,
- else => return sema.fail(block, b_src, "expected vector or array with element type {}, found {}", .{
+ else => return sema.fail(block, b_src, "expected vector or array with element type '{}', found '{}'", .{
elem_ty.fmt(sema.mod),
sema.typeOf(b).fmt(sema.mod),
}),
@@ -16411,15 +16534,15 @@ fn analyzeShuffle(
}
if (unsigned >= operand_info[chosen][0]) {
const msg = msg: {
- const msg = try sema.errMsg(block, mask_src, "mask index {d} has out-of-bounds selection", .{i});
+ const msg = try sema.errMsg(block, mask_src, "mask index '{d}' has out-of-bounds selection", .{i});
errdefer msg.destroy(sema.gpa);
- try sema.errNote(block, operand_info[chosen][1], msg, "selected index {d} out of bounds of {}", .{
+ try sema.errNote(block, operand_info[chosen][1], msg, "selected index '{d}' out of bounds of '{}'", .{
unsigned,
operand_info[chosen][2].fmt(sema.mod),
});
- if (chosen == 1) {
+ if (chosen == 0) {
try sema.errNote(block, b_src, msg, "selections from the second vector are specified with negative numbers", .{});
}
@@ -16846,10 +16969,15 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
break :modifier modifier_val.toEnum(std.builtin.CallOptions.Modifier);
};
+ const is_comptime = extra.flags.is_comptime or block.is_comptime;
+
const modifier: std.builtin.CallOptions.Modifier = switch (wanted_modifier) {
// These can be upgraded to comptime or nosuspend calls.
.auto, .never_tail, .no_async => m: {
- if (extra.flags.is_comptime) {
+ if (is_comptime) {
+ if (wanted_modifier == .never_tail) {
+ return sema.fail(block, options_src, "unable to perform 'never_tail' call at compile-time", .{});
+ }
break :m .compile_time;
}
if (extra.flags.is_nosuspend) {
@@ -16859,7 +16987,11 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
},
// These can be upgraded to comptime. nosuspend bit can be safely ignored.
.always_tail, .always_inline, .compile_time => m: {
- if (extra.flags.is_comptime) {
+ _ = (try sema.resolveDefinedValue(block, func_src, func)) orelse {
+ return sema.fail(block, func_src, "modifier '{s}' requires a comptime-known function", .{@tagName(wanted_modifier)});
+ };
+
+ if (is_comptime) {
break :m .compile_time;
}
break :m wanted_modifier;
@@ -16868,14 +17000,14 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (extra.flags.is_nosuspend) {
return sema.fail(block, options_src, "modifier 'async_kw' cannot be used inside nosuspend block", .{});
}
- if (extra.flags.is_comptime) {
+ if (is_comptime) {
return sema.fail(block, options_src, "modifier 'async_kw' cannot be used in combination with comptime function call", .{});
}
break :m wanted_modifier;
},
.never_inline => m: {
- if (extra.flags.is_comptime) {
- return sema.fail(block, options_src, "modifier 'never_inline' cannot be used in combination with comptime function call", .{});
+ if (is_comptime) {
+ return sema.fail(block, options_src, "unable to perform 'never_inline' call at compile-time", .{});
}
break :m wanted_modifier;
},
@@ -16883,7 +17015,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const args_ty = sema.typeOf(args);
if (!args_ty.isTuple() and args_ty.tag() != .empty_struct_literal) {
- return sema.fail(block, args_src, "expected a tuple, found {}", .{args_ty.fmt(sema.mod)});
+ return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(sema.mod)});
}
var resolved_args: []Air.Inst.Ref = undefined;
@@ -17696,7 +17828,7 @@ fn zirBuiltinExtern(
}
fn requireFunctionBlock(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
- if (sema.func == null and !block.is_typeof) {
+ if (sema.func == null and !block.is_typeof and !block.is_coerce_result_ptr) {
return sema.fail(block, src, "instruction illegal outside function body", .{});
}
}
@@ -17765,7 +17897,8 @@ fn validateRunTimeType(
.Pointer => {
const elem_ty = ty.childType();
switch (elem_ty.zigTypeTag()) {
- .Opaque, .Fn => return true,
+ .Opaque => return true,
+ .Fn => return elem_ty.isFnOrHasRuntimeBits(),
else => ty = elem_ty,
}
},
@@ -17829,7 +17962,25 @@ fn explainWhyTypeIsComptime(
.Optional,
=> return,
- .Pointer, .Array, .Vector => {
+ .Array, .Vector => {
+ try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType());
+ },
+ .Pointer => {
+ const elem_ty = ty.elemType2();
+ if (elem_ty.zigTypeTag() == .Fn) {
+ const fn_info = elem_ty.fnInfo();
+ if (fn_info.is_generic) {
+ try mod.errNoteNonLazy(src_loc, msg, "function is generic", .{});
+ }
+ switch (fn_info.cc) {
+ .Inline => try mod.errNoteNonLazy(src_loc, msg, "function has inline calling convention", .{}),
+ else => {},
+ }
+ if (fn_info.return_type.comptimeOnly()) {
+ try mod.errNoteNonLazy(src_loc, msg, "function has a comptime-only return type", .{});
+ }
+ return;
+ }
try sema.explainWhyTypeIsComptime(block, src, msg, src_loc, ty.elemType());
},
@@ -18219,9 +18370,15 @@ fn fieldVal(
if (payload.data.names.getEntry(field_name)) |entry| {
break :blk entry.key_ptr.*;
}
- return sema.fail(block, src, "no error named '{s}' in '{}'", .{
- field_name, child_type.fmt(sema.mod),
- });
+ const msg = msg: {
+ const msg = try sema.errMsg(block, src, "no error named '{s}' in '{}'", .{
+ field_name, child_type.fmt(sema.mod),
+ });
+ errdefer msg.destroy(sema.gpa);
+ try sema.addDeclaredHereNote(msg, child_type);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(block, msg);
} else (try sema.mod.getErrorValue(field_name)).key;
return sema.addConstant(
@@ -18896,12 +19053,12 @@ fn tupleFieldIndex(
field_name_src: LazySrcLoc,
) CompileError!u32 {
const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch |err| {
- return sema.fail(block, field_name_src, "tuple {} has no such field '{s}': {s}", .{
+ return sema.fail(block, field_name_src, "tuple '{}' has no such field '{s}': {s}", .{
tuple_ty.fmt(sema.mod), field_name, @errorName(err),
});
};
if (field_index >= tuple_ty.structFieldCount()) {
- return sema.fail(block, field_name_src, "tuple {} has no such field '{s}'", .{
+ return sema.fail(block, field_name_src, "tuple '{}' has no such field '{s}'", .{
tuple_ty.fmt(sema.mod), field_name,
});
}
@@ -19811,7 +19968,7 @@ fn coerce(
return sema.fail(
block,
inst_src,
- "fractional component prevents float value {} from coercion to type '{}'",
+ "fractional component prevents float value '{}' from coercion to type '{}'",
.{ val.fmtValue(inst_ty, sema.mod), dest_ty.fmt(sema.mod) },
);
}
@@ -19821,8 +19978,8 @@ fn coerce(
.Int, .ComptimeInt => {
if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
// comptime known integer to other number
- if (!(try sema.intFitsInType(block, inst_src, val, dest_ty))) {
- return sema.fail(block, inst_src, "type {} cannot represent integer value {}", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
+ if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) {
+ return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
}
return try sema.addConstant(dest_ty, val);
}
@@ -19856,7 +20013,7 @@ fn coerce(
return sema.fail(
block,
inst_src,
- "type {} cannot represent float value {}",
+ "type '{}' cannot represent float value '{}'",
.{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) },
);
}
@@ -19880,7 +20037,7 @@ fn coerce(
// return sema.fail(
// block,
// inst_src,
- // "type {} cannot represent integer value {}",
+ // "type '{}' cannot represent integer value '{}'",
// .{ dest_ty.fmt(sema.mod), val },
// );
//}
@@ -20023,7 +20180,7 @@ fn coerce(
return sema.addConstUndef(dest_ty);
}
- return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });
+ return sema.fail(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });
}
const InMemoryCoercionResult = enum {
@@ -21543,7 +21700,7 @@ fn coerceEnumToUnion(
const tag_ty = union_ty.unionTagType() orelse {
const msg = msg: {
- const msg = try sema.errMsg(block, inst_src, "expected {}, found {}", .{
+ const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
});
errdefer msg.destroy(sema.gpa);
@@ -21559,7 +21716,7 @@ fn coerceEnumToUnion(
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
const field_index = union_obj.tag_ty.enumTagFieldIndex(val, sema.mod) orelse {
const msg = msg: {
- const msg = try sema.errMsg(block, inst_src, "union {} has no tag with value {}", .{
+ const msg = try sema.errMsg(block, inst_src, "union '{}' has no tag with value '{}'", .{
union_ty.fmt(sema.mod), val.fmtValue(tag_ty, sema.mod),
});
errdefer msg.destroy(sema.gpa);
@@ -21595,7 +21752,7 @@ fn coerceEnumToUnion(
if (tag_ty.isNonexhaustiveEnum()) {
const msg = msg: {
- const msg = try sema.errMsg(block, inst_src, "runtime coercion to union {} from non-exhaustive enum", .{
+ const msg = try sema.errMsg(block, inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{
union_ty.fmt(sema.mod),
});
errdefer msg.destroy(sema.gpa);
@@ -21712,7 +21869,7 @@ fn coerceArrayLike(
if (dest_len != inst_len) {
const msg = msg: {
- const msg = try sema.errMsg(block, inst_src, "expected {}, found {}", .{
+ const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
});
errdefer msg.destroy(sema.gpa);
@@ -21783,7 +21940,7 @@ fn coerceTupleToArray(
if (dest_len != inst_len) {
const msg = msg: {
- const msg = try sema.errMsg(block, inst_src, "expected {}, found {}", .{
+ const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
});
errdefer msg.destroy(sema.gpa);
@@ -23555,7 +23712,7 @@ fn resolveStructLayout(
switch (struct_obj.status) {
.none, .have_field_types => {},
.field_types_wip, .layout_wip => {
- return sema.fail(block, src, "struct {} depends on itself", .{ty.fmt(sema.mod)});
+ return sema.fail(block, src, "struct '{}' depends on itself", .{ty.fmt(sema.mod)});
},
.have_layout, .fully_resolved_wip, .fully_resolved => return,
}
@@ -23586,7 +23743,7 @@ fn resolveUnionLayout(
switch (union_obj.status) {
.none, .have_field_types => {},
.field_types_wip, .layout_wip => {
- return sema.fail(block, src, "union {} depends on itself", .{ty.fmt(sema.mod)});
+ return sema.fail(block, src, "union '{}' depends on itself", .{ty.fmt(sema.mod)});
},
.have_layout, .fully_resolved_wip, .fully_resolved => return,
}
@@ -23754,7 +23911,7 @@ fn resolveTypeFieldsStruct(
switch (struct_obj.status) {
.none => {},
.field_types_wip => {
- return sema.fail(block, src, "struct {} depends on itself", .{ty.fmt(sema.mod)});
+ return sema.fail(block, src, "struct '{}' depends on itself", .{ty.fmt(sema.mod)});
},
.have_field_types,
.have_layout,
@@ -23784,7 +23941,7 @@ fn resolveTypeFieldsUnion(
switch (union_obj.status) {
.none => {},
.field_types_wip => {
- return sema.fail(block, src, "union {} depends on itself", .{ty.fmt(sema.mod)});
+ return sema.fail(block, src, "union '{}' depends on itself", .{ty.fmt(sema.mod)});
},
.have_field_types,
.have_layout,
@@ -24161,7 +24318,7 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
if (small.auto_enum_tag) {
// The provided type is an integer type and we must construct the enum tag type here.
int_tag_ty = provided_ty;
- union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty);
+ union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty, union_obj);
const enum_obj = union_obj.tag_ty.castTag(.enum_numbered).?.data;
enum_field_names = &enum_obj.fields;
enum_value_map = &enum_obj.values;
@@ -24177,7 +24334,7 @@ fn semaUnionFields(block: *Block, mod: *Module, union_obj: *Module.Union) Compil
// If auto_enum_tag is false, this is an untagged union. However, for semantic analysis
// purposes, we still auto-generate an enum tag type the same way. That the union is
// untagged is represented by the Type tag (union vs union_tagged).
- union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, fields_len);
+ union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, fields_len, union_obj);
enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
}
@@ -24346,6 +24503,7 @@ fn generateUnionTagTypeNumbered(
block: *Block,
fields_len: u32,
int_ty: Type,
+ union_obj: *Module.Union,
) !Type {
const mod = sema.mod;
@@ -24361,13 +24519,24 @@ fn generateUnionTagTypeNumbered(
};
const enum_ty = Type.initPayload(&enum_ty_payload.base);
const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
- // TODO better type name
- const new_decl_index = try mod.createAnonymousDecl(block, .{
+
+ const src_decl = mod.declPtr(block.src_decl);
+ const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
+ errdefer mod.destroyDecl(new_decl_index);
+ const name = name: {
+ const fqn = try union_obj.getFullyQualifiedName(mod);
+ defer sema.gpa.free(fqn);
+ break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn});
+ };
+ try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
.ty = Type.type,
.val = enum_val,
- });
+ }, name);
+ sema.mod.declPtr(new_decl_index).name_fully_qualified = true;
+
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
+ new_decl.name_fully_qualified = true;
errdefer mod.abortAnonDecl(new_decl_index);
enum_obj.* = .{
@@ -24387,7 +24556,7 @@ fn generateUnionTagTypeNumbered(
return enum_ty;
}
-fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize) !Type {
+fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, maybe_union_obj: ?*Module.Union) !Type {
const mod = sema.mod;
var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
@@ -24402,11 +24571,30 @@ fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize) !Ty
};
const enum_ty = Type.initPayload(&enum_ty_payload.base);
const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
- // TODO better type name
- const new_decl_index = try mod.createAnonymousDecl(block, .{
- .ty = Type.type,
- .val = enum_val,
- });
+
+ const new_decl_index = new_decl_index: {
+ const union_obj = maybe_union_obj orelse {
+ break :new_decl_index try mod.createAnonymousDecl(block, .{
+ .ty = Type.type,
+ .val = enum_val,
+ });
+ };
+ const src_decl = mod.declPtr(block.src_decl);
+ const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
+ errdefer mod.destroyDecl(new_decl_index);
+ const name = name: {
+ const fqn = try union_obj.getFullyQualifiedName(mod);
+ defer sema.gpa.free(fqn);
+ break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn});
+ };
+ try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
+ .ty = Type.type,
+ .val = enum_val,
+ }, name);
+ sema.mod.declPtr(new_decl_index).name_fully_qualified = true;
+ break :new_decl_index new_decl_index;
+ };
+
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
@@ -25007,7 +25195,7 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
// The type is not in-memory coercible or the direct dereference failed, so it must
// be bitcast according to the pointer type we are performing the load through.
if (!load_ty.hasWellDefinedLayout())
- return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{load_ty.fmt(sema.mod)});
+ return sema.fail(block, src, "comptime dereference requires '{}' to have a well-defined layout, but it does not.", .{load_ty.fmt(sema.mod)});
const load_sz = try sema.typeAbiSize(block, src, load_ty);
@@ -25022,11 +25210,11 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
if (deref.ty_without_well_defined_layout) |bad_ty| {
// We got no parent for bit-casting, or the parent we got was too small. Either way, the problem
// is that some type we encountered when de-referencing does not have a well-defined layout.
- return sema.fail(block, src, "comptime dereference requires {} to have a well-defined layout, but it does not.", .{bad_ty.fmt(sema.mod)});
+ return sema.fail(block, src, "comptime dereference requires '{}' to have a well-defined layout, but it does not.", .{bad_ty.fmt(sema.mod)});
} else {
// If all encountered types had well-defined layouts, the parent is the root decl and it just
// wasn't big enough for the load.
- return sema.fail(block, src, "dereference of {} exceeds bounds of containing decl of type {}", .{ ptr_ty.fmt(sema.mod), deref.parent.?.tv.ty.fmt(sema.mod) });
+ return sema.fail(block, src, "dereference of '{}' exceeds bounds of containing decl of type '{}'", .{ ptr_ty.fmt(sema.mod), deref.parent.?.tv.ty.fmt(sema.mod) });
}
}
@@ -25034,7 +25222,7 @@ fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr
/// is too big to fit.
fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError!usize {
if (@bitSizeOf(u64) <= @bitSizeOf(usize)) return int;
- return std.math.cast(usize, int) orelse return sema.fail(block, src, "expression produces integer value {d} which is too big for this compiler implementation to handle", .{int});
+ return std.math.cast(usize, int) orelse return sema.fail(block, src, "expression produces integer value '{d}' which is too big for this compiler implementation to handle", .{int});
}
/// For pointer-like optionals, it returns the pointer type. For pointers,
@@ -25389,7 +25577,7 @@ fn anonStructFieldIndex(
return @intCast(u32, i);
}
}
- return sema.fail(block, field_src, "anonymous struct {} has no such field '{s}'", .{
+ return sema.fail(block, field_src, "anonymous struct '{}' has no such field '{s}'", .{
struct_ty.fmt(sema.mod), field_name,
});
}
@@ -25769,8 +25957,8 @@ fn floatToIntScalar(
else
try Value.Tag.int_big_positive.create(sema.arena, result_limbs);
- if (!(try sema.intFitsInType(block, src, result, int_ty))) {
- return sema.fail(block, src, "float value {} cannot be stored in integer type '{}'", .{
+ if (!(try sema.intFitsInType(block, src, result, int_ty, null))) {
+ return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{
val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod),
});
}
@@ -25785,6 +25973,7 @@ fn intFitsInType(
src: LazySrcLoc,
self: Value,
ty: Type,
+ vector_index: ?*usize,
) CompileError!bool {
const target = sema.mod.getTarget();
switch (self.tag()) {
@@ -25894,8 +26083,9 @@ fn intFitsInType(
.aggregate => {
assert(ty.zigTypeTag() == .Vector);
- for (self.castTag(.aggregate).?.data) |elem| {
- if (!(try sema.intFitsInType(block, src, elem, ty.scalarType()))) {
+ for (self.castTag(.aggregate).?.data) |elem, i| {
+ if (!(try sema.intFitsInType(block, src, elem, ty.scalarType(), null))) {
+ if (vector_index) |some| some.* = i;
return false;
}
}
@@ -25933,7 +26123,7 @@ fn enumHasInt(
int: Value,
) CompileError!bool {
switch (ty.tag()) {
- .enum_nonexhaustive => return sema.intFitsInType(block, src, int, ty),
+ .enum_nonexhaustive => return sema.intFitsInType(block, src, int, ty, null),
.enum_full => {
const enum_full = ty.castTag(.enum_full).?.data;
const tag_ty = enum_full.tag_ty;