Skip to content

Commit 22f28a7

Browse files
committed
Merge rustc_infer::infer::relate::{glb,lub}.
Most of the code in these two modules is duplicated in the other module. This commit eliminates the duplication by replacing them with a new module `lattice_op`. The new `LatticeOpKind` enum is used to distinguish between glb and lub in the few places where the behaviour differs.
1 parent 7042c26 commit 22f28a7

File tree

5 files changed

+185
-332
lines changed

5 files changed

+185
-332
lines changed

compiler/rustc_infer/src/infer/relate/combine.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ use rustc_middle::ty::{self, InferConst, IntType, Ty, TyCtxt, TypeVisitableExt,
2626
pub use rustc_next_trait_solver::relate::combine::*;
2727
use tracing::debug;
2828

29-
use super::glb::Glb;
30-
use super::lub::Lub;
29+
use super::lattice::{LatticeOp, LatticeOpKind};
3130
use super::type_relating::TypeRelating;
3231
use super::{RelateResult, StructurallyRelateAliases};
3332
use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace, relate};
@@ -298,12 +297,16 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
298297
TypeRelating::new(self, StructurallyRelateAliases::No, ty::Contravariant)
299298
}
300299

301-
pub fn lub<'a>(&'a mut self) -> Lub<'a, 'infcx, 'tcx> {
302-
Lub::new(self)
300+
pub(crate) fn lattice_op<'a>(&'a mut self, kind: LatticeOpKind) -> LatticeOp<'a, 'infcx, 'tcx> {
301+
LatticeOp::new(kind, self)
303302
}
304303

305-
pub fn glb<'a>(&'a mut self) -> Glb<'a, 'infcx, 'tcx> {
306-
Glb::new(self)
304+
pub(crate) fn lub<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> {
305+
LatticeOp::new(LatticeOpKind::Lub, self)
306+
}
307+
308+
pub(crate) fn glb<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> {
309+
LatticeOp::new(LatticeOpKind::Glb, self)
307310
}
308311

309312
pub fn register_obligations(

compiler/rustc_infer/src/infer/relate/glb.rs

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

compiler/rustc_infer/src/infer/relate/lattice.rs

Lines changed: 176 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,23 @@
1717
//!
1818
//! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
1919
20-
use rustc_middle::ty::relate::RelateResult;
21-
use rustc_middle::ty::{self, Ty, TyVar};
22-
use tracing::instrument;
20+
use rustc_middle::traits::solve::Goal;
21+
use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
22+
use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt};
23+
use rustc_span::Span;
24+
use tracing::{debug, instrument};
2325

24-
use super::combine::PredicateEmittingRelation;
25-
use crate::infer::{DefineOpaqueTypes, InferCtxt};
26+
use super::StructurallyRelateAliases;
27+
use super::combine::{CombineFields, PredicateEmittingRelation};
28+
use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin};
2629
use crate::traits::ObligationCause;
2730

2831
/// Trait for returning data about a lattice, and for abstracting
2932
/// over the "direction" of the lattice operation (LUB/GLB).
3033
///
3134
/// GLB moves "down" the lattice (to smaller values); LUB moves
3235
/// "up" the lattice (to bigger values).
33-
pub(crate) trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<InferCtxt<'tcx>> {
36+
trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<InferCtxt<'tcx>> {
3437
fn infcx(&self) -> &'f InferCtxt<'tcx>;
3538

3639
fn cause(&self) -> &ObligationCause<'tcx>;
@@ -48,7 +51,7 @@ pub(crate) trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation<InferCtxt<'tcx>
4851

