stage1: Fix edge case in casting between optional types

Closes #6370
This commit is contained in:
LemonBoy 2020-09-18 21:25:37 +02:00 committed by Andrew Kelley
parent 4fbf9f7f79
commit f92d01c8a8
2 changed files with 28 additions and 1 deletions

View File

@ -63,6 +63,7 @@ enum ConstCastResultId {
ConstCastResultIdPointerChild, ConstCastResultIdPointerChild,
ConstCastResultIdSliceChild, ConstCastResultIdSliceChild,
ConstCastResultIdOptionalChild, ConstCastResultIdOptionalChild,
ConstCastResultIdOptionalShape,
ConstCastResultIdErrorUnionPayload, ConstCastResultIdErrorUnionPayload,
ConstCastResultIdErrorUnionErrorSet, ConstCastResultIdErrorUnionErrorSet,
ConstCastResultIdFnAlign, ConstCastResultIdFnAlign,
@ -11946,8 +11947,22 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
} }
} }
// maybe // optional types
if (wanted_type->id == ZigTypeIdOptional && actual_type->id == ZigTypeIdOptional) { if (wanted_type->id == ZigTypeIdOptional && actual_type->id == ZigTypeIdOptional) {
// Consider the case where the wanted type is ??[*]T and the actual one
// is ?[*]T, we cannot turn the former into the latter even though the
// child types are compatible (?[*]T and [*]T are both represented as a
// pointer). The extra level of indirection in ??[*]T means it's
// represented as a regular, fat, optional type and, as a consequence,
// has a different shape than the one of ?[*]T.
if ((wanted_ptr_type != nullptr) != (actual_ptr_type != nullptr)) {
// The use of type_mismatch is intentional
result.id = ConstCastResultIdOptionalShape;
result.data.type_mismatch = heap::c_allocator.allocate_nonzero<ConstCastTypeMismatch>(1);
result.data.type_mismatch->wanted_type = wanted_type;
result.data.type_mismatch->actual_type = actual_type;
return result;
}
ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.maybe.child_type, ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.maybe.child_type,
actual_type->data.maybe.child_type, source_node, wanted_is_mutable); actual_type->data.maybe.child_type, source_node, wanted_is_mutable);
if (child.id == ConstCastResultIdInvalid) if (child.id == ConstCastResultIdInvalid)
@ -14549,6 +14564,13 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
report_recursive_error(ira, source_node, &cast_result->data.optional->child, msg); report_recursive_error(ira, source_node, &cast_result->data.optional->child, msg);
break; break;
} }
case ConstCastResultIdOptionalShape: {
add_error_note(ira->codegen, parent_msg, source_node,
buf_sprintf("optional type child '%s' cannot cast into optional type '%s'",
buf_ptr(&cast_result->data.type_mismatch->actual_type->name),
buf_ptr(&cast_result->data.type_mismatch->wanted_type->name)));
break;
}
case ConstCastResultIdErrorUnionErrorSet: { case ConstCastResultIdErrorUnionErrorSet: {
ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
buf_sprintf("error set '%s' cannot cast into error set '%s'", buf_sprintf("error set '%s' cannot cast into error set '%s'",

View File

@ -849,3 +849,8 @@ test "comptime float casts" {
expect(b == 2); expect(b == 2);
expect(@TypeOf(b) == comptime_int); expect(@TypeOf(b) == comptime_int);
} }
test "cast from ?[*]T to ??[*]T" {
const a: ??[*]u8 = @as(?[*]u8, null);
expect(a != null and a.? == null);
}