Skip to content

Commit a03707d

Browse files
committed
refactor: use select inside of a probe
We ought not to be affecting inference state when assembling candidates, so invoke select inside of a probe.
1 parent 4aeadfa commit a03707d

File tree

1 file changed

+172
-118
lines changed

1 file changed

+172
-118
lines changed

src/librustc/traits/project.rs

Lines changed: 172 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,8 @@ enum ProjectionTyCandidate<'tcx> {
152152
// from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
153153
TraitDef(ty::PolyProjectionPredicate<'tcx>),
154154

155-
// defined in an impl
156-
Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
157-
158-
// closure return type
159-
Closure(VtableClosureData<'tcx, PredicateObligation<'tcx>>),
160-
161-
// fn pointer return type
162-
FnPointer(Ty<'tcx>),
155+
// from a "impl" (or a "pseudo-impl" returned by select)
156+
Select,
163157
}
164158

165159
struct ProjectionTyCandidateSet<'tcx> {
@@ -652,10 +646,8 @@ fn project_type<'cx,'tcx>(
652646
debug!("retaining param-env candidates only from {:?}", candidates.vec);
653647
candidates.vec.retain(|c| match *c {
654648
ProjectionTyCandidate::ParamEnv(..) => true,
655-
ProjectionTyCandidate::Impl(..) |
656-
ProjectionTyCandidate::Closure(..) |
657649
ProjectionTyCandidate::TraitDef(..) |
658-
ProjectionTyCandidate::FnPointer(..) => false,
650+
ProjectionTyCandidate::Select => false,
659651
});
660652
debug!("resulting candidate set: {:?}", candidates.vec);
661653
if candidates.vec.len() != 1 {
@@ -736,7 +728,10 @@ fn project_type<'cx,'tcx>(
736728

737729
match possible_candidate {
738730
Some(candidate) => {
739-
let (ty, obligations) = confirm_candidate(selcx, obligation, candidate);
731+
let (ty, obligations) = confirm_candidate(selcx,
732+
obligation,
733+
&obligation_trait_ref,
734+
candidate);
740735
Ok(ProjectedTy::Progress(ty, obligations))
741736
}
742737
None => {
@@ -855,38 +850,6 @@ fn assemble_candidates_from_predicates<'cx,'tcx,I>(
855850
}
856851
}
857852

858-
fn assemble_candidates_from_object_type<'cx,'tcx>(
859-
selcx: &mut SelectionContext<'cx,'tcx>,
860-
obligation: &ProjectionTyObligation<'tcx>,
861-
obligation_trait_ref: &ty::TraitRef<'tcx>,
862-
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
863-
{
864-
let self_ty = obligation_trait_ref.self_ty();
865-
let object_ty = selcx.infcx().shallow_resolve(self_ty);
866-
debug!("assemble_candidates_from_object_type(object_ty={:?})",
867-
object_ty);
868-
let data = match object_ty.sty {
869-
ty::TyTrait(ref data) => data,
870-
_ => {
871-
span_bug!(
872-
obligation.cause.span,
873-
"assemble_candidates_from_object_type called with non-object: {:?}",
874-
object_ty);
875-
}
876-
};
877-
let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty);
878-
let env_predicates = projection_bounds.iter()
879-
.map(|p| p.to_predicate())
880-
.collect();
881-
let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
882-
assemble_candidates_from_predicates(selcx,
883-
obligation,
884-
obligation_trait_ref,
885-
candidate_set,
886-
ProjectionTyCandidate::ParamEnv,
887-
env_predicates)
888-
}
889-
890853
fn assemble_candidates_from_impls<'cx,'tcx>(
891854
selcx: &mut SelectionContext<'cx,'tcx>,
892855
obligation: &ProjectionTyObligation<'tcx>,
@@ -898,82 +861,75 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
898861
// start out by selecting the predicate `T as TraitRef<...>`:
899862
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
900863
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
901-
let vtable = match selcx.select(&trait_obligation) {
902-
Ok(Some(vtable)) => vtable,
903-
Ok(None) => {
904-
candidate_set.ambiguous = true;
905-
return Ok(());
906-
}
907-
Err(e) => {
908-
debug!("assemble_candidates_from_impls: selection error {:?}",
909-
e);
910-
return Err(e);
911-
}
912-
};
864+
selcx.infcx().probe(|_| {
865+
let vtable = match selcx.select(&trait_obligation) {
866+
Ok(Some(vtable)) => vtable,
867+
Ok(None) => {
868+
candidate_set.ambiguous = true;
869+
return Ok(());
870+
}
871+
Err(e) => {
872+
debug!("assemble_candidates_from_impls: selection error {:?}",
873+
e);
874+
return Err(e);
875+
}
876+
};
913877

914-
match vtable {
915-
super::VtableImpl(data) => {
916-
debug!("assemble_candidates_from_impls: impl candidate {:?}",
917-
data);
878+
match vtable {
879+
super::VtableImpl(_) |
880+
super::VtableClosure(_) |
881+
super::VtableFnPointer(_) |
882+
super::VtableObject(_) => {
883+
debug!("assemble_candidates_from_impls: vtable={:?}",
884+
vtable);
918885

919-
candidate_set.vec.push(
920-
ProjectionTyCandidate::Impl(data));
921-
}
922-
super::VtableObject(_) => {
923-
assemble_candidates_from_object_type(
924-
selcx, obligation, obligation_trait_ref, candidate_set);
925-
}
926-
super::VtableClosure(data) => {
927-
candidate_set.vec.push(
928-
ProjectionTyCandidate::Closure(data));
929-
}
930-
super::VtableFnPointer(fn_type) => {
931-
candidate_set.vec.push(
932-
ProjectionTyCandidate::FnPointer(fn_type));
933-
}
934-
super::VtableParam(..) => {
935-
// This case tell us nothing about the value of an
936-
// associated type. Consider:
937-
//
938-
// ```
939-
// trait SomeTrait { type Foo; }
940-
// fn foo<T:SomeTrait>(...) { }
941-
// ```
942-
//
943-
// If the user writes `<T as SomeTrait>::Foo`, then the `T
944-
// : SomeTrait` binding does not help us decide what the
945-
// type `Foo` is (at least, not more specifically than
946-
// what we already knew).
947-
//
948-
// But wait, you say! What about an example like this:
949-
//
950-
// ```
951-
// fn bar<T:SomeTrait<Foo=usize>>(...) { ... }
952-
// ```
953-
//
954-
// Doesn't the `T : Sometrait<Foo=usize>` predicate help
955-
// resolve `T::Foo`? And of course it does, but in fact
956-
// that single predicate is desugared into two predicates
957-
// in the compiler: a trait predicate (`T : SomeTrait`) and a
958-
// projection. And the projection where clause is handled
959-
// in `assemble_candidates_from_param_env`.
960-
}
961-
super::VtableDefaultImpl(..) |
962-
super::VtableBuiltin(..) => {
963-
// These traits have no associated types.
964-
span_bug!(
965-
obligation.cause.span,
966-
"Cannot project an associated type from `{:?}`",
967-
vtable);
886+
candidate_set.vec.push(ProjectionTyCandidate::Select);
887+
}
888+
super::VtableParam(..) => {
889+
// This case tell us nothing about the value of an
890+
// associated type. Consider:
891+
//
892+
// ```
893+
// trait SomeTrait { type Foo; }
894+
// fn foo<T:SomeTrait>(...) { }
895+
// ```
896+
//
897+
// If the user writes `<T as SomeTrait>::Foo`, then the `T
898+
// : SomeTrait` binding does not help us decide what the
899+
// type `Foo` is (at least, not more specifically than
900+
// what we already knew).
901+
//
902+
// But wait, you say! What about an example like this:
903+
//
904+
// ```
905+
// fn bar<T:SomeTrait<Foo=usize>>(...) { ... }
906+
// ```
907+
//
908+
// Doesn't the `T : Sometrait<Foo=usize>` predicate help
909+
// resolve `T::Foo`? And of course it does, but in fact
910+
// that single predicate is desugared into two predicates
911+
// in the compiler: a trait predicate (`T : SomeTrait`) and a
912+
// projection. And the projection where clause is handled
913+
// in `assemble_candidates_from_param_env`.
914+
}
915+
super::VtableDefaultImpl(..) |
916+
super::VtableBuiltin(..) => {
917+
// These traits have no associated types.
918+
span_bug!(
919+
obligation.cause.span,
920+
"Cannot project an associated type from `{:?}`",
921+
vtable);
922+
}
968923
}
969-
}
970924

971-
Ok(())
925+
Ok(())
926+
})
972927
}
973928

974929
fn confirm_candidate<'cx,'tcx>(
975930
selcx: &mut SelectionContext<'cx,'tcx>,
976931
obligation: &ProjectionTyObligation<'tcx>,
932+
obligation_trait_ref: &ty::TraitRef<'tcx>,
977933
candidate: ProjectionTyCandidate<'tcx>)
978934
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
979935
{
@@ -987,20 +943,118 @@ fn confirm_candidate<'cx,'tcx>(
987943
confirm_param_env_candidate(selcx, obligation, poly_projection)
988944
}
989945

990-
ProjectionTyCandidate::Impl(impl_vtable) => {
991-
confirm_impl_candidate(selcx, obligation, impl_vtable)
946+
ProjectionTyCandidate::Select => {
947+
confirm_select_candidate(selcx, obligation, obligation_trait_ref)
992948
}
949+
}
950+
}
993951

994-
ProjectionTyCandidate::Closure(closure_vtable) => {
995-
confirm_closure_candidate(selcx, obligation, closure_vtable)
952+
fn confirm_select_candidate<'cx,'tcx>(
953+
selcx: &mut SelectionContext<'cx,'tcx>,
954+
obligation: &ProjectionTyObligation<'tcx>,
955+
obligation_trait_ref: &ty::TraitRef<'tcx>)
956+
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
957+
{
958+
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
959+
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
960+
let vtable = match selcx.select(&trait_obligation) {
961+
Ok(Some(vtable)) => vtable,
962+
_ => {
963+
span_bug!(
964+
obligation.cause.span,
965+
"Failed to select `{:?}`",
966+
trait_obligation);
996967
}
968+
};
997969

998-
ProjectionTyCandidate::FnPointer(fn_type) => {
999-
confirm_fn_pointer_candidate(selcx, obligation, fn_type)
1000-
}
970+
match vtable {
971+
super::VtableImpl(data) =>
972+
confirm_impl_candidate(selcx, obligation, data),
973+
super::VtableClosure(data) =>
974+
confirm_closure_candidate(selcx, obligation, data),
975+
super::VtableFnPointer(data) =>
976+
confirm_fn_pointer_candidate(selcx, obligation, data),
977+
super::VtableObject(_) =>
978+
confirm_object_candidate(selcx, obligation, obligation_trait_ref),
979+
super::VtableDefaultImpl(..) |
980+
super::VtableParam(..) |
981+
super::VtableBuiltin(..) =>
982+
// we don't create Select candidates with this kind of resolution
983+
span_bug!(
984+
obligation.cause.span,
985+
"Cannot project an associated type from `{:?}`",
986+
vtable),
1001987
}
1002988
}
1003989

990+
fn confirm_object_candidate<'cx,'tcx>(
991+
selcx: &mut SelectionContext<'cx,'tcx>,
992+
obligation: &ProjectionTyObligation<'tcx>,
993+
obligation_trait_ref: &ty::TraitRef<'tcx>)
994+
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
995+
{
996+
let self_ty = obligation_trait_ref.self_ty();
997+
let object_ty = selcx.infcx().shallow_resolve(self_ty);
998+
debug!("assemble_candidates_from_object_type(object_ty={:?})",
999+
object_ty);
1000+
let data = match object_ty.sty {
1001+
ty::TyTrait(ref data) => data,
1002+
_ => {
1003+
span_bug!(
1004+
obligation.cause.span,
1005+
"assemble_candidates_from_object_type called with non-object: {:?}",
1006+
object_ty);
1007+
}
1008+
};
1009+
let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty);
1010+
let env_predicates = projection_bounds.iter()
1011+
.map(|p| p.to_predicate())
1012+
.collect();
1013+
let env_predicate = {
1014+
let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
1015+
1016+
// select only those projections that are actually projecting an
1017+
// item with the correct name
1018+
let env_predicates = env_predicates.filter_map(|p| match p {
1019+
ty::Predicate::Projection(data) =>
1020+
if data.item_name() == obligation.predicate.item_name {
1021+
Some(data)
1022+
} else {
1023+
None
1024+
},
1025+
_ => None
1026+
});
1027+
1028+
// select those with a relevant trait-ref
1029+
let mut env_predicates = env_predicates.filter(|data| {
1030+
let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
1031+
let data_poly_trait_ref = data.to_poly_trait_ref();
1032+
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
1033+
selcx.infcx().probe(|_| {
1034+
selcx.infcx().sub_poly_trait_refs(false,
1035+
origin,
1036+
data_poly_trait_ref,
1037+
obligation_poly_trait_ref).is_ok()
1038+
})
1039+
});
1040+
1041+
// select the first matching one; there really ought to be one or
1042+
// else the object type is not WF, since an object type should
1043+
// include all of its projections explicitly
1044+
match env_predicates.next() {
1045+
Some(env_predicate) => env_predicate,
1046+
None => {
1047+
debug!("confirm_object_candidate: no env-predicate \
1048+
found in object type `{:?}`; ill-formed",
1049+
object_ty);
1050+
return (selcx.tcx().types.err, vec!());
1051+
}
1052+
}
1053+
};
1054+
1055+
confirm_param_env_candidate(selcx, obligation, env_predicate)
1056+
}
1057+
10041058
fn confirm_fn_pointer_candidate<'cx,'tcx>(
10051059
selcx: &mut SelectionContext<'cx,'tcx>,
10061060
obligation: &ProjectionTyObligation<'tcx>,

0 commit comments

Comments
 (0)