Skip to content

Commit 35bc8ae

Browse files
committed
eager nll type relating
1 parent da0fe80 commit 35bc8ae

File tree

1 file changed

+104
-170
lines changed
  • compiler/rustc_infer/src/infer/nll_relate

1 file changed

+104
-170
lines changed

compiler/rustc_infer/src/infer/nll_relate/mod.rs

+104-170
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use crate::traits::{Obligation, PredicateObligations};
2828
use rustc_data_structures::fx::FxHashMap;
2929
use rustc_middle::traits::ObligationCause;
3030
use rustc_middle::ty::error::TypeError;
31+
use rustc_middle::ty::fold::FnMutDelegate;
3132
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
3233
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
3334
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
@@ -55,21 +56,6 @@ where
5556
ambient_variance: ty::Variance,
5657

5758
ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
58-
59-
/// When we pass through a set of binders (e.g., when looking into
60-
/// a `fn` type), we push a new bound region scope onto here. This
61-
/// will contain the instantiated region for each region in those
62-
/// binders. When we then encounter a `ReLateBound(d, br)`, we can
63-
/// use the De Bruijn index `d` to find the right scope, and then
64-
/// bound region name `br` to find the specific instantiation from
65-
/// within that scope. See `replace_bound_region`.
66-
///
67-
/// This field stores the instantiations for late-bound regions in
68-
/// the `a` type.
69-
a_scopes: Vec<BoundRegionScope<'tcx>>,
70-
71-
/// Same as `a_scopes`, but for the `b` type.
72-
b_scopes: Vec<BoundRegionScope<'tcx>>,
7359
}
7460

7561
pub trait TypeRelatingDelegate<'tcx> {
@@ -147,8 +133,6 @@ where
147133
delegate,
148134
ambient_variance,
149135
ambient_variance_info: ty::VarianceDiagInfo::default(),
150-
a_scopes: vec![],
151-
b_scopes: vec![],
152136
}
153137
}
154138

@@ -166,88 +150,6 @@ where
166150
}
167151
}
168152