4952
/// Relates two types using a given lattice.
5053
#[instrument(skip(this), level = "debug")]
51-
pub fn super_lattice_tys<'a, 'tcx: 'a, L>(
54+
fn super_lattice_tys<'a, 'tcx: 'a, L>(
5255
this: &mut L,
5356
a: Ty<'tcx>,
5457
b: Ty<'tcx>,
@@ -113,3 +116,169 @@ where
113116
_ => infcx.super_combine_tys(this, a, b),
114117
}
115118
}
119+
120+
#[derive(Clone, Copy)]
121+
pub(crate) enum LatticeOpKind {
122+
Glb,
123+
Lub,
124+
}
125+
126+
/// A greatest lower bound" (common subtype) or least upper bound (common supertype).
127+
pub(crate) struct LatticeOp<'combine, 'infcx, 'tcx> {
128+
kind: LatticeOpKind,
129+
fields: &'combine mut CombineFields<'infcx, 'tcx>,
130+
}
131+
132+
impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> {
133+
pub(crate) fn new(
134+
kind: LatticeOpKind,
135+
fields: &'combine mut CombineFields<'infcx, 'tcx>,
136+
) -> LatticeOp<'combine, 'infcx, 'tcx> {
137+
LatticeOp { kind, fields }
138+
}
139+
}
140+
141+
impl<'tcx> TypeRelation<TyCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> {
142+
fn cx(&self) -> TyCtxt<'tcx> {
143+
self.fields.tcx()
144+
}
145+
146+
fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>(
147+
&mut self,
148+
variance: ty::Variance,
149+
_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>,
150+
a: T,
151+
b: T,
152+
) -> RelateResult<'tcx, T> {
153+
match variance {
154+
ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b),
155+
ty::Covariant => self.relate(a, b),
156+
// FIXME(#41044) -- not correct, need test
157+
ty::Bivariant => Ok(a),
158+
ty::Contravariant => self.fields.lattice_op(self.kind).relate(a, b),
159+
}
160+
}
161+
162+
#[instrument(skip(self), level = "trace")]
163+
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
164+
super_lattice_tys(self, a, b)
165+
}
166+
167+
#[instrument(skip(self), level = "trace")]
168+
fn regions(
169+
&mut self,
170+
a: ty::Region<'tcx>,
171+
b: ty::Region<'tcx>,
172+
) -> RelateResult<'tcx, ty::Region<'tcx>> {
173+
let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
174+
let mut inner = self.fields.infcx.inner.borrow_mut();
175+
let mut constraints = inner.unwrap_region_constraints();
176+
Ok(match self.kind {
177+
// GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8
178+
LatticeOpKind::Glb => constraints.glb_regions(self.cx(), origin, a, b),
179+
180+
// LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8
181+
LatticeOpKind::Lub => constraints.lub_regions(self.cx(), origin, a, b),
182+
})
183+
}
184+
185+
#[instrument(skip(self), level = "trace")]
186+
fn consts(
187+
&mut self,
188+
a: ty::Const<'tcx>,
189+
b: ty::Const<'tcx>,
190+
) -> RelateResult<'tcx, ty::Const<'tcx>> {
191+
self.fields.infcx.super_combine_consts(self, a, b)
192+
}
193+
194+
fn binders<T>(
195+
&mut self,
196+
a: ty::Binder<'tcx, T>,
197+
b: ty::Binder<'tcx, T>,
198+
) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
199+
where
200+
T: Relate<TyCtxt<'tcx>>,
201+
{
202+
// GLB/LUB of a binder and itself is just itself
203+
if a == b {
204+
return Ok(a);
205+
}
206+
207+
debug!("binders(a={:?}, b={:?})", a, b);
208+
if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() {
209+
// When higher-ranked types are involved, computing the GLB/LUB is
210+
// very challenging, switch to invariance. This is obviously
211+
// overly conservative but works ok in practice.
212+
self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?;
213+
Ok(a)
214+
} else {
215+
Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?))
216+
}
217+
}
218+
}
219+
220+
impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for LatticeOp<'combine, 'infcx, 'tcx> {
221+
fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
222+
self.fields.infcx
223+
}
224+
225+
fn cause(&self) -> &ObligationCause<'tcx> {
226+
&self.fields.trace.cause
227+
}
228+
229+
fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
230+
let mut sub = self.fields.sub();
231+
match self.kind {
232+
LatticeOpKind::Glb => {
233+
sub.relate(v, a)?;
234+
sub.relate(v, b)?;
235+
}
236+
LatticeOpKind::Lub => {
237+
sub.relate(a, v)?;
238+
sub.relate(b, v)?;
239+
}
240+
}
241+
Ok(())
242+
}
243+
244+
fn define_opaque_types(&self) -> DefineOpaqueTypes {
245+
self.fields.define_opaque_types
246+
}
247+
}
248+
249+
impl<'tcx> PredicateEmittingRelation<InferCtxt<'tcx>> for LatticeOp<'_, '_, 'tcx> {
250+
fn span(&self) -> Span {
251+
self.fields.trace.span()
252+
}
253+
254+
fn structurally_relate_aliases(&self) -> StructurallyRelateAliases {
255+
StructurallyRelateAliases::No
256+
}
257+
258+
fn param_env(&self) -> ty::ParamEnv<'tcx> {
259+
self.fields.param_env
260+
}
261+
262+
fn register_predicates(
263+
&mut self,
264+
obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
265+
) {
266+
self.fields.register_predicates(obligations);
267+
}
268+
269+
fn register_goals(
270+
&mut self,
271+
obligations: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
272+
) {
273+
self.fields.register_obligations(obligations);
274+
}
275+
276+
fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
277+
self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate(
278+
a.into(),
279+
b.into(),
280+
// FIXME(deferred_projection_equality): This isn't right, I think?
281+
ty::AliasRelationDirection::Equate,
282+
))]);
283+
}
284+
}

0 commit comments

Comments
 (0)