Skip to content

Commit 34e5a49

Browse files
committed
Normalize projection bounds when considering candidates
This unfortunately requires some winnowing hacks to avoid now ambiguous candidates.
1 parent cfee495 commit 34e5a49

16 files changed

+390
-256
lines changed

compiler/rustc_trait_selection/src/traits/project.rs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,7 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
884884
candidate_set,
885885
ProjectionTyCandidate::ParamEnv,
886886
obligation.param_env.caller_bounds().iter(),
887+
false,
887888
);
888889
}
889890

@@ -927,6 +928,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
927928
candidate_set,
928929
ProjectionTyCandidate::TraitDef,
929930
bounds.iter(),
931+
true,
930932
)
931933
}
932934

@@ -937,6 +939,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
937939
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
938940
ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
939941
env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
942+
potentially_unnormalized_candidates: bool,
940943
) {
941944
debug!("assemble_candidates_from_predicates(obligation={:?})", obligation);
942945
let infcx = selcx.infcx();
@@ -948,16 +951,12 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
948951

949952
let is_match = same_def_id
950953
&& infcx.probe(|_| {
951-
let data_poly_trait_ref = data.to_poly_trait_ref(infcx.tcx);
952-
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
953-
infcx
954-
.at(&obligation.cause, obligation.param_env)
955-
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
956-
.map(|InferOk { obligations: _, value: () }| {
957-
// FIXME(#32730) -- do we need to take obligations
958-
// into account in any way? At the moment, no.
959-
})
960-
.is_ok()
954+
selcx.match_projection_projections(
955+
obligation,
956+
obligation_trait_ref,
957+
&data,
958+
potentially_unnormalized_candidates,
959+
)
961960
});
962961

963962
debug!(
@@ -1157,9 +1156,12 @@ fn confirm_candidate<'cx, 'tcx>(
11571156
debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation);
11581157

11591158
let mut progress = match candidate {
1160-
ProjectionTyCandidate::ParamEnv(poly_projection)
1161-
| ProjectionTyCandidate::TraitDef(poly_projection) => {
1162-
confirm_param_env_candidate(selcx, obligation, poly_projection)
1159+
ProjectionTyCandidate::ParamEnv(poly_projection) => {
1160+
confirm_param_env_candidate(selcx, obligation, poly_projection, false)
1161+
}
1162+
1163+
ProjectionTyCandidate::TraitDef(poly_projection) => {
1164+
confirm_param_env_candidate(selcx, obligation, poly_projection, true)
11631165
}
11641166

11651167
ProjectionTyCandidate::Select(impl_source) => {
@@ -1272,7 +1274,7 @@ fn confirm_object_candidate<'cx, 'tcx>(
12721274
}
12731275
};
12741276

1275-
confirm_param_env_candidate(selcx, obligation, env_predicate)
1277+
confirm_param_env_candidate(selcx, obligation, env_predicate, false)
12761278
}
12771279

12781280
fn confirm_generator_candidate<'cx, 'tcx>(
@@ -1323,7 +1325,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
13231325
}
13241326
});
13251327

1326-
confirm_param_env_candidate(selcx, obligation, predicate)
1328+
confirm_param_env_candidate(selcx, obligation, predicate, false)
13271329
.with_addl_obligations(impl_source.nested)
13281330
.with_addl_obligations(obligations)
13291331
}
@@ -1345,7 +1347,7 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
13451347
ty: self_ty.discriminant_ty(tcx),
13461348
};
13471349

1348-
confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate))
1350+
confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false)
13491351
}
13501352

13511353
fn confirm_fn_pointer_candidate<'cx, 'tcx>(
@@ -1420,13 +1422,14 @@ fn confirm_callable_candidate<'cx, 'tcx>(
14201422
ty: ret_type,
14211423
});
14221424

1423-
confirm_param_env_candidate(selcx, obligation, predicate)
1425+
confirm_param_env_candidate(selcx, obligation, predicate, false)
14241426
}
14251427

14261428
fn confirm_param_env_candidate<'cx, 'tcx>(
14271429
selcx: &mut SelectionContext<'cx, 'tcx>,
14281430
obligation: &ProjectionTyObligation<'tcx>,
14291431
poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
1432+
potentially_unnormalized_candidate: bool,
14301433
) -> Progress<'tcx> {
14311434
let infcx = selcx.infcx();
14321435
let cause = &obligation.cause;
@@ -1440,8 +1443,27 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
14401443

14411444
let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
14421445
let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx);
1446+
let mut nested_obligations = Vec::new();
1447+
let cache_trait_ref = if potentially_unnormalized_candidate {
1448+
ensure_sufficient_stack(|| {
1449+
normalize_with_depth_to(
1450+
selcx,
1451+
obligation.param_env,
1452+
obligation.cause.clone(),
1453+
obligation.recursion_depth + 1,
1454+
&cache_trait_ref,
1455+
&mut nested_obligations,
1456+
)
1457+
})
1458+
} else {
1459+
cache_trait_ref
1460+
};
1461+
14431462
match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
1444-
Ok(InferOk { value: _, obligations }) => Progress { ty: cache_entry.ty, obligations },
1463+
Ok(InferOk { value: _, obligations }) => {
1464+
nested_obligations.extend(obligations);
1465+
Progress { ty: cache_entry.ty, obligations: nested_obligations }
1466+
}
14451467
Err(e) => {
14461468
let msg = format!(
14471469
"Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}",

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

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
137137
let candidate = candidate_predicate
138138
.to_opt_poly_trait_ref()
139139
.expect("projection candidate is not a trait predicate");
140-
let mut obligations = self
141-
.infcx
142-
.at(&obligation.cause, obligation.param_env)
143-
.sup(obligation.predicate.to_poly_trait_ref(), candidate)
144-
.map(|InferOk { obligations, .. }| obligations)
145-
.unwrap_or_else(|_| {
146-
bug!(
147-
"Projection bound `{:?}` was applicable to `{:?}` but now is not",
148-
candidate,
149-
obligation
150-
);
151-
});
140+
let Normalized { value: candidate, mut obligations } = normalize_with_depth(
141+
self,
142+
obligation.param_env,
143+
obligation.cause.clone(),
144+
obligation.recursion_depth + 1,
145+
&candidate,
146+
);
147+
148+
obligations.extend(
149+
self.infcx
150+
.at(&obligation.cause, obligation.param_env)
151+
.sup(obligation.predicate.to_poly_trait_ref(), candidate)
152+
.map(|InferOk { obligations, .. }| obligations)
153+
.unwrap_or_else(|_| {
154+
bug!(
155+
"Projection bound `{:?}` was applicable to `{:?}` but now is not",
156+
candidate,
157+
obligation
158+
);
159+
}),
160+
);
152161
// Require that the projection is well-formed.
153162
let self_ty = self.infcx.replace_bound_vars_with_placeholders(&bound_self_ty);
154163
let self_ty = normalize_with_depth_to(

0 commit comments

Comments
 (0)