authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-17 19:59:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-17 19:59:20-07:00
log1d1364c3cd296d628501bce131513ce18d2055a3
tree1cbd0803b10a57c980edca7223875d15e5a41af9
parent46ba24010af521936e416160decb660fe56cb484

Sema: change how undefined is handled in coerce

Instead of doing it before the switch tower, do it afterwards, so that special handling may be done before undefined gets casted to the destination type. In this case the special handling we want to do is *[N]T to []T setting the slice length based on the array length, even when the array value is undefined.

2 files changed, 48 insertions(+), 20 deletions(-)

src/Sema.zig+45-15
......@@ -16945,10 +16945,11 @@ fn coerce(
1694516945
1694616946 const arena = sema.arena;
1694716947 const target = sema.mod.getTarget();
16948 const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst);
1694816949
1694916950 const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
1695016951 if (in_memory_result == .ok) {
16951 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
16952 if (maybe_inst_val) |val| {
1695216953 // Keep the comptime Value representation; take the new type.
1695316954 return sema.addConstant(dest_ty, val);
1695416955 }
......@@ -16956,16 +16957,15 @@ fn coerce(
1695616957 return block.addBitCast(dest_ty, inst);
1695716958 }
1695816959
16959 // undefined to anything
16960 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
16961 if (val.isUndef() or inst_ty.zigTypeTag() == .Undefined) {
16962 return sema.addConstant(dest_ty, val);
16963 }
16964 }
16965 assert(inst_ty.zigTypeTag() != .Undefined);
16960 const is_undef = if (maybe_inst_val) |val| val.isUndef() else false;
1696616961
1696716962 switch (dest_ty.zigTypeTag()) {
1696816963 .Optional => {
16964 // undefined sets the optional bit also to undefined.
16965 if (is_undef) {
16966 return sema.addConstUndef(dest_ty);
16967 }
16968
1696916969 // null to ?T
1697016970 if (inst_ty.zigTypeTag() == .Null) {
1697116971 return sema.addConstant(dest_ty, Value.@"null");
......@@ -17167,8 +17167,8 @@ fn coerce(
1716717167 }
1716817168 },
1716917169 .Many => p: {
17170 if (!inst_ty.isSlice()) break :p;
1717017171 const inst_info = inst_ty.ptrInfo().data;
17171 if (inst_info.size != .Slice) break :p;
1717217172
1717317173 switch (try sema.coerceInMemoryAllowed(
1717417174 block,
......@@ -17191,9 +17191,6 @@ fn coerce(
1719117191 return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src);
1719217192 },
1719317193 }
17194
17195 // This will give an extra hint on top of what the bottom of this func would provide.
17196 try sema.checkPtrOperand(block, dest_ty_src, inst_ty);
1719717194 },
1719817195 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
1719917196 .Float, .ComptimeFloat => float: {
......@@ -17230,6 +17227,9 @@ fn coerce(
1723017227 return block.addTyOp(.intcast, dest_ty, inst);
1723117228 }
1723217229 },
17230 .Undefined => {
17231 return sema.addConstUndef(dest_ty);
17232 },
1723317233 else => {},
1723417234 },
1723517235 .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag()) {
......@@ -17275,6 +17275,9 @@ fn coerce(
1727517275 //}
1727617276 return try sema.addConstant(dest_ty, result_val);
1727717277 },
17278 .Undefined => {
17279 return sema.addConstUndef(dest_ty);
17280 },
1727817281 else => {},
1727917282 },
1728017283 .Enum => switch (inst_ty.zigTypeTag()) {
......@@ -17313,11 +17316,14 @@ fn coerce(
1731317316 return sema.unionToTag(block, dest_ty, inst, inst_src);
1731417317 }
1731517318 },
17319 .Undefined => {
17320 return sema.addConstUndef(dest_ty);
17321 },
1731617322 else => {},
1731717323 },
1731817324 .ErrorUnion => switch (inst_ty.zigTypeTag()) {
1731917325 .ErrorUnion => {
17320 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |inst_val| {
17326 if (maybe_inst_val) |inst_val| {
1732117327 switch (inst_val.tag()) {
1732217328 .undef => return sema.addConstUndef(dest_ty),
1732317329 .eu_payload => {
......@@ -17341,7 +17347,15 @@ fn coerce(
1734117347 // E to E!T
1734217348 return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);
1734317349 },
17350 .Undefined => {
17351 return sema.addConstUndef(dest_ty);
17352 },
1734417353 else => {
17354 // undefined sets the error code also to undefined.
17355 if (is_undef) {
17356 return sema.addConstUndef(dest_ty);
17357 }
17358
1734517359 // T to E!T
1734617360 return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src);
1734717361 },
......@@ -17353,6 +17367,9 @@ fn coerce(
1735317367 return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
1735417368 }
1735517369 },
17370 .Undefined => {
17371 return sema.addConstUndef(dest_ty);
17372 },
1735617373 else => {},
1735717374 },
1735817375 .Array => switch (inst_ty.zigTypeTag()) {
......@@ -17365,10 +17382,16 @@ fn coerce(
1736517382 return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
1736617383 }
1736717384 },
17385 .Undefined => {
17386 return sema.addConstUndef(dest_ty);
17387 },
1736817388 else => {},
1736917389 },
1737017390 .Vector => switch (inst_ty.zigTypeTag()) {
1737117391 .Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
17392 .Undefined => {
17393 return sema.addConstUndef(dest_ty);
17394 },
1737217395 else => {},
1737317396 },
1737417397 .Struct => {
......@@ -17382,6 +17405,13 @@ fn coerce(
1738217405 else => {},
1738317406 }
1738417407
17408 // undefined to anything. We do this after the big switch above so that
17409 // special logic has a chance to run first, such as `*[N]T` to `[]T` which
17410 // should initialize the length field of the slice.
17411 if (is_undef) {
17412 return sema.addConstUndef(dest_ty);
17413 }
17414
1738517415 return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty, inst_ty });
1738617416}
1738717417
......@@ -18452,7 +18482,7 @@ fn coerceArrayPtrToSlice(
1845218482 inst: Air.Inst.Ref,
1845318483 inst_src: LazySrcLoc,
1845418484) CompileError!Air.Inst.Ref {
18455 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
18485 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
1845618486 const ptr_array_ty = sema.typeOf(inst);
1845718487 const array_ty = ptr_array_ty.childType();
1845818488 const slice_val = try Value.Tag.slice.create(sema.arena, .{
......@@ -21336,7 +21366,7 @@ fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref {
2133621366}
2133721367
2133821368fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {
21339 return sema.addConstant(ty, Value.initTag(.undef));
21369 return sema.addConstant(ty, Value.undef);
2134021370}
2134121371
2134221372pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {
test/behavior/struct.zig+3-5
......@@ -1138,11 +1138,9 @@ test "packed struct with undefined initializers" {
11381138}
11391139
11401140test "for loop over pointers to struct, getting field from struct pointer" {
1141 // When enabling this test, be careful. I have observed it to pass when compiling
1142 // stage2 alone, but when using stage1 with -fno-stage1 -fLLVM it fails.
1143 // Maybe eyeball the LLVM that it generates and run in valgrind, both the compiler
1144 // and the generated test at runtime.
1145 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1141 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1143 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11461144
11471145 const S = struct {
11481146 const Foo = struct {