169-
fn create_scope(
170-
&mut self,
171-
value: ty::Binder<'tcx, impl Relate<'tcx>>,
172-
universally_quantified: UniversallyQuantified,
173-
) -> BoundRegionScope<'tcx> {
174-
let mut scope = BoundRegionScope::default();
175-
176-
// Create a callback that creates (via the delegate) either an
177-
// existential or placeholder region as needed.
178-
let mut next_region = {
179-
let delegate = &mut self.delegate;
180-
let mut lazy_universe = None;
181-
move |br: ty::BoundRegion| {
182-
if universally_quantified.0 {
183-
// The first time this closure is called, create a
184-
// new universe for the placeholders we will make
185-
// from here out.
186-
let universe = lazy_universe.unwrap_or_else(|| {
187-
let universe = delegate.create_next_universe();
188-
lazy_universe = Some(universe);
189-
universe
190-
});
191-
192-
let placeholder = ty::PlaceholderRegion { universe, name: br.kind };
193-
delegate.next_placeholder_region(placeholder)
194-
} else {
195-
delegate.next_existential_region_var(true, br.kind.get_name())
196-
}
197-
}
198-
};
199-
200-
value.skip_binder().visit_with(&mut ScopeInstantiator {
201-
next_region: &mut next_region,
202-
target_index: ty::INNERMOST,
203-
bound_region_scope: &mut scope,
204-
});
205-
206-
scope
207-
}
208-
209-
/// When we encounter binders during the type traversal, we record
210-
/// the value to substitute for each of the things contained in
211-
/// that binder. (This will be either a universal placeholder or
212-
/// an existential inference variable.) Given the De Bruijn index
213-
/// `debruijn` (and name `br`) of some binder we have now
214-
/// encountered, this routine finds the value that we instantiated
215-
/// the region with; to do so, it indexes backwards into the list
216-
/// of ambient scopes `scopes`.
217-
fn lookup_bound_region(
218-
debruijn: ty::DebruijnIndex,
219-
br: &ty::BoundRegion,
220-
first_free_index: ty::DebruijnIndex,
221-
scopes: &[BoundRegionScope<'tcx>],
222-
) -> ty::Region<'tcx> {
223-
// The debruijn index is a "reverse index" into the
224-
// scopes listing. So when we have INNERMOST (0), we
225-
// want the *last* scope pushed, and so forth.
226-
let debruijn_index = debruijn.index() - first_free_index.index();
227-
let scope = &scopes[scopes.len() - debruijn_index - 1];
228-
229-
// Find this bound region in that scope to map to a
230-
// particular region.
231-
scope.map[br]
232-
}
233-
234-
/// If `r` is a bound region, find the scope in which it is bound
235-
/// (from `scopes`) and return the value that we instantiated it
236-
/// with. Otherwise just return `r`.
237-
fn replace_bound_region(
238-
&self,
239-
r: ty::Region<'tcx>,
240-
first_free_index: ty::DebruijnIndex,
241-
scopes: &[BoundRegionScope<'tcx>],
242-
) -> ty::Region<'tcx> {
243-
debug!("replace_bound_regions(scopes={:?})", scopes);
244-
if let ty::ReLateBound(debruijn, br) = *r {
245-
Self::lookup_bound_region(debruijn, &br, first_free_index, scopes)
246-
} else {
247-
r
248-
}
249-
}
250-
251153
/// Push a new outlives requirement into our output set of
252154
/// constraints.
253155
fn push_outlives(
@@ -314,18 +216,9 @@ where
314216

315217
self.infcx.inner.borrow_mut().type_variables().instantiate(vid, generalized_ty);
316218

317-
// The generalized values we extract from `canonical_var_values` have
318-
// been fully instantiated and hence the set of scopes we have
319-
// doesn't matter -- just to be sure, put an empty vector
320-
// in there.
321-
let old_a_scopes = std::mem::take(pair.vid_scopes(self));
322-
323219
// Relate the generalized kind to the original one.
324220
let result = pair.relate_generalized_ty(self, generalized_ty);
325221

326-
// Restore the old scopes now.
327-
*pair.vid_scopes(self) = old_a_scopes;
328-
329222
debug!("relate_ty_var: complete, result = {:?}", result);
330223
result
331224
}
@@ -379,6 +272,97 @@ where
379272
trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
380273
Ok(a)
381274
}
275+
276+
#[instrument(skip(self), level = "debug")]
277+
fn instantiate_binder_with_placeholders<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
278+
where
279+
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
280+
{
281+
if let Some(inner) = binder.no_bound_vars() {
282+
return inner;
283+
}
284+
285+
let mut next_region = {
286+
let nll_delegate = &mut self.delegate;
287+
let mut lazy_universe = None;
288+
289+
move |br: ty::BoundRegion| {
290+
// The first time this closure is called, create a
291+
// new universe for the placeholders we will make
292+
// from here out.
293+
let universe = lazy_universe.unwrap_or_else(|| {
294+
let universe = nll_delegate.create_next_universe();
295+
lazy_universe = Some(universe);
296+
universe
297+
});
298+
299+
let placeholder = ty::PlaceholderRegion { universe, name: br.kind };
300+
debug!(?placeholder);
301+
let placeholder_reg = nll_delegate.next_placeholder_region(placeholder);
302+
debug!(?placeholder_reg);
303+
304+
placeholder_reg
305+
}
306+
};
307+
308+
let delegate = FnMutDelegate {
309+
regions: &mut next_region,
310+
types: &mut |_bound_ty: ty::BoundTy| {
311+
unreachable!("we only replace regions in nll_relate, not types")
312+
},
313+
consts: &mut |_bound_var: ty::BoundVar, _ty| {
314+
unreachable!("we only replace regions in nll_relate, not consts")
315+
},
316+
};
317+
318+
let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate);
319+
debug!(?replaced);
320+
321+
replaced
322+
}
323+
324+
#[instrument(skip(self), level = "debug")]
325+
fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
326+
where
327+
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
328+
{
329+
if let Some(inner) = binder.no_bound_vars() {
330+
return inner;
331+
}
332+
333+
let mut next_region = {
334+
let nll_delegate = &mut self.delegate;
335+
let mut reg_map = FxHashMap::default();
336+
337+
move |br: ty::BoundRegion| {
338+
if let Some(ex_reg_var) = reg_map.get(&br) {
339+
return *ex_reg_var;
340+
} else {
341+
let ex_reg_var =
342+
nll_delegate.next_existential_region_var(true, br.kind.get_name());
343+
debug!(?ex_reg_var);
344+
reg_map.insert(br, ex_reg_var);
345+
346+
ex_reg_var
347+
}
348+
}
349+
};
350+
351+
let delegate = FnMutDelegate {
352+
regions: &mut next_region,
353+
types: &mut |_bound_ty: ty::BoundTy| {
354+
unreachable!("we only replace regions in nll_relate, not types")
355+
},
356+
consts: &mut |_bound_var: ty::BoundVar, _ty| {
357+
unreachable!("we only replace regions in nll_relate, not consts")
358+
},
359+
};
360+
361+
let replaced = self.infcx.tcx.replace_bound_vars_uncached(binder, delegate);
362+
debug!(?replaced);
363+
364+
replaced
365+
}
382366
}
383367

384368
/// When we instantiate an inference variable with a value in
@@ -396,14 +380,6 @@ trait VidValuePair<'tcx>: Debug {
396380
/// opposite part of the tuple from the vid).
397381
fn value_ty(&self) -> Ty<'tcx>;
398382

