Skip to content

Commit 27ab794

Browse files
committed
Update implied_outlives_bounds to properly register implied bounds behind normalization
1 parent d563a32 commit 27ab794

File tree

2 files changed

+72
-48
lines changed

2 files changed

+72
-48
lines changed

compiler/rustc_traits/src/implied_outlives_bounds.rs

Lines changed: 71 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use rustc_infer::infer::canonical::{self, Canonical};
77
use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
88
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
99
use rustc_infer::traits::query::OutlivesBound;
10-
use rustc_infer::traits::TraitEngineExt as _;
1110
use rustc_middle::ty::query::Providers;
1211
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
1312
use rustc_span::source_map::DUMMY_SP;
@@ -65,70 +64,94 @@ fn compute_implied_outlives_bounds<'tcx>(
6564
// than the ultimate set. (Note: normally there won't be
6665
// unresolved inference variables here anyway, but there might be
6766
// during typeck under some circumstances.)
68-
let obligations = wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
69-
.unwrap_or_default();
70-
71-
// N.B., all of these predicates *ought* to be easily proven
72-
// true. In fact, their correctness is (mostly) implied by
73-
// other parts of the program. However, in #42552, we had
74-
// an annoying scenario where:
75-
//
76-
// - Some `T::Foo` gets normalized, resulting in a
77-
// variable `_1` and a `T: Trait<Foo=_1>` constraint
78-
// (not sure why it couldn't immediately get
79-
// solved). This result of `_1` got cached.
80-
// - These obligations were dropped on the floor here,
81-
// rather than being registered.
82-
// - Then later we would get a request to normalize
83-
// `T::Foo` which would result in `_1` being used from
84-
// the cache, but hence without the `T: Trait<Foo=_1>`
85-
// constraint. As a result, `_1` never gets resolved,
86-
// and we get an ICE (in dropck).
87-
//
88-
// Therefore, we register any predicates involving
89-
// inference variables. We restrict ourselves to those
90-
// involving inference variables both for efficiency and
91-
// to avoids duplicate errors that otherwise show up.
92-
fulfill_cx.register_predicate_obligations(
93-
infcx,
94-
obligations.iter().filter(|o| o.predicate.has_infer_types_or_consts()).cloned(),
95-
);
96-
97-
// From the full set of obligations, just filter down to the
98-
// region relationships.
99-
implied_bounds.extend(obligations.into_iter().flat_map(|obligation| {
100-
debug!(?obligation);
101-
assert!(!obligation.has_escaping_bound_vars());
102-
match obligation.predicate.kind().no_bound_vars() {
103-
None => vec![],
104-
Some(pred) => match pred {
67+
let mut obligations =
68+
wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, 0, arg, DUMMY_SP)
69+
.unwrap_or_default();
70+
71+
let mut first = true;
72+
loop {
73+
obligations.drain_filter(|obligation| {
74+
debug!(?obligation);
75+
assert!(!obligation.has_escaping_bound_vars());
76+
let pred = match obligation.predicate.kind().no_bound_vars() {
77+
None => return false,
78+
Some(pred) => pred,
79+
};
80+
match pred {
10581
ty::PredicateKind::Trait(..)
10682
| ty::PredicateKind::Subtype(..)
10783
| ty::PredicateKind::Coerce(..)
108-
| ty::PredicateKind::Projection(..)
10984
| ty::PredicateKind::ClosureKind(..)
11085
| ty::PredicateKind::ObjectSafe(..)
11186
| ty::PredicateKind::ConstEvaluatable(..)
11287
| ty::PredicateKind::ConstEquate(..)
113-
| ty::PredicateKind::TypeWellFormedFromEnv(..) => vec![],
88+
| ty::PredicateKind::TypeWellFormedFromEnv(..) => true,
89+
ty::PredicateKind::Projection(..) => {
90+
// N.B., all of these predicates *ought* to be easily proven
91+
// true. In fact, their correctness is (mostly) implied by
92+
// other parts of the program. However, in #42552, we had
93+
// an annoying scenario where:
94+
//
95+
// - Some `T::Foo` gets normalized, resulting in a
96+
// variable `_1` and a `T: Trait<Foo=_1>` constraint
97+
// (not sure why it couldn't immediately get
98+
// solved). This result of `_1` got cached.
99+
// - These obligations were dropped on the floor here,
100+
// rather than being registered.
101+
// - Then later we would get a request to normalize
102+
// `T::Foo` which would result in `_1` being used from
103+
// the cache, but hence without the `T: Trait<Foo=_1>`
104+
// constraint. As a result, `_1` never gets resolved,
105+
// and we get an ICE (in dropck).
106+
//
107+
// Therefore, we register any predicates involving
108+
// inference variables. We restrict ourselves to those
109+
// involving inference variables both for efficiency and
110+
// to avoids duplicate errors that otherwise show up.
111+
if obligation.has_infer_types_or_consts() {
112+
fulfill_cx.register_predicate_obligation(infcx, obligation.clone());
113+
}
114+
true
115+
}
114116
ty::PredicateKind::WellFormed(arg) => {
115117
wf_args.push(arg);
116-
vec![]
118+
true
117119
}
118120

119121
ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => {
120-
vec![OutlivesBound::RegionSubRegion(r_b, r_a)]
122+
if first {
123+
false
124+
} else {
125+
implied_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a));
126+
true
127+
}
121128
}
122129

123130
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, r_b)) => {
124-
let ty_a = infcx.resolve_vars_if_possible(ty_a);
125-
let mut components = smallvec![];
126-
push_outlives_components(tcx, ty_a, &mut components);
127-
implied_bounds_from_components(r_b, components)
131+
if first {
132+
false
133+
} else {
134+
let ty_a = infcx.resolve_vars_if_possible(ty_a);
135+
let mut components = smallvec![];
136+
push_outlives_components(tcx, ty_a, &mut components);
137+
let bounds = implied_bounds_from_components(r_b, components);
138+
implied_bounds.extend(bounds);
139+
true
140+
}
128141
}
129-
},
142+
}
143+
});
144+
145+
if !first {
146+
break;
130147
}
131-
}));
148+
149+
if first {
150+
let _ = fulfill_cx.select_where_possible(infcx);
151+
}
152+
153+
first = false;
154+
}
132155
}
133156

134157
// Ensure that those obligations that we had to solve

compiler/rustc_traits/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
#![deny(rustc::untranslatable_diagnostic)]
55
#![deny(rustc::diagnostic_outside_of_impl)]
6+
#![feature(drain_filter)]
67
#![feature(let_else)]
78
#![recursion_limit = "256"]
89

0 commit comments

Comments
 (0)