Skip to content

Commit 64d6303

Browse files
committedFeb 21, 2024
Inline NllTypeRelating into its only usage site
·
1.90.01.78.0
1 parent 6c03033 commit 64d6303

File tree

5 files changed

+451
-599
lines changed

5 files changed

+451
-599
lines changed
 

‎compiler/rustc_borrowck/src/type_check/relate_tys.rs‎

Lines changed: 446 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
use rustc_data_structures::fx::FxHashMap;
12
use rustc_errors::ErrorGuaranteed;
2-
use rustc_infer::infer::nll_relate::{NllTypeRelating, NllTypeRelatingDelegate};
3-
use rustc_infer::infer::NllRegionVariableOrigin;
4-
use rustc_infer::traits::PredicateObligations;
3+
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
4+
use rustc_infer::infer::{NllRegionVariableOrigin, ObligationEmittingRelation};
5+
use rustc_infer::traits::{Obligation, PredicateObligations};
56
use rustc_middle::mir::ConstraintCategory;
67
use rustc_middle::traits::query::NoSolution;
7-
use rustc_middle::ty::relate::TypeRelation;
8-
use rustc_middle::ty::{self, Ty};
8+
use rustc_middle::traits::ObligationCause;
9+
use rustc_middle::ty::fold::FnMutDelegate;
10+
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
11+
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
912
use rustc_span::symbol::sym;
1013
use rustc_span::{Span, Symbol};
1114

@@ -32,12 +35,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
3235
locations: Locations,
3336
category: ConstraintCategory<'tcx>,
3437
) -> Result<(), NoSolution> {
35-
NllTypeRelating::new(
36-
self.infcx,
37-
NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)),
38-
v,
39-
)
40-
.relate(a, b)?;
38+
NllTypeRelating::new(self, locations, category, UniverseInfo::relate(a, b), v)
39+
.relate(a, b)?;
4140
Ok(())
4241
}
4342

@@ -50,16 +49,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
5049
category: ConstraintCategory<'tcx>,
5150
) -> Result<(), NoSolution> {
5251
NllTypeRelating::new(
53-
self.infcx,
54-
NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::other()),
52+
self,
53+
locations,
54+
category,
55+
UniverseInfo::other(),
5556
ty::Variance::Invariant,
5657
)
5758
.relate(a, b)?;
5859
Ok(())
5960
}
6061
}
6162

62-
struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
63+
pub struct NllTypeRelating<'me, 'bccx, 'tcx> {
6364
type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
6465

6566
/// Where (and why) is this relation taking place?
@@ -71,26 +72,177 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
7172
/// Information so that error reporting knows what types we are relating
7273
/// when reporting a bound region error.
7374
universe_info: UniverseInfo<'tcx>,
75+
76+
/// How are we relating `a` and `b`?
77+
///
78+
/// - Covariant means `a <: b`.
79+
/// - Contravariant means `b <: a`.
80+
/// - Invariant means `a == b`.
81+
/// - Bivariant means that it doesn't matter.
82+
ambient_variance: ty::Variance,
83+
84+
ambient_variance_info: ty::VarianceDiagInfo<'tcx>,
7485
}
7586

