@@ -673,13 +673,20 @@ static auto ConvertDerivedToBase(Context& context, SemIR::LocId loc_id,
673
673
// Materialize a temporary if necessary.
674
674
value_id = ConvertToValueOrRefExpr (context, value_id);
675
675
676
+ // Preserve type qualifiers.
677
+ auto quals = context.types ()
678
+ .GetUnqualifiedTypeAndQualifiers (
679
+ context.insts ().Get (value_id).type_id ())
680
+ .second ;
681
+
676
682
// Add a series of `.base` accesses.
677
683
for (auto [base_id, base_type_id] : path) {
678
684
auto base_decl = context.insts ().GetAs <SemIR::BaseDecl>(base_id);
679
- value_id = AddInst<SemIR::ClassElementAccess>(context, loc_id,
680
- {.type_id = base_type_id,
681
- .base_id = value_id,
682
- .index = base_decl.index });
685
+ value_id = AddInst<SemIR::ClassElementAccess>(
686
+ context, loc_id,
687
+ {.type_id = GetQualifiedType (context, base_type_id, quals),
688
+ .base_id = value_id,
689
+ .index = base_decl.index });
683
690
}
684
691
return value_id;
685
692
}
@@ -689,13 +696,13 @@ static auto ConvertDerivedPointerToBasePointer(
689
696
Context& context, SemIR::LocId loc_id, SemIR::PointerType src_ptr_type,
690
697
SemIR::TypeId dest_ptr_type_id, SemIR::InstId ptr_id,
691
698
const InheritancePath& path) -> SemIR::InstId {
699
+ auto pointee_type_id =
700
+ context.types ().GetTypeIdForTypeInstId (src_ptr_type.pointee_id );
701
+
692
702
// Form `*p`.
693
703
ptr_id = ConvertToValueExpr (context, ptr_id);
694
704
auto ref_id = AddInst<SemIR::Deref>(
695
- context, loc_id,
696
- {.type_id =
697
- context.types ().GetTypeIdForTypeInstId (src_ptr_type.pointee_id ),
698
- .pointer_id = ptr_id});
705
+ context, loc_id, {.type_id = pointee_type_id, .pointer_id = ptr_id});
699
706
700
707
// Convert as a reference expression.
701
708
ref_id = ConvertDerivedToBase (context, loc_id, ref_id, path);
@@ -950,6 +957,12 @@ static auto PerformBuiltinConversion(
950
957
}
951
958
}
952
959
960
+ // No other conversions apply when the source and destination types are the
961
+ // same.
962
+ if (value_type_id == target.type_id ) {
963
+ return value_id;
964
+ }
965
+
953
966
// A tuple (T1, T2, ..., Tn) converts to array(T, n) if each Ti converts to T.
954
967
if (auto target_array_type = target_type_inst.TryAs <SemIR::ArrayType>()) {
955
968
if (auto src_tuple_type =
@@ -983,21 +996,50 @@ static auto PerformBuiltinConversion(
983
996
}
984
997
}
985
998
986
- // A pointer T* converts to U* if T is a class derived from U.
999
+ // A pointer T* converts to [const] U* if T is the same as U, or is a class
1000
+ // derived from U.
987
1001
if (auto target_pointer_type = target_type_inst.TryAs <SemIR::PointerType>()) {
988
1002
if (auto src_pointer_type =
989
1003
sem_ir.types ().TryGetAs <SemIR::PointerType>(value_type_id)) {
990
- if (auto path =
991
- ComputeInheritancePath (context, loc_id,
992
- context.types ().GetTypeIdForTypeInstId (
993
- src_pointer_type->pointee_id ),
994
- context.types ().GetTypeIdForTypeInstId (
995
- target_pointer_type->pointee_id ));
996
- path && !path->empty ()) {
997
- return ConvertDerivedPointerToBasePointer (
998
- context, loc_id, *src_pointer_type, target.type_id , value_id,
999
- *path);
1004
+ auto [unqual_target_pointee_type_id, target_quals] =
1005
+ sem_ir.types ().GetUnqualifiedTypeAndQualifiers (
1006
+ context.types ().GetTypeIdForTypeInstId (
1007
+ target_pointer_type->pointee_id ));
1008
+ auto [unqual_src_pointee_type_id, src_quals] =
1009
+ sem_ir.types ().GetUnqualifiedTypeAndQualifiers (
1010
+ context.types ().GetTypeIdForTypeInstId (
1011
+ src_pointer_type->pointee_id ));
1012
+
1013
+ // If the qualifiers are incompatible, we can't perform a conversion.
1014
+ if ((src_quals & ~target_quals) != SemIR::TypeQualifiers::None) {
1015
+ // TODO: Consider producing a custom diagnostic here for a cast that
1016
+ // discards constness. We should allow this with `unsafe as`.
1017
+ return value_id;
1000
1018
}
1019
+
1020
+ if (unqual_target_pointee_type_id != unqual_src_pointee_type_id) {
1021
+ // If there's an inheritance path from target to source, this is a
1022
+ // derived to base conversion.
1023
+ if (auto path = ComputeInheritancePath (context, loc_id,
1024
+ unqual_src_pointee_type_id,
1025
+ unqual_target_pointee_type_id);
1026
+ path && !path->empty ()) {
1027
+ value_id = ConvertDerivedPointerToBasePointer (
1028
+ context, loc_id, *src_pointer_type, target.type_id , value_id,
1029
+ *path);
1030
+ } else {
1031
+ // No conversion was possible.
1032
+ return value_id;
1033
+ }
1034
+ }
1035
+
1036
+ // Perform a compatible conversion to add any new qualifiers.
1037
+ if (src_quals != target_quals) {
1038
+ return AddInst<SemIR::AsCompatible>(
1039
+ context, loc_id,
1040
+ {.type_id = target.type_id , .source_id = value_id});
1041
+ }
1042
+ return value_id;
1001
1043
}
1002
1044
}
1003
1045
0 commit comments