Skip to content

Commit 1b33f39

Browse files
matthewjasperlcnr
authored andcommitted
Handle trait/projection predicates with bound regions correctly
1 parent 9a33b59 commit 1b33f39

File tree

2 files changed

+132
-70
lines changed

2 files changed

+132
-70
lines changed

src/librustc_trait_selection/traits/fulfill.rs

Lines changed: 131 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_data_structures::obligation_forest::ProcessResult;
33
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
44
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
55
use rustc_errors::ErrorReported;
6-
use rustc_infer::traits::{TraitEngine, TraitEngineExt as _};
6+
use rustc_infer::traits::{PolyTraitObligation, TraitEngine, TraitEngineExt as _};
77
use rustc_middle::mir::interpret::ErrorHandled;
88
use rustc_middle::ty::error::ExpectedFound;
99
use rustc_middle::ty::{self, Binder, Const, ToPredicate, Ty, TypeFoldable};
@@ -20,6 +20,7 @@ use super::{FulfillmentError, FulfillmentErrorCode};
2020
use super::{ObligationCause, PredicateObligation};
2121

2222
use crate::traits::error_reporting::InferCtxtExt as _;
23+
use crate::traits::project::PolyProjectionObligation;
2324
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
2425

2526
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
@@ -318,65 +319,50 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
318319
let infcx = self.selcx.infcx();
319320