76-
impl<'me, 'bccx, 'tcx> NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
77-
fn new(
87+
impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> {
88+
pub fn new(
7889
type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
7990
locations: Locations,
8091
category: ConstraintCategory<'tcx>,
8192
universe_info: UniverseInfo<'tcx>,
93+
ambient_variance: ty::Variance,
8294
) -> Self {
83-
Self { type_checker, locations, category, universe_info }
95+
Self {
96+
type_checker,
97+
locations,
98+
category,
99+
universe_info,
100+
ambient_variance,
101+
ambient_variance_info: ty::VarianceDiagInfo::default(),
102+
}
84103
}
85-
}
86104

87-
impl<'tcx> NllTypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
88-
fn span(&self) -> Span {
89-
self.locations.span(self.type_checker.body)
105+
fn ambient_covariance(&self) -> bool {
106+
match self.ambient_variance {
107+
ty::Variance::Covariant | ty::Variance::Invariant => true,
108+
ty::Variance::Contravariant | ty::Variance::Bivariant => false,
109+
}
90110
}
91111

92-
fn param_env(&self) -> ty::ParamEnv<'tcx> {
93-
self.type_checker.param_env
112+
fn ambient_contravariance(&self) -> bool {
113+
match self.ambient_variance {
114+
ty::Variance::Contravariant | ty::Variance::Invariant => true,
115+
ty::Variance::Covariant | ty::Variance::Bivariant => false,
116+
}
117+
}
118+
119+
fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
120+
let infcx = self.type_checker.infcx;
121+
debug_assert!(!infcx.next_trait_solver());
122+
let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
123+
// `handle_opaque_type` cannot handle subtyping, so to support subtyping
124+
// we instead eagerly generalize here. This is a bit of a mess but will go
125+
// away once we're using the new solver.
126+
let mut enable_subtyping = |ty, ty_is_expected| {
127+
let ty_vid = infcx.next_ty_var_id_in_universe(
128+
TypeVariableOrigin {
129+
kind: TypeVariableOriginKind::MiscVariable,
130+
span: self.span(),
131+
},
132+
ty::UniverseIndex::ROOT,
133+
);
134+
135+
let variance = if ty_is_expected {
136+
self.ambient_variance
137+
} else {
138+
self.ambient_variance.xform(ty::Contravariant)
139+
};
140+
141+
self.type_checker.infcx.instantiate_ty_var(
142+
self,
143+
ty_is_expected,
144+
ty_vid,
145+
variance,
146+
ty,
147+
)?;
148+
Ok(infcx.resolve_vars_if_possible(Ty::new_infer(infcx.tcx, ty::TyVar(ty_vid))))
149+
};
150+
151+
let (a, b) = match (a.kind(), b.kind()) {
152+
(&ty::Alias(ty::Opaque, ..), _) => (a, enable_subtyping(b, false)?),
153+
(_, &ty::Alias(ty::Opaque, ..)) => (enable_subtyping(a, true)?, b),
154+
_ => unreachable!(
155+
"expected at least one opaque type in `relate_opaques`, got {a} and {b}."
156+
),
157+
};
158+
let cause = ObligationCause::dummy_with_span(self.span());
159+
let obligations =
160+
infcx.handle_opaque_type(a, b, true, &cause, self.param_env())?.obligations;
161+
self.register_obligations(obligations);
162+
Ok(())
163+
}
164+
165+
fn enter_forall<T, U>(
166+
&mut self,
167+
binder: ty::Binder<'tcx, T>,
168+
f: impl FnOnce(&mut Self, T) -> U,
169+
) -> U
170+
where
171+
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
172+
{
173+
let value = if let Some(inner) = binder.no_bound_vars() {
174+
inner
175+
} else {
176+
let infcx = self.type_checker.infcx;
177+
let mut lazy_universe = None;
178+
let delegate = FnMutDelegate {
179+
regions: &mut |br: ty::BoundRegion| {
180+
// The first time this closure is called, create a
181+
// new universe for the placeholders we will make
182+
// from here out.
183+
let universe = lazy_universe.unwrap_or_else(|| {
184+
let universe = self.create_next_universe();
185+
lazy_universe = Some(universe);
186+
universe
187+
});
188+
189+
let placeholder = ty::PlaceholderRegion { universe, bound: br };
190+
debug!(?placeholder);
191+
let placeholder_reg = self.next_placeholder_region(placeholder);
192+
debug!(?placeholder_reg);
193+
194+
placeholder_reg
195+
},
196+
types: &mut |_bound_ty: ty::BoundTy| {
197+
unreachable!("we only replace regions in nll_relate, not types")
198+
},
199+
consts: &mut |_bound_var: ty::BoundVar, _ty| {
200+
unreachable!("we only replace regions in nll_relate, not consts")
201+
},
202+
};
203+
204+
infcx.tcx.replace_bound_vars_uncached(binder, delegate)
205+
};
206+
207+
debug!(?value);
208+
f(self, value)
209+
}
210+
211+
#[instrument(skip(self), level = "debug")]
212+
fn instantiate_binder_with_existentials<T>(&mut self, binder: ty::Binder<'tcx, T>) -> T
213+
where
214+
T: ty::TypeFoldable<TyCtxt<'tcx>> + Copy,
215+
{
216+
if let Some(inner) = binder.no_bound_vars() {
217+
return inner;
218+
}
219+
220+
let infcx = self.type_checker.infcx;
221+
let mut reg_map = FxHashMap::default();
222+
let delegate = FnMutDelegate {
223+
regions: &mut |br: ty::BoundRegion| {
224+
if let Some(ex_reg_var) = reg_map.get(&br) {
225+
return *ex_reg_var;
226+
} else {
227+
let ex_reg_var = self.next_existential_region_var(true, br.kind.get_name());
228+
debug!(?ex_reg_var);
229+
reg_map.insert(br, ex_reg_var);
230+
231+
ex_reg_var
232+
}
233+
},
234+
types: &mut |_bound_ty: ty::BoundTy| {
235+
unreachable!("we only replace regions in nll_relate, not types")
236+
},
237+
consts: &mut |_bound_var: ty::BoundVar, _ty| {
238+
unreachable!("we only replace regions in nll_relate, not consts")
239+
},
240+
};
241+
242+
let replaced = infcx.tcx.replace_bound_vars_uncached(binder, delegate);
243+
debug!(?replaced);
244+
245+
replaced
94246
}
95247

96248
fn create_next_universe(&mut self) -> ty::UniverseIndex {
@@ -163,6 +315,249 @@ impl<'tcx> NllTypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tc
163315
},
164316
);
165317
}
318+
}
319+
320+
impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
321+
fn tcx(&self) -> TyCtxt<'tcx> {
322+
self.type_checker.infcx.tcx
323+
}
324+
325+
fn tag(&self) -> &'static str {
326+
"nll::subtype"
327+
}
328+
329+
fn a_is_expected(&self) -> bool {
330+
true
331+
}
332+
333+
#[instrument(skip(self, info), level = "trace", ret)]
334+
fn relate_with_variance<T: Relate<'tcx>>(
335+
&mut self,
336+
variance: ty::Variance,
337+
info: ty::VarianceDiagInfo<'tcx>,
338+
a: T,
339+
b: T,
340+
) -> RelateResult<'tcx, T> {
341+
let old_ambient_variance = self.ambient_variance;
342+
self.ambient_variance = self.ambient_variance.xform(variance);
343+
self.ambient_variance_info = self.ambient_variance_info.xform(info);
344+
345+
debug!(?self.ambient_variance);
346+
// In a bivariant context this always succeeds.
347+
let r =
348+
if self.ambient_variance == ty::Variance::Bivariant { a } else { self.relate(a, b)? };
349+
350+
self.ambient_variance = old_ambient_variance;
351+
352+
Ok(r)
353+
}
354+
355+
#[instrument(skip(self), level = "debug")]
356+
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
357+
let infcx = self.type_checker.infcx;
358+
359+
let a = self.type_checker.infcx.shallow_resolve(a);
360+
assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
361+
362+
if a == b {
363+
return Ok(a);
364+
}
365+
366+
match (a.kind(), b.kind()) {
367+
(_, &ty::Infer(ty::TyVar(_))) => {
368+
span_bug!(
369+
self.span(),
370+
"should not be relating type variables on the right in MIR typeck"
371+
);
372+
}
373+
374+
(&ty::Infer(ty::TyVar(a_vid)), _) => {
375+
infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)?
376+
}
377+
378+
(
379+
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
380+
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
381+
) if a_def_id == b_def_id || infcx.next_trait_solver() => {
382+
infcx.super_combine_tys(self, a, b).map(|_| ()).or_else(|err| {
383+
// This behavior is only there for the old solver, the new solver
384+
// shouldn't ever fail. Instead, it unconditionally emits an
385+
// alias-relate goal.
386+
assert!(!self.type_checker.infcx.next_trait_solver());
387+
self.tcx().dcx().span_delayed_bug(
388+
self.span(),
389+
"failure to relate an opaque to itself should result in an error later on",
390+
);
391+
if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
392+
})?;
393+
}
394+
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
395+
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
396+
if def_id.is_local() && !self.type_checker.infcx.next_trait_solver() =>
397+
{
398+
self.relate_opaques(a, b)?;
399+
}
400+
401+
_ => {
402+
debug!(?a, ?b, ?self.ambient_variance);
403+
404+
// Will also handle unification of `IntVar` and `FloatVar`.
405+
self.type_checker.infcx.super_combine_tys(self, a, b)?;
406+
}
407+
}
408+
409+
Ok(a)
410+
}
411+
412+
#[instrument(skip(self), level = "trace")]
413+
fn regions(
414+
&mut self,
415+
a: ty::Region<'tcx>,
416+
b: ty::Region<'tcx>,
417+
) -> RelateResult<'tcx, ty::Region<'tcx>> {
418+
debug!(?self.ambient_variance);
419+
420+
if self.ambient_covariance() {
421+
// Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
422+
self.push_outlives(a, b, self.ambient_variance_info);
423+
}
424+
425+
if self.ambient_contravariance() {
426+
// Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
427+
self.push_outlives(b, a, self.ambient_variance_info);
428+
}
429+
430+
Ok(a)
431+
}
432+
433+
fn consts(
434+
&mut self,
435+
a: ty::Const<'tcx>,
436+
b: ty::Const<'tcx>,
437+
) -> RelateResult<'tcx, ty::Const<'tcx>> {
438+
let a = self.type_checker.infcx.shallow_resolve(a);
439+
assert!(!a.has_non_region_infer(), "unexpected inference var {:?}", a);
440+
assert!(!b.has_non_region_infer(), "unexpected inference var {:?}", b);
441+
442+
self.type_checker.infcx.super_combine_consts(self, a, b)
443+
}
444+
445+
#[instrument(skip(self), level = "trace")]
446+
fn binders<T>(
447+
&mut self,
448+
a: ty::Binder<'tcx, T>,
449+
b: ty::Binder<'tcx, T>,
450+
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
451+
where
452+
T: Relate<'tcx>,
453+
{
454+
// We want that
455+
//
456+
// ```
457+
// for<'a> fn(&'a u32) -> &'a u32 <:
458+
// fn(&'b u32) -> &'b u32
459+
// ```
460+
//
461+
// but not
462+
//
463+
// ```
464+
// fn(&'a u32) -> &'a u32 <:
465+
// for<'b> fn(&'b u32) -> &'b u32
466+
// ```
467+
//
468+
// We therefore proceed as follows:
469+
//
470+
// - Instantiate binders on `b` universally, yielding a universe U1.
471+
// - Instantiate binders on `a` existentially in U1.
472+
473+
debug!(?self.ambient_variance);
474+
475+
if let (Some(a), Some(b)) = (a.no_bound_vars(), b.no_bound_vars()) {
476+
// Fast path for the common case.
477+
self.relate(a, b)?;
478+
return Ok(ty::Binder::dummy(a));
479+
}
480+
481+
if self.ambient_covariance() {
482+
// Covariance, so we want `for<..> A <: for<..> B` --
483+
// therefore we compare any instantiation of A (i.e., A
484+
// instantiated with existentials) against every
485+
// instantiation of B (i.e., B instantiated with
486+
// universals).
487+
488+
// Reset the ambient variance to covariant. This is needed
489+
// to correctly handle cases like
490+
//
491+
// for<'a> fn(&'a u32, &'a u32) == for<'b, 'c> fn(&'b u32, &'c u32)
492+
//
493+
// Somewhat surprisingly, these two types are actually
494+
// **equal**, even though the one on the right looks more
495+
// polymorphic. The reason is due to subtyping. To see it,
496+
// consider that each function can call the other:
497+
//
498+
// - The left function can call the right with `'b` and
499+
// `'c` both equal to `'a`
500+
//
501+
// - The right function can call the left with `'a` set to
502+
// `{P}`, where P is the point in the CFG where the call
503+
// itself occurs. Note that `'b` and `'c` must both
504+
// include P. At the point, the call works because of
505+
// subtyping (i.e., `&'b u32 <: &{P} u32`).
506+
let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
507+
508+
// Note: the order here is important. Create the placeholders first, otherwise
509+
// we assign the wrong universe to the existential!
510+
self.enter_forall(b, |this, b| {
511+
let a = this.instantiate_binder_with_existentials(a);
512+
this.relate(a, b)
513+
})?;
514+
515+
self.ambient_variance = variance;
516+
}
517+
518+
if self.ambient_contravariance() {
519+
// Contravariance, so we want `for<..> A :> for<..> B`
520+
// -- therefore we compare every instantiation of A (i.e.,
521+
// A instantiated with universals) against any
522+
// instantiation of B (i.e., B instantiated with
523+
// existentials). Opposite of above.
524+
525+
// Reset ambient variance to contravariance. See the
526+
// covariant case above for an explanation.
527+
let variance =
528+
std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
529+
530+
self.enter_forall(a, |this, a| {
531+
let b = this.instantiate_binder_with_existentials(b);
532+
this.relate(a, b)
533+
})?;
534+
535+
self.ambient_variance = variance;
536+
}
537+
538+
Ok(a)
539+
}
540+
}
541+
542+
impl<'bccx, 'tcx> ObligationEmittingRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> {
543+
fn span(&self) -> Span {
544+
self.locations.span(self.type_checker.body)
545+
}
546+
547+
fn param_env(&self) -> ty::ParamEnv<'tcx> {
548+
self.type_checker.param_env
549+
}
550+
551+
fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
552+
self.register_obligations(
553+
obligations
554+
.into_iter()
555+
.map(|to_pred| {
556+
Obligation::new(self.tcx(), ObligationCause::dummy(), self.param_env(), to_pred)
557+
})
558+
.collect(),
559+
);
560+
}
166561

