Sema: perform requested coercion when decl literal demoted to enum literal

Resolves: #21392
This commit is contained in:
mlugg 2024-09-12 19:20:52 +01:00 committed by Matthew Lugg
parent 03c363300f
commit 55250a9370
2 changed files with 31 additions and 17 deletions

View File

@ -8980,36 +8980,41 @@ fn zirDeclLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index, do_coerce: b
sema.code.nullTerminatedString(extra.field_name_start),
.no_embedded_nulls,
);
const orig_ty = sema.resolveType(block, src, extra.lhs) catch |err| switch (err) {
error.GenericPoison => {
// Treat this as a normal enum literal.
return Air.internedToRef(try pt.intern(.{ .enum_literal = name }));
},
error.GenericPoison => Type.generic_poison,
else => |e| return e,
};
var ty = orig_ty;
while (true) switch (ty.zigTypeTag(zcu)) {
.error_union => ty = ty.errorUnionPayload(zcu),
.optional => ty = ty.optionalChild(zcu),
.enum_literal, .error_set => {
const uncoerced_result = res: {
if (orig_ty.toIntern() == .generic_poison_type) {
// Treat this as a normal enum literal.
return Air.internedToRef(try pt.intern(.{ .enum_literal = name }));
},
else => break,
break :res Air.internedToRef(try pt.intern(.{ .enum_literal = name }));
}
var ty = orig_ty;
while (true) switch (ty.zigTypeTag(zcu)) {
.error_union => ty = ty.errorUnionPayload(zcu),
.optional => ty = ty.optionalChild(zcu),
.enum_literal, .error_set => {
// Treat this as a normal enum literal.
break :res Air.internedToRef(try pt.intern(.{ .enum_literal = name }));
},
else => break,
};
break :res try sema.fieldVal(block, src, Air.internedToRef(ty.toIntern()), name, src);
};
const result = try sema.fieldVal(block, src, Air.internedToRef(ty.toIntern()), name, src);
// Decl literals cannot lookup runtime `var`s.
if (!try sema.isComptimeKnown(result)) {
if (!try sema.isComptimeKnown(uncoerced_result)) {
return sema.fail(block, src, "decl literal must be comptime-known", .{});
}
if (do_coerce) {
return sema.coerce(block, orig_ty, result, src);
return sema.coerce(block, orig_ty, uncoerced_result, src);
} else {
return result;
return uncoerced_result;
}
}

View File

@ -0,0 +1,9 @@
export fn entry() void {
const E = error{Foo};
const e: E = .Foo;
_ = e;
}
// error
//
// :3:19: error: expected type 'error{Foo}', found '@TypeOf(.enum_literal)'