Skip to content

Commit 170901e

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 a832190 commit 170901e

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> {
@@ -645,10 +639,8 @@ fn project_type<'cx,'tcx>(
645639
debug!("retaining param-env candidates only from {:?}", candidates.vec);
646640
candidates.vec.retain(|c| match *c {
647641
ProjectionTyCandidate::ParamEnv(..) => true,
648-
ProjectionTyCandidate::Impl(..) |
649-
ProjectionTyCandidate::Closure(..) |
650642
ProjectionTyCandidate::TraitDef(..) |
651-
ProjectionTyCandidate::FnPointer(..) => false,
643+
ProjectionTyCandidate::Select => false,
652644
});
653645
debug!("resulting candidate set: {:?}", candidates.vec);
654646
if candidates.vec.len() != 1 {
@@ -729,7 +721,10 @@ fn project_type<'cx,'tcx>(
729721

730722
match possible_candidate {
731723
Some(candidate) => {
732-
let (ty, obligations) = confirm_candidate(selcx, obligation, candidate);
724+
let (ty, obligations) = confirm_candidate(selcx,
725+
obligation,
726+
&obligation_trait_ref,
727+
candidate);
733728
Ok(ProjectedTy::Progress(ty, obligations))
734729
}
735730
None => {
@@ -845,38 +840,6 @@ fn assemble_candidates_from_predicates<'cx,'tcx,I>(
845840
}
846841
}
847842

848-
fn assemble_candidates_from_object_type<'cx,'tcx>(
849-
selcx: &mut SelectionContext<'cx,'tcx>,
850-
obligation: &ProjectionTyObligation<'tcx>,
851-
obligation_trait_ref: &ty::TraitRef<'tcx>,
852-
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
853-
{
854-
let self_ty = obligation_trait_ref.self_ty();
855-
let object_ty = selcx.infcx().shallow_resolve(self_ty);
856-
debug!("assemble_candidates_from_object_type(object_ty={:?})",
857-
object_ty);
858-
let data = match object_ty.sty {
859-
ty::TyTrait(ref data) => data,
860-
_ => {
861-
span_bug!(
862-
obligation.cause.span,
863-
"assemble_candidates_from_object_type called with non-object: {:?}",
864-
object_ty);
865-
}
866-
};
867-
let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty);
868-
let env_predicates = projection_bounds.iter()
869-
.map(|p| p.to_predicate())
870-
.collect();
871-
let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
872-
assemble_candidates_from_predicates(selcx,
873-
obligation,
874-
obligation_trait_ref,
875-
candidate_set,
876-
ProjectionTyCandidate::ParamEnv,
877-
env_predicates)
878-
}
879-
880843
fn assemble_candidates_from_impls<'cx,'tcx>(
881844
selcx: &mut SelectionContext<'cx,'tcx>,
882845
obligation: &ProjectionTyObligation<'tcx>,
@@ -888,82 +851,75 @@ fn assemble_candidates_from_impls<'cx,'tcx>(
888851
// start out by selecting the predicate `T as TraitRef<...>`:
889852
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
890853
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
891-
let vtable = match selcx.select(&trait_obligation) {
892-
Ok(Some(vtable)) => vtable,
893-
Ok(None) => {
894-
candidate_set.ambiguous = true;
895-
return Ok(());
896-
}
897-
Err(e) => {
898-
debug!("assemble_candidates_from_impls: selection error {:?}",
899-
e);
900-
return Err(e);
901-
}
902-
};
854+
selcx.infcx().probe(|_| {
855+
let vtable = match selcx.select(&trait_obligation) {
856+
Ok(Some(vtable)) => vtable,
857+
Ok(None) => {
858+
candidate_set.ambiguous = true;
859+
return Ok(());
860+
}
861+
Err(e) => {
862+
debug!("assemble_candidates_from_impls: selection error {:?}",
863+
e);
864+
return Err(e);
865+
}
866+
};
903867

904-
match vtable {
905-
super::VtableImpl(data) => {
906-
debug!("assemble_candidates_from_impls: impl candidate {:?}",
907-
data);
868+
match vtable {
869+
super::VtableImpl(_) |
870+
super::VtableClosure(_) |
871+
super::VtableFnPointer(_) |
872+
super::VtableObject(_) => {
873+
debug!("assemble_candidates_from_impls: vtable={:?}",
874+
vtable);
908875

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

961-
Ok(())
915+
Ok(())
916+
})
962917
}
963918

964919
fn confirm_candidate<'cx,'tcx>(
965920
selcx: &mut SelectionContext<'cx,'tcx>,
966921
obligation: &ProjectionTyObligation<'tcx>,
922+
obligation_trait_ref: &ty::TraitRef<'tcx>,
967923
candidate: ProjectionTyCandidate<'tcx>)
968924
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
969925
{
@@ -977,20 +933,118 @@ fn confirm_candidate<'cx,'tcx>(
977933
confirm_param_env_candidate(selcx, obligation, poly_projection)
978934
}
979935

980-
ProjectionTyCandidate::Impl(impl_vtable) => {
981-
confirm_impl_candidate(selcx, obligation, impl_vtable)
936+
ProjectionTyCandidate::Select => {
937+
confirm_select_candidate(selcx, obligation, obligation_trait_ref)
982938
}
939+
}
940+
}
983941

984-
ProjectionTyCandidate::Closure(closure_vtable) => {
985-
confirm_closure_candidate(selcx, obligation, closure_vtable)
942+
fn confirm_select_candidate<'cx,'tcx>(
943+
selcx: &mut SelectionContext<'cx,'tcx>,
944+
obligation: &ProjectionTyObligation<'tcx>,
945+
obligation_trait_ref: &ty::TraitRef<'tcx>)
946+
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
947+
{
948+
let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
949+
let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
950+
let vtable = match selcx.select(&trait_obligation) {
951+
Ok(Some(vtable)) => vtable,
952+
_ => {
953+
span_bug!(
954+
obligation.cause.span,
955+
"Failed to select `{:?}`",
956+
trait_obligation);
986957
}
958+
};
987959

988-
ProjectionTyCandidate::FnPointer(fn_type) => {
989-
confirm_fn_pointer_candidate(selcx, obligation, fn_type)
990-
}
960+
match vtable {
961+
super::VtableImpl(data) =>
962+
confirm_impl_candidate(selcx, obligation, data),
963+
super::VtableClosure(data) =>
964+
confirm_closure_candidate(selcx, obligation, data),
965+
super::VtableFnPointer(data) =>
966+
confirm_fn_pointer_candidate(selcx, obligation, data),
967+
super::VtableObject(_) =>
968+
confirm_object_candidate(selcx, obligation, obligation_trait_ref),
969+
super::VtableDefaultImpl(..) |
970+
super::VtableParam(..) |
971+
super::VtableBuiltin(..) =>
972+
// we don't create Select candidates with this kind of resolution
973+
span_bug!(
974+
obligation.cause.span,
975+
"Cannot project an associated type from `{:?}`",
976+
vtable),
991977
}
992978
}
993979

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

0 commit comments

Comments
 (0)