167562
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
168563
let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op(
@@ -176,4 +571,32 @@ impl<'tcx> NllTypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tc
176571
},
177572
);
178573
}
574+
575+
fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
576+
unreachable!("manually overridden to handle ty::Variance::Contravariant ambient variance")
577+
}
578+
579+
fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
580+
self.register_predicates([ty::Binder::dummy(match self.ambient_variance {
581+
ty::Variance::Covariant => ty::PredicateKind::AliasRelate(
582+
a.into(),
583+
b.into(),
584+
ty::AliasRelationDirection::Subtype,
585+
),
586+
// a :> b is b <: a
587+
ty::Variance::Contravariant => ty::PredicateKind::AliasRelate(
588+
b.into(),
589+
a.into(),
590+
ty::AliasRelationDirection::Subtype,
591+
),
592+
ty::Variance::Invariant => ty::PredicateKind::AliasRelate(
593+
a.into(),
594+
b.into(),
595+
ty::AliasRelationDirection::Equate,
596+
),
597+
ty::Variance::Bivariant => {
598+
unreachable!("cannot defer an alias-relate goal with Bivariant variance (yet?)")
599+
}
600+
})]);
601+
}
179602
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ use self::region_constraints::{
5454
RegionConstraintCollector, RegionConstraintStorage, RegionSnapshot,
5555
};
5656
pub use self::relate::combine::CombineFields;
57-
pub use self::relate::nll as nll_relate;
5857
use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
5958

6059
pub mod at;

‎compiler/rustc_infer/src/infer/relate/generalize.rs‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@ impl<'tcx> InferCtxt<'tcx> {
2222
/// subtyping could occur. This also does the occurs checks, detecting whether
2323
/// instantiating `target_vid` would result in a cyclic type. We eagerly error
2424
/// in this case.
25+
///
26+
/// This is *not* expected to be used anywhere except for an implementation of
27+
/// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all
28+
/// other usecases (i.e. setting the value of a type var).
2529
#[instrument(level = "debug", skip(self, relation, target_is_expected))]
26-
pub(super) fn instantiate_ty_var<R: ObligationEmittingRelation<'tcx>>(
30+
pub fn instantiate_ty_var<R: ObligationEmittingRelation<'tcx>>(
2731
&self,
2832
relation: &mut R,
2933
target_is_expected: bool,

‎compiler/rustc_infer/src/infer/relate/mod.rs‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,4 @@ mod glb;
88
mod higher_ranked;
99
mod lattice;
1010
mod lub;
11-
pub mod nll;
1211
mod sub;

‎compiler/rustc_infer/src/infer/relate/nll.rs‎

Lines changed: 0 additions & 573 deletions
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.