Skip to content

Commit 7c942cc

Browse files
committedAug 3, 2023
Don't be incomplete
1 parent 238beae commit 7c942cc

File tree

3 files changed

+128
-92
lines changed

3 files changed

+128
-92
lines changed
 

‎compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+26-9
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
745745

746746
match (source.kind(), target.kind()) {
747747
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
748-
(&ty::Dynamic(ref data_a, _, ty::Dyn), &ty::Dynamic(ref data_b, _, ty::Dyn)) => {
748+
(
749+
&ty::Dynamic(ref a_data, a_region, ty::Dyn),
750+
&ty::Dynamic(ref b_data, b_region, ty::Dyn),
751+
) => {
749752
// Upcast coercions permit several things:
750753
//
751754
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
@@ -757,19 +760,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
757760
//
758761
// We always perform upcasting coercions when we can because of reason
759762
// #2 (region bounds).
760-
let auto_traits_compatible = data_b
763+
let auto_traits_compatible = b_data
761764
.auto_traits()
762765
// All of a's auto traits need to be in b's auto traits.
763-
.all(|b| data_a.auto_traits().any(|a| a == b));
766+
.all(|b| a_data.auto_traits().any(|a| a == b));
764767
if auto_traits_compatible {
765-
let principal_def_id_a = data_a.principal_def_id();
766-
let principal_def_id_b = data_b.principal_def_id();
768+
let principal_def_id_a = a_data.principal_def_id();
769+
let principal_def_id_b = b_data.principal_def_id();
767770
if principal_def_id_a == principal_def_id_b {
768771
// no cyclic
769772
candidates.vec.push(BuiltinUnsizeCandidate);
770773
} else if principal_def_id_a.is_some() && principal_def_id_b.is_some() {
771774
// not casual unsizing, now check whether this is trait upcasting coercion.
772-
let principal_a = data_a.principal().unwrap();
775+
let principal_a = a_data.principal().unwrap();
773776
let target_trait_did = principal_def_id_b.unwrap();
774777
let source_trait_ref = principal_a.with_self_ty(self.tcx(), source);
775778
if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object(
@@ -785,9 +788,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
785788
for (idx, upcast_trait_ref) in
786789
util::supertraits(self.tcx(), source_trait_ref).enumerate()
787790
{
788-
if upcast_trait_ref.def_id() == target_trait_did {
789-
candidates.vec.push(TraitUpcastingUnsizeCandidate(idx));
790-
}
791+
self.infcx.probe(|_| {
792+
if upcast_trait_ref.def_id() == target_trait_did
793+
&& let Ok(nested) = self.match_upcast_principal(
794+
obligation,
795+
upcast_trait_ref,
796+
a_data,
797+
b_data,
798+
a_region,
799+
b_region,
800+
)
801+
{
802+
if nested.is_none() {
803+
candidates.ambiguous = true;
804+
}
805+
candidates.vec.push(TraitUpcastingUnsizeCandidate(idx));
806+
}
807+
})
791808
}
792809
}
793810
}

‎compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+10-83
Original file line numberDiff line numberDiff line change
@@ -890,89 +890,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
890890
let unnormalized_upcast_principal =
891891
util::supertraits(tcx, source_principal).nth(idx).unwrap();
892892

893-
let mut nested = vec![];
894-
let upcast_principal = normalize_with_depth_to(
895-
self,
896-
obligation.param_env,
897-
obligation.cause.clone(),
898-
obligation.recursion_depth + 1,
899-
unnormalized_upcast_principal,
900-
&mut nested,
901-
);
902-
903-
for bound in b_data {
904-
match bound.skip_binder() {
905-
// Check that a's supertrait (upcast_principal) is compatible
906-
// with the target (b_ty).
907-
ty::ExistentialPredicate::Trait(target_principal) => {
908-
nested.extend(
909-
self.infcx
910-
.at(&obligation.cause, obligation.param_env)
911-
.sup(
912-
DefineOpaqueTypes::No,
913-
upcast_principal.map_bound(|trait_ref| {
914-
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
915-
}),
916-
bound.rebind(target_principal),
917-
)
918-
.map_err(|_| SelectionError::Unimplemented)?
919-
.into_obligations(),
920-
);
921-
}
922-
// Check that b_ty's projection is satisfied by exactly one of
923-
// a_ty's projections. First, we look through the list to see if
924-
// any match. If not, error. Then, if *more* than one matches, we
925-
// return ambiguity. Otherwise, if exactly one matches, equate
926-
// it with b_ty's projection.
927-
ty::ExistentialPredicate::Projection(target_projection) => {
928-
let target_projection = bound.rebind(target_projection);
929-
let mut matching_projections =
930-
a_data.projection_bounds().filter(|source_projection| {
931-
// Eager normalization means that we can just use can_eq
932-
// here instead of equating and processing obligations.
933-
source_projection.item_def_id() == target_projection.item_def_id()
934-
&& self.infcx.can_eq(
935-
obligation.param_env,
936-
*source_projection,
937-
target_projection,
938-
)
939-
});
940-
let Some(source_projection) = matching_projections.next() else {
941-
return Err(SelectionError::Unimplemented);
942-
};
943-
if matching_projections.next().is_some() {
944-
// This is incomplete but I don't care. We should never
945-
// have more than one projection that ever applies with
946-
// eager norm and actually implementable traits, since
947-
// you can't have two supertraits like:
948-
// `trait A: B<i32, Assoc = First> + B<i32, Assoc = Second>`
949-
return Err(SelectionError::Unimplemented);
950-
}
951-
nested.extend(
952-
self.infcx
953-
.at(&obligation.cause, obligation.param_env)
954-
.sup(DefineOpaqueTypes::No, source_projection, target_projection)
955-
.map_err(|_| SelectionError::Unimplemented)?
956-
.into_obligations(),
957-
);
958-
}
959-
// Check that b_ty's auto trait is present in a_ty's bounds.
960-
ty::ExistentialPredicate::AutoTrait(def_id) => {
961-
if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) {
962-
return Err(SelectionError::Unimplemented);
963-
}
964-
}
965-
}
966-
}
967-
968-
// Also require that a_ty's lifetime outlives b_ty's lifetime.
969-
nested.push(Obligation::with_depth(
970-
tcx,
971-
obligation.cause.clone(),
972-
obligation.recursion_depth + 1,
973-
obligation.param_env,
974-
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
975-
));
893+
let nested = self
894+
.match_upcast_principal(
895+
obligation,
896+
unnormalized_upcast_principal,
897+
a_data,
898+
b_data,
899+
a_region,
900+
b_region,
901+
)?
902+
.expect("did not expect ambiguity during confirmation");
976903

977904
let vtable_segment_callback = {
978905
let mut vptr_offset = 0;

‎compiler/rustc_trait_selection/src/traits/select/mod.rs

+92
Original file line numberDiff line numberDiff line change
@@ -2477,6 +2477,98 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
24772477
Ok(Normalized { value: impl_args, obligations: nested_obligations })
24782478
}
24792479

2480+
fn match_upcast_principal(
2481+
&mut self,
2482+
obligation: &PolyTraitObligation<'tcx>,
2483+
unnormalized_upcast_principal: ty::PolyTraitRef<'tcx>,
2484+
a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
2485+
b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
2486+
a_region: ty::Region<'tcx>,
2487+
b_region: ty::Region<'tcx>,
2488+
) -> SelectionResult<'tcx, Vec<PredicateObligation<'tcx>>> {
2489+
let tcx = self.tcx();
2490+
let mut nested = vec![];
2491+
2492+
let upcast_principal = normalize_with_depth_to(
2493+
self,
2494+
obligation.param_env,
2495+
obligation.cause.clone(),
2496+
obligation.recursion_depth + 1,
2497+
unnormalized_upcast_principal,
2498+
&mut nested,
2499+
);
2500+
2501+
for bound in b_data {
2502+
match bound.skip_binder() {
2503+
// Check that a_ty's supertrait (upcast_principal) is compatible
2504+
// with the target (b_ty).
2505+
ty::ExistentialPredicate::Trait(target_principal) => {
2506+
nested.extend(
2507+
self.infcx
2508+
.at(&obligation.cause, obligation.param_env)
2509+
.sup(
2510+
DefineOpaqueTypes::No,
2511+
upcast_principal.map_bound(|trait_ref| {
2512+
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
2513+
}),
2514+
bound.rebind(target_principal),
2515+
)
2516+
.map_err(|_| SelectionError::Unimplemented)?
2517+
.into_obligations(),
2518+
);
2519+
}
2520+
// Check that b_ty's projection is satisfied by exactly one of
2521+
// a_ty's projections. First, we look through the list to see if
2522+
// any match. If not, error. Then, if *more* than one matches, we
2523+
// return ambiguity. Otherwise, if exactly one matches, equate
2524+
// it with b_ty's projection.
2525+
ty::ExistentialPredicate::Projection(target_projection) => {
2526+
let target_projection = bound.rebind(target_projection);
2527+
let mut matching_projections =
2528+
a_data.projection_bounds().filter(|source_projection| {
2529+
// Eager normalization means that we can just use can_eq
2530+
// here instead of equating and processing obligations.
2531+
source_projection.item_def_id() == target_projection.item_def_id()
2532+
&& self.infcx.can_eq(
2533+
obligation.param_env,
2534+
*source_projection,
2535+
target_projection,
2536+
)
2537+
});
2538+
let Some(source_projection) = matching_projections.next() else {
2539+
return Err(SelectionError::Unimplemented);
2540+
};
2541+
if matching_projections.next().is_some() {
2542+
return Ok(None);
2543+
}
2544+
nested.extend(
2545+
self.infcx
2546+
.at(&obligation.cause, obligation.param_env)
2547+
.sup(DefineOpaqueTypes::No, source_projection, target_projection)
2548+
.map_err(|_| SelectionError::Unimplemented)?
2549+
.into_obligations(),
2550+
);
2551+
}
2552+
// Check that b_ty's auto traits are present in a_ty's bounds.
2553+
ty::ExistentialPredicate::AutoTrait(def_id) => {
2554+
if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) {
2555+
return Err(SelectionError::Unimplemented);
2556+
}
2557+
}
2558+
}
2559+
}
2560+
2561+
nested.push(Obligation::with_depth(
2562+
tcx,
2563+
obligation.cause.clone(),
2564+
obligation.recursion_depth + 1,
2565+
obligation.param_env,
2566+
ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)),
2567+
));
2568+
2569+
Ok(Some(nested))
2570+
}
2571+
24802572
/// Normalize `where_clause_trait_ref` and try to match it against
24812573
/// `obligation`. If successful, return any predicates that
24822574
/// result from the normalization.

0 commit comments

Comments
 (0)
Please sign in to comment.