Skip to content

Commit dfb8c80

Browse files
committed
Auto merge of #42659 - nikomatsakis:issue-42545-type-inference-regression, r=eddyb
Issue 42545 type inference regression Fix an ICE that results from type inference obligations being dropped on the floor. Specifically, when computing the implied bounds, we would sometimes do normalizations that get stored in the cache, but we would *not* try to solve the resulting obligations. This can sometimes leave type variables uninferred. Occurs only rarely because implied bounds are processed in regionck which happens very late, so usually the cache is populated already from somewhere else. I think that the *proper* fix here is probably lazy normalization. This fix is intentionally very narrow both because this code is on the chopping block and because this needs a beta backport. r? @eddyb cc @arielb1
2 parents ff9f2d2 + 9fec409 commit dfb8c80

File tree

5 files changed

+210
-166
lines changed

5 files changed

+210
-166
lines changed

Diff for: src/librustc/middle/free_region.rs

+1-19
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
use hir::def_id::DefId;
1919
use middle::region::RegionMaps;
2020
use ty::{self, Lift, TyCtxt, Region};
21-
use ty::wf::ImpliedBound;
2221
use rustc_data_structures::transitive_relation::TransitiveRelation;
2322

2423
/// Combines a `RegionMaps` (which governs relationships between
@@ -136,23 +135,6 @@ impl<'tcx> FreeRegionMap<'tcx> {
136135
self.relation.is_empty()
137136
}
138137

