Allow derived->base conversions with compatible qualifiers (#7415)

Move the existing derived->base conversion earlier in
`PerformBuiltinConversion`, into the block that handles qualifier
conversions. This allows, for example, converting from `partial Derived`
to `partial Base` -- see the tests in
`toolchain/check/testdata/class/inheritance/derived_to_base.carbon`.
This commit is contained in:
Nicholas Bishop
2026-06-24 21:08:24 +00:00
committed by GitHub
parent f2d99f31f0
commit 885b1110d5
20 changed files with 345 additions and 288 deletions
+13 -11
View File
@@ -1322,7 +1322,12 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
target.is_explicit_as()
? context.types().GetTransitiveUnqualifiedAdaptedType(value_type_id)
: context.types().GetUnqualifiedTypeAndQualifiers(value_type_id);
if (target_foundation_id == value_foundation_id) {
auto inheritance_path = ComputeInheritancePath(
context, loc_id, value_foundation_id, target_foundation_id);
if (inheritance_path && inheritance_path->empty()) {
inheritance_path = std::nullopt;
}
if (target_foundation_id == value_foundation_id || inheritance_path) {
auto category = SemIR::GetExprCategory(context.sem_ir(), value_id);
auto added_quals = target_quals & ~value_quals;
auto removed_quals = value_quals & ~target_quals;
@@ -1378,6 +1383,13 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
context, loc_id,
{.type_id = target.type_id, .value_id = value_id});
}
// An expression of type T converts to U if T is a class derived from U.
if (inheritance_path) {
value_id = ConvertDerivedToBase(context, loc_id, value_id,
*inheritance_path);
}
return value_id;
} else {
// TODO: Produce a custom diagnostic explaining that we can't perform
@@ -1448,16 +1460,6 @@ static auto PerformBuiltinConversion(Context& context, SemIR::LocId loc_id,
target_quals.HasAnyOf(SemIR::TypeQualifiers::Partial));
}
}
// An expression of type T converts to U if T is a class derived from U.
//
// TODO: Combine this with the qualifiers and adapter conversion logic above
// to allow qualifiers and inheritance conversions to be performed together.
if (auto path = ComputeInheritancePath(context, loc_id, value_type_id,
target.type_id);
path && !path->empty()) {
return ConvertDerivedToBase(context, loc_id, value_id, *path);
}
}
// A pointer T* converts to [qualified] U* if T is the same as U, or is a