320321
match obligation.predicate.kint(infcx.tcx) {
321-
ty::PredicateKint::ForAll(binder) => {
322-
let (pred, _) = infcx.replace_bound_vars_with_placeholders(binder);
323-
ProcessResult::Changed(mk_pending(vec![
324-
obligation.with(pred.to_predicate(infcx.tcx)),
325-
]))
326-
}
327-
ty::PredicateKint::Trait(ref data, _) => {
328-
let trait_obligation = obligation.with(Binder::dummy(*data));
329-
330-
if obligation.predicate.is_global() {
331-
// no type variables present, can use evaluation for better caching.
332-
// FIXME: consider caching errors too.
333-
if infcx.predicate_must_hold_considering_regions(&obligation) {
334-
debug!(
335-
"selecting trait `{:?}` at depth {} evaluated to holds",
336-
data, obligation.recursion_depth
337-
);
338-
return ProcessResult::Changed(vec![]);
339-
}
322+
ty::PredicateKint::ForAll(binder) => match binder.skip_binder() {
323+
// Evaluation will discard candidates using the leak check.
324+
// This means we need to pass it the bound version of our
325+
// predicate.
326+
rustc_middle::ty::PredicateKint::Trait(trait_ref, _constness) => {
327+
let trait_obligation = obligation.with(Binder::bind(*trait_ref));
328+
329+
self.process_trait_obligation(
330+
obligation,
331+
trait_obligation,
332+
&mut pending_obligation.stalled_on,
333+
)
340334
}
335+
rustc_middle::ty::PredicateKint::Projection(projection) => {
336+
let project_obligation = obligation.with(Binder::bind(*projection));
341337

342-
match self.selcx.select(&trait_obligation) {
343-
Ok(Some(impl_source)) => {
344-
debug!(
345-
"selecting trait `{:?}` at depth {} yielded Ok(Some)",
346-
data, obligation.recursion_depth
347-
);
348-
ProcessResult::Changed(mk_pending(impl_source.nested_obligations()))
349-
}
350-
Ok(None) => {
351-
debug!(
352-
"selecting trait `{:?}` at depth {} yielded Ok(None)",
353-
data, obligation.recursion_depth
354-
);
355-
356-
// This is a bit subtle: for the most part, the
357-
// only reason we can fail to make progress on
358-
// trait selection is because we don't have enough
359-
// information about the types in the trait.
360-
pending_obligation.stalled_on =
361-
trait_ref_infer_vars(self.selcx, data.trait_ref);
362-
363-
debug!(
364-
"process_predicate: pending obligation {:?} now stalled on {:?}",
365-
infcx.resolve_vars_if_possible(obligation),
366-
pending_obligation.stalled_on
367-
);
368-
369-
ProcessResult::Unchanged
370-
}
371-
Err(selection_err) => {
372-
info!(
373-
"selecting trait `{:?}` at depth {} yielded Err",
374-
data, obligation.recursion_depth
375-
);
376-
377-
ProcessResult::Error(CodeSelectionError(selection_err))
378-
}
338+
self.process_projection_obligation(
339+
project_obligation,
340+
&mut pending_obligation.stalled_on,
341+
)
379342
}
343+
rustc_middle::ty::PredicateKint::RegionOutlives(_)
344+
| rustc_middle::ty::PredicateKint::TypeOutlives(_)
345+
| rustc_middle::ty::PredicateKint::WellFormed(_)
346+
| rustc_middle::ty::PredicateKint::ObjectSafe(_)
347+
| rustc_middle::ty::PredicateKint::ClosureKind(..)
348+
| rustc_middle::ty::PredicateKint::Subtype(_)
349+
| rustc_middle::ty::PredicateKint::ConstEvaluatable(..)
350+
| rustc_middle::ty::PredicateKint::ConstEquate(..)
351+
| rustc_middle::ty::PredicateKint::ForAll(_) => {
352+
let (pred, _) = infcx.replace_bound_vars_with_placeholders(binder);
353+
ProcessResult::Changed(mk_pending(vec![
354+
obligation.with(pred.to_predicate(infcx.tcx)),
355+
]))
356+
}
357+
},
358+
ty::PredicateKint::Trait(ref data, _) => {
359+
let trait_obligation = obligation.with(Binder::dummy(*data));
360+
361+
self.process_trait_obligation(
362+
obligation,
363+
trait_obligation,
364+
&mut pending_obligation.stalled_on,
365+
)
380366
}
381367

382368
&ty::PredicateKint::RegionOutlives(data) => {
@@ -399,17 +385,11 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
399385

400386
ty::PredicateKint::Projection(ref data) => {
401387
let project_obligation = obligation.with(Binder::dummy(*data));
402-
match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
403-
Ok(None) => {
404-
pending_obligation.stalled_on = trait_ref_infer_vars(
405-
self.selcx,
406-
data.projection_ty.trait_ref(infcx.tcx),
407-
);
408-
ProcessResult::Unchanged
409-
}
410-
Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)),
411-
Err(e) => ProcessResult::Error(CodeProjectionError(e)),
412-
}
388+
389+
self.process_projection_obligation(
390+
project_obligation,
391+
&mut pending_obligation.stalled_on,
392+
)
413393
}
414394

415395
&ty::PredicateKint::ObjectSafe(trait_def_id) => {
@@ -569,14 +549,96 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
569549
}
570550
}
571551

552+
impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
553+
fn process_trait_obligation(
554+
&mut self,
555+
obligation: &PredicateObligation<'tcx>,
556+
trait_obligation: PolyTraitObligation<'tcx>,
557+
stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
558+
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
559+
let infcx = self.selcx.infcx();
560+
if obligation.predicate.is_global() {
561+
// no type variables present, can use evaluation for better caching.
562+
// FIXME: consider caching errors too.
563+
if infcx.predicate_must_hold_considering_regions(obligation) {
564+
debug!(
565+
"selecting trait `{:?}` at depth {} evaluated to holds",
566+
obligation.predicate, obligation.recursion_depth
567+
);
568+
return ProcessResult::Changed(vec![]);
569+
}
570+
}
571+
572+
match self.selcx.select(&trait_obligation) {
573+
Ok(Some(impl_source)) => {
574+
debug!(
575+
"selecting trait `{:?}` at depth {} yielded Ok(Some)",
576+
trait_obligation.predicate, obligation.recursion_depth
577+
);
578+
ProcessResult::Changed(mk_pending(impl_source.nested_obligations()))
579+
}
580+
Ok(None) => {
581+
debug!(
582+
"selecting trait `{:?}` at depth {} yielded Ok(None)",
583+
trait_obligation.predicate, obligation.recursion_depth
584+
);
585+
586+
// This is a bit subtle: for the most part, the
587+
// only reason we can fail to make progress on
588+
// trait selection is because we don't have enough
589+
// information about the types in the trait.
590+
*stalled_on = trait_ref_infer_vars(
591+
self.selcx,
592+
trait_obligation.predicate.map_bound(|pred| pred.trait_ref),
593+
);
594+
595+
debug!(
596+
"process_predicate: pending obligation {:?} now stalled on {:?}",
597+
infcx.resolve_vars_if_possible(obligation),
598+
stalled_on
599+
);
600+
601+
ProcessResult::Unchanged
602+
}
603+
Err(selection_err) => {
604+
info!(
605+
"selecting trait `{:?}` at depth {} yielded Err",
606+
trait_obligation.predicate, obligation.recursion_depth
607+
);
608+
609+
ProcessResult::Error(CodeSelectionError(selection_err))
610+
}
611+
}
612+
}
613+
614+
fn process_projection_obligation(
615+
&mut self,
616+
project_obligation: PolyProjectionObligation<'tcx>,
617+
stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
618+
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
619+
match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
620+
Ok(None) => {
621+
*stalled_on = trait_ref_infer_vars(
622+
self.selcx,
623+
project_obligation.predicate.to_poly_trait_ref(self.selcx.tcx()),
624+
);
625+
ProcessResult::Unchanged
626+
}
627+
Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)),
628+
Err(e) => ProcessResult::Error(CodeProjectionError(e)),
629+
}
630+
}
631+
}
632+
572633
/// Returns the set of inference variables contained in a trait ref.
573634
fn trait_ref_infer_vars<'a, 'tcx>(
574635
selcx: &mut SelectionContext<'a, 'tcx>,
575-
trait_ref: ty::TraitRef<'tcx>,
636+
trait_ref: ty::PolyTraitRef<'tcx>,
576637
) -> Vec<TyOrConstInferVar<'tcx>> {
577638
selcx
578639
.infcx()
579640
.resolve_vars_if_possible(&trait_ref)
641+
.skip_binder()
580642
.substs
581643
.iter()
582644
// FIXME(eddyb) try using `skip_current_subtree` to skip everything that

src/test/ui/issues/issue-26217.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error[E0477]: the type `&'a i32` does not fulfill the required lifetime
44
LL | foo::<&'a i32>();
55
| ^^^^^^^^^^^^^^
66
|
7-
= note: type must satisfy the static lifetime
7+
= note: type must outlive any other region
88

99
error: aborting due to previous error
1010

0 commit comments

Comments
 (0)