399-
/// Extract the scopes that apply to whichever side of the tuple
400-
/// the vid was found on. See the comment where this is called
401-
/// for more details on why we want them.
402-
fn vid_scopes<'r, D: TypeRelatingDelegate<'tcx>>(
403-
&self,
404-
relate: &'r mut TypeRelating<'_, 'tcx, D>,
405-
) -> &'r mut Vec<BoundRegionScope<'tcx>>;
406-
407383
/// Given a generalized type G that should replace the vid, relate
408384
/// G to the value, putting G on whichever side the vid would have
409385
/// appeared.
@@ -425,16 +401,6 @@ impl<'tcx> VidValuePair<'tcx> for (ty::TyVid, Ty<'tcx>) {
425401
self.1
426402
}
427403

428-
fn vid_scopes<'r, D>(
429-
&self,
430-
relate: &'r mut TypeRelating<'_, 'tcx, D>,
431-
) -> &'r mut Vec<BoundRegionScope<'tcx>>
432-
where
433-
D: TypeRelatingDelegate<'tcx>,
434-
{
435-
&mut relate.a_scopes
436-
}
437-
438404
fn relate_generalized_ty<D>(
439405
&self,
440406
relate: &mut TypeRelating<'_, 'tcx, D>,
@@ -457,16 +423,6 @@ impl<'tcx> VidValuePair<'tcx> for (Ty<'tcx>, ty::TyVid) {
457423
self.0
458424
}
459425

460-
fn vid_scopes<'r, D>(
461-
&self,
462-
relate: &'r mut TypeRelating<'_, 'tcx, D>,
463-
) -> &'r mut Vec<BoundRegionScope<'tcx>>
464-
where
465-
D: TypeRelatingDelegate<'tcx>,
466-
{
467-
&mut relate.b_scopes
468-
}
469-
470426
fn relate_generalized_ty<D>(
471427
&self,
472428
relate: &mut TypeRelating<'_, 'tcx, D>,
@@ -602,20 +558,14 @@ where
602558
) -> RelateResult<'tcx, ty::Region<'tcx>> {
603559
debug!(?self.ambient_variance);
604560

605-
let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes);
606-
let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes);
607-
608-
debug!(?v_a);
609-
debug!(?v_b);
610-
611561
if self.ambient_covariance() {
612562
// Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
613-
self.push_outlives(v_a, v_b, self.ambient_variance_info);
563+
self.push_outlives(a, b, self.ambient_variance_info);
614564
}
615565

616566
if self.ambient_contravariance() {
617567
// Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
618-
self.push_outlives(v_b, v_a, self.ambient_variance_info);
568+
self.push_outlives(b, a, self.ambient_variance_info);
619569
}
620570

621571
Ok(a)
@@ -689,15 +639,6 @@ where
689639
// instantiation of B (i.e., B instantiated with
690640
// universals).
691641

692-
let b_scope = self.create_scope(b, UniversallyQuantified(true));
693-
let a_scope = self.create_scope(a, UniversallyQuantified(false));
694-
695-
debug!(?a_scope, "(existential)");
696-
debug!(?b_scope, "(universal)");
697-
698-
self.b_scopes.push(b_scope);
699-
self.a_scopes.push(a_scope);
700-
701642
// Reset the ambient variance to covariant. This is needed
702643
// to correctly handle cases like
703644
//
@@ -718,12 +659,14 @@ where
718659
// subtyping (i.e., `&'b u32 <: &{P} u32`).
719660
let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
720661

721-
self.relate(a.skip_binder(), b.skip_binder())?;
662+
// Note: the order here is important. Create the placeholders first, otherwise
663+
// we assign the wrong universe to the existential!
664+
let b_replaced = self.instantiate_binder_with_placeholders(b);
665+
let a_replaced = self.instantiate_binder_with_existentials(a);
722666

723-
self.ambient_variance = variance;
667+
self.relate(a_replaced, b_replaced)?;
724668

725-
self.b_scopes.pop().unwrap();
726-
self.a_scopes.pop().unwrap();
669+
self.ambient_variance = variance;
727670
}
728671

729672
if self.ambient_contravariance() {
@@ -733,26 +676,17 @@ where
733676
// instantiation of B (i.e., B instantiated with
734677
// existentials). Opposite of above.
735678

736-
let a_scope = self.create_scope(a, UniversallyQuantified(true));
737-
let b_scope = self.create_scope(b, UniversallyQuantified(false));
738-
739-
debug!(?a_scope, "(universal)");
740-
debug!(?b_scope, "(existential)");
741-
742-
self.a_scopes.push(a_scope);
743-
self.b_scopes.push(b_scope);
744-
745679
// Reset ambient variance to contravariance. See the
746680
// covariant case above for an explanation.
747681
let variance =
748682
std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
749683

750-
self.relate(a.skip_binder(), b.skip_binder())?;
684+
let a_replaced = self.instantiate_binder_with_placeholders(a);
685+
let b_replaced = self.instantiate_binder_with_existentials(b);
751686

752-
self.ambient_variance = variance;
687+
self.relate(a_replaced, b_replaced)?;
753688

754-
self.b_scopes.pop().unwrap();
755-
self.a_scopes.pop().unwrap();
689+
self.ambient_variance = variance;
756690
}
757691

758692
Ok(a)

0 commit comments

Comments
 (0)