139-
pub fn relate_free_regions_from_implied_bounds(&mut self,
140-
implied_bounds: &[ImpliedBound<'tcx>])
141-
{
142-
debug!("relate_free_regions_from_implied_bounds()");
143-
for implied_bound in implied_bounds {
144-
debug!("implied bound: {:?}", implied_bound);
145-
match *implied_bound {
146-
ImpliedBound::RegionSubRegion(a, b) => {
147-
self.relate_regions(a, b);
148-
}
149-
ImpliedBound::RegionSubParam(..) |
150-
ImpliedBound::RegionSubProjection(..) => {
151-
}
152-
}
153-
}
154-
}
155-
156138
pub fn relate_free_regions_from_predicates(&mut self,
157139
predicates: &[ty::Predicate<'tcx>]) {
158140
debug!("relate_free_regions_from_predicates(predicates={:?})", predicates);
@@ -177,7 +159,7 @@ impl<'tcx> FreeRegionMap<'tcx> {
177159

178160
// Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`.
179161
// (with the exception that `'static: 'x` is not notable)
180-
fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
162+
pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) {
181163
if (is_free(sub) || *sub == ty::ReStatic) && is_free(sup) {
182164
self.relation.add(sub, sup)
183165
}

Diff for: src/librustc/ty/wf.rs

-128
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
use hir::def_id::DefId;
1212
use infer::InferCtxt;
13-
use ty::outlives::Component;
1413
use ty::subst::Substs;
1514
use traits;
1615
use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
@@ -107,133 +106,6 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
107106
wf.normalize()
108107
}
109108

110-
/// Implied bounds are region relationships that we deduce
111-
/// automatically. The idea is that (e.g.) a caller must check that a
112-
/// function's argument types are well-formed immediately before
113-
/// calling that fn, and hence the *callee* can assume that its
114-
/// argument types are well-formed. This may imply certain relationships
115-
/// between generic parameters. For example:
116-
///
117-
/// fn foo<'a,T>(x: &'a T)
118-
///
119-
/// can only be called with a `'a` and `T` such that `&'a T` is WF.
120-
/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
121-
#[derive(Debug)]
122-
pub enum ImpliedBound<'tcx> {
123-
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
124-
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
125-
RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
126-
}
127-
128-
/// Compute the implied bounds that a callee/impl can assume based on
129-
/// the fact that caller/projector has ensured that `ty` is WF. See
130-
/// the `ImpliedBound` type for more details.
131-
pub fn implied_bounds<'a, 'gcx, 'tcx>(
132-
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
133-
param_env: ty::ParamEnv<'tcx>,
134-
body_id: ast::NodeId,
135-
ty: Ty<'tcx>,
136-
span: Span)
137-
-> Vec<ImpliedBound<'tcx>>
138-
{
139-
// Sometimes when we ask what it takes for T: WF, we get back that
140-
// U: WF is required; in that case, we push U onto this stack and
141-
// process it next. Currently (at least) these resulting
142-
// predicates are always guaranteed to be a subset of the original
143-
// type, so we need not fear non-termination.
144-
let mut wf_types = vec![ty];
145-
146-
let mut implied_bounds = vec![];
147-
148-
while let Some(ty) = wf_types.pop() {
149-
// Compute the obligations for `ty` to be well-formed. If `ty` is
150-
// an unresolved inference variable, just substituted an empty set
151-
// -- because the return type here is going to be things we *add*
152-
// to the environment, it's always ok for this set to be smaller
153-
// than the ultimate set. (Note: normally there won't be
154-
// unresolved inference variables here anyway, but there might be
155-
// during typeck under some circumstances.)
156-
let obligations = obligations(infcx, param_env, body_id, ty, span).unwrap_or(vec![]);
157-
158-
// From the full set of obligations, just filter down to the
159-
// region relationships.
160-
implied_bounds.extend(
161-
obligations
162-
.into_iter()
163-
.flat_map(|obligation| {
164-
assert!(!obligation.has_escaping_regions());
165-
match obligation.predicate {
166-
ty::Predicate::Trait(..) |
167-
ty::Predicate::Equate(..) |
168-
ty::Predicate::Subtype(..) |
169-
ty::Predicate::Projection(..) |
170-
ty::Predicate::ClosureKind(..) |
171-
ty::Predicate::ObjectSafe(..) =>
172-
vec![],
173-
174-
ty::Predicate::WellFormed(subty) => {
175-
wf_types.push(subty);
176-
vec![]
177-
}
178-
179-
ty::Predicate::RegionOutlives(ref data) =>
180-
match infcx.tcx.no_late_bound_regions(data) {
181-
None =>
182-
vec![],
183-
Some(ty::OutlivesPredicate(r_a, r_b)) =>
184-
vec![ImpliedBound::RegionSubRegion(r_b, r_a)],
185-
},
186-
187-
ty::Predicate::TypeOutlives(ref data) =>
188-
match infcx.tcx.no_late_bound_regions(data) {
189-
None => vec![],
190-
Some(ty::OutlivesPredicate(ty_a, r_b)) => {
191-
let ty_a = infcx.resolve_type_vars_if_possible(&ty_a);
192-
let components = infcx.tcx.outlives_components(ty_a);
193-
implied_bounds_from_components(r_b, components)
194-
}
195-
},
196-
}}));
197-
}
198-
199-
implied_bounds
200-
}
201-
202-
/// When we have an implied bound that `T: 'a`, we can further break
203-
/// this down to determine what relationships would have to hold for
204-
/// `T: 'a` to hold. We get to assume that the caller has validated
205-
/// those relationships.
206-
fn implied_bounds_from_components<'tcx>(sub_region: ty::Region<'tcx>,
207-
sup_components: Vec<Component<'tcx>>)
208-
-> Vec<ImpliedBound<'tcx>>
209-
{
210-
sup_components
211-
.into_iter()
212-
.flat_map(|component| {
213-
match component {
214-
Component::Region(r) =>
215-
vec![ImpliedBound::RegionSubRegion(sub_region, r)],
216-
Component::Param(p) =>
217-
vec![ImpliedBound::RegionSubParam(sub_region, p)],
218-
Component::Projection(p) =>
219-
vec![ImpliedBound::RegionSubProjection(sub_region, p)],
220-
Component::EscapingProjection(_) =>
221-
// If the projection has escaping regions, don't
222-
// try to infer any implied bounds even for its
223-
// free components. This is conservative, because
224-
// the caller will still have to prove that those
225-
// free components outlive `sub_region`. But the
226-
// idea is that the WAY that the caller proves
227-
// that may change in the future and we want to
228-
// give ourselves room to get smarter here.
229-
vec![],
230-
Component::UnresolvedInferenceVariable(..) =>
231-
vec![],
232-
}
233-
})
234-
.collect()
235-
}
236-
237109
struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
238110
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
239111
param_env: ty::ParamEnv<'tcx>,

Diff for: src/librustc_typeck/check/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,8 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
614614
.register_predicate_obligation(self, obligation);
615615
}
616616

617-
fn register_predicates(&self, obligations: Vec<traits::PredicateObligation<'tcx>>) {
617+
fn register_predicates<I>(&self, obligations: I)
618+
where I: IntoIterator<Item = traits::PredicateObligation<'tcx>> {
618619
for obligation in obligations {
619620
self.register_predicate(obligation);
620621
}

0 commit comments

Comments
 (0)