From 0aab10135dd3d4e43e44ba5c375f5fae382cae49 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 3 Oct 2024 16:20:26 +1000 Subject: [PATCH] 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. --- .../rustc_infer/src/infer/relate/combine.rs | 13 +- compiler/rustc_infer/src/infer/relate/glb.rs | 159 -------------- .../rustc_infer/src/infer/relate/lattice.rs | 197 +++++++++++++++++- compiler/rustc_infer/src/infer/relate/lub.rs | 158 -------------- compiler/rustc_infer/src/infer/relate/mod.rs | 2 - 5 files changed, 196 insertions(+), 333 deletions(-) delete mode 100644 compiler/rustc_infer/src/infer/relate/glb.rs delete mode 100644 compiler/rustc_infer/src/infer/relate/lub.rs diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index e75d7b7db14..d9e59d67ba3 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -1,4 +1,4 @@ -//! There are four type combiners: [TypeRelating], [Lub], and [Glb], +//! There are four type combiners: [TypeRelating], `Lub`, and `Glb`, //! and `NllTypeRelating` in rustc_borrowck, which is only used for NLL. //! //! Each implements the trait [TypeRelation] and contains methods for @@ -26,8 +26,7 @@ pub use rustc_next_trait_solver::relate::combine::*; use tracing::debug; -use super::glb::Glb; -use super::lub::Lub; +use super::lattice::{LatticeOp, LatticeOpKind}; use super::type_relating::TypeRelating; use super::{RelateResult, StructurallyRelateAliases}; use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace, relate}; @@ -298,12 +297,12 @@ pub fn sup<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> { TypeRelating::new(self, StructurallyRelateAliases::No, ty::Contravariant) } - pub fn lub<'a>(&'a mut self) -> Lub<'a, 'infcx, 'tcx> { - Lub::new(self) + pub(crate) fn lub<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> { + LatticeOp::new(self, LatticeOpKind::Lub) } - pub fn glb<'a>(&'a mut self) -> Glb<'a, 'infcx, 'tcx> { - Glb::new(self) + pub(crate) fn glb<'a>(&'a mut self) -> LatticeOp<'a, 'infcx, 'tcx> { + LatticeOp::new(self, LatticeOpKind::Glb) } pub fn register_obligations( diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs deleted file mode 100644 index ed108f42969..00000000000 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ /dev/null @@ -1,159 +0,0 @@ -//! Greatest lower bound. See [`lattice`]. - -use rustc_middle::traits::solve::Goal; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::Span; -use tracing::{debug, instrument}; - -use super::StructurallyRelateAliases; -use super::combine::{CombineFields, PredicateEmittingRelation}; -use super::lattice::{self, LatticeDir}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; -use crate::traits::ObligationCause; - -/// "Greatest lower bound" (common subtype) -pub struct Glb<'combine, 'infcx, 'tcx> { - fields: &'combine mut CombineFields<'infcx, 'tcx>, -} - -impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Glb<'combine, 'infcx, 'tcx> { - Glb { fields } - } -} - -impl<'tcx> TypeRelation> for Glb<'_, '_, 'tcx> { - fn cx(&self) -> TyCtxt<'tcx> { - self.fields.tcx() - } - - fn relate_with_variance>>( - &mut self, - variance: ty::Variance, - _info: ty::VarianceDiagInfo>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - match variance { - ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b), - ty::Covariant => self.relate(a, b), - // FIXME(#41044) -- not correct, need test - ty::Bivariant => Ok(a), - ty::Contravariant => self.fields.lub().relate(a, b), - } - } - - #[instrument(skip(self), level = "trace")] - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - lattice::super_lattice_tys(self, a, b) - } - - #[instrument(skip(self), level = "trace")] - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); - // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 - Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions( - self.cx(), - origin, - a, - b, - )) - } - - #[instrument(skip(self), level = "trace")] - fn consts( - &mut self, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - self.fields.infcx.super_combine_consts(self, a, b) - } - - fn binders( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate>, - { - // GLB of a binder and itself is just itself - if a == b { - return Ok(a); - } - - debug!("binders(a={:?}, b={:?})", a, b); - if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() { - // When higher-ranked types are involved, computing the GLB is - // very challenging, switch to invariance. This is obviously - // overly conservative but works ok in practice. - self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?; - Ok(a) - } else { - Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) - } - } -} - -impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, 'tcx> { - fn infcx(&self) -> &'infcx InferCtxt<'tcx> { - self.fields.infcx - } - - fn cause(&self) -> &ObligationCause<'tcx> { - &self.fields.trace.cause - } - - fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(); - sub.relate(v, a)?; - sub.relate(v, b)?; - Ok(()) - } - - fn define_opaque_types(&self) -> DefineOpaqueTypes { - self.fields.define_opaque_types - } -} - -impl<'tcx> PredicateEmittingRelation> for Glb<'_, '_, 'tcx> { - fn span(&self) -> Span { - self.fields.trace.span() - } - - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - StructurallyRelateAliases::No - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.fields.param_env - } - - fn register_predicates( - &mut self, - obligations: impl IntoIterator, ty::Predicate<'tcx>>>, - ) { - self.fields.register_predicates(obligations); - } - - fn register_goals( - &mut self, - obligations: impl IntoIterator>>, - ) { - self.fields.register_obligations(obligations); - } - - fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { - self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - // FIXME(deferred_projection_equality): This isn't right, I think? - ty::AliasRelationDirection::Equate, - ))]); - } -} diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 1d3f45465d6..1e4db708986 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -17,12 +17,15 @@ //! //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order) -use rustc_middle::ty::relate::RelateResult; -use rustc_middle::ty::{self, Ty, TyVar}; -use tracing::instrument; +use rustc_middle::traits::solve::Goal; +use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::{self, Ty, TyCtxt, TyVar, TypeVisitableExt}; +use rustc_span::Span; +use tracing::{debug, instrument}; -use super::combine::PredicateEmittingRelation; -use crate::infer::{DefineOpaqueTypes, InferCtxt}; +use super::StructurallyRelateAliases; +use super::combine::{CombineFields, PredicateEmittingRelation}; +use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::ObligationCause; /// Trait for returning data about a lattice, and for abstracting @@ -30,7 +33,7 @@ /// /// GLB moves "down" the lattice (to smaller values); LUB moves /// "up" the lattice (to bigger values). -pub(crate) trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation> { +trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation> { fn infcx(&self) -> &'f InferCtxt<'tcx>; fn cause(&self) -> &ObligationCause<'tcx>; @@ -48,7 +51,7 @@ pub(crate) trait LatticeDir<'f, 'tcx>: PredicateEmittingRelation /// Relates two types using a given lattice. #[instrument(skip(this), level = "debug")] -pub fn super_lattice_tys<'a, 'tcx: 'a, L>( +fn super_lattice_tys<'a, 'tcx: 'a, L>( this: &mut L, a: Ty<'tcx>, b: Ty<'tcx>, @@ -113,3 +116,183 @@ pub fn super_lattice_tys<'a, 'tcx: 'a, L>( _ => infcx.super_combine_tys(this, a, b), } } + +#[derive(Clone, Copy)] +pub(crate) enum LatticeOpKind { + Glb, + Lub, +} + +impl LatticeOpKind { + fn invert(self) -> Self { + match self { + LatticeOpKind::Glb => LatticeOpKind::Lub, + LatticeOpKind::Lub => LatticeOpKind::Glb, + } + } +} + +/// A greatest lower bound" (common subtype) or least upper bound (common supertype). +pub(crate) struct LatticeOp<'combine, 'infcx, 'tcx> { + fields: &'combine mut CombineFields<'infcx, 'tcx>, + kind: LatticeOpKind, +} + +impl<'combine, 'infcx, 'tcx> LatticeOp<'combine, 'infcx, 'tcx> { + pub(crate) fn new( + fields: &'combine mut CombineFields<'infcx, 'tcx>, + kind: LatticeOpKind, + ) -> LatticeOp<'combine, 'infcx, 'tcx> { + LatticeOp { fields, kind } + } +} + +impl<'tcx> TypeRelation> for LatticeOp<'_, '_, 'tcx> { + fn cx(&self) -> TyCtxt<'tcx> { + self.fields.tcx() + } + + fn relate_with_variance>>( + &mut self, + variance: ty::Variance, + _info: ty::VarianceDiagInfo>, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + match variance { + ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b), + ty::Covariant => self.relate(a, b), + // FIXME(#41044) -- not correct, need test + ty::Bivariant => Ok(a), + ty::Contravariant => { + self.kind = self.kind.invert(); + let res = self.relate(a, b); + self.kind = self.kind.invert(); + res + } + } + } + + #[instrument(skip(self), level = "trace")] + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + super_lattice_tys(self, a, b) + } + + #[instrument(skip(self), level = "trace")] + fn regions( + &mut self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); + let mut inner = self.fields.infcx.inner.borrow_mut(); + let mut constraints = inner.unwrap_region_constraints(); + Ok(match self.kind { + // GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8 + LatticeOpKind::Glb => constraints.lub_regions(self.cx(), origin, a, b), + + // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8 + LatticeOpKind::Lub => constraints.glb_regions(self.cx(), origin, a, b), + }) + } + + #[instrument(skip(self), level = "trace")] + fn consts( + &mut self, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { + self.fields.infcx.super_combine_consts(self, a, b) + } + + fn binders( + &mut self, + a: ty::Binder<'tcx, T>, + b: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> + where + T: Relate>, + { + // GLB/LUB of a binder and itself is just itself + if a == b { + return Ok(a); + } + + debug!("binders(a={:?}, b={:?})", a, b); + if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() { + // When higher-ranked types are involved, computing the GLB/LUB is + // very challenging, switch to invariance. This is obviously + // overly conservative but works ok in practice. + self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?; + Ok(a) + } else { + Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) + } + } +} + +impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for LatticeOp<'combine, 'infcx, 'tcx> { + fn infcx(&self) -> &'infcx InferCtxt<'tcx> { + self.fields.infcx + } + + fn cause(&self) -> &ObligationCause<'tcx> { + &self.fields.trace.cause + } + + fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + let mut sub = self.fields.sub(); + match self.kind { + LatticeOpKind::Glb => { + sub.relate(v, a)?; + sub.relate(v, b)?; + } + LatticeOpKind::Lub => { + sub.relate(a, v)?; + sub.relate(b, v)?; + } + } + Ok(()) + } + + fn define_opaque_types(&self) -> DefineOpaqueTypes { + self.fields.define_opaque_types + } +} + +impl<'tcx> PredicateEmittingRelation> for LatticeOp<'_, '_, 'tcx> { + fn span(&self) -> Span { + self.fields.trace.span() + } + + fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { + StructurallyRelateAliases::No + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.fields.param_env + } + + fn register_predicates( + &mut self, + obligations: impl IntoIterator, ty::Predicate<'tcx>>>, + ) { + self.fields.register_predicates(obligations); + } + + fn register_goals( + &mut self, + obligations: impl IntoIterator>>, + ) { + self.fields.register_obligations(obligations); + } + + fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { + self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + // FIXME(deferred_projection_equality): This isn't right, I think? + ty::AliasRelationDirection::Equate, + ))]); + } +} diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs deleted file mode 100644 index 35c7ab5000d..00000000000 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! Least upper bound. See [`lattice`]. - -use rustc_middle::traits::solve::Goal; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::Span; -use tracing::{debug, instrument}; - -use super::StructurallyRelateAliases; -use super::combine::{CombineFields, PredicateEmittingRelation}; -use super::lattice::{self, LatticeDir}; -use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; -use crate::traits::ObligationCause; - -/// "Least upper bound" (common supertype) -pub struct Lub<'combine, 'infcx, 'tcx> { - fields: &'combine mut CombineFields<'infcx, 'tcx>, -} - -impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'tcx>) -> Lub<'combine, 'infcx, 'tcx> { - Lub { fields } - } -} - -impl<'tcx> TypeRelation> for Lub<'_, '_, 'tcx> { - fn cx(&self) -> TyCtxt<'tcx> { - self.fields.tcx() - } - - fn relate_with_variance>>( - &mut self, - variance: ty::Variance, - _info: ty::VarianceDiagInfo>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - match variance { - ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b), - ty::Covariant => self.relate(a, b), - // FIXME(#41044) -- not correct, need test - ty::Bivariant => Ok(a), - ty::Contravariant => self.fields.glb().relate(a, b), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - lattice::super_lattice_tys(self, a, b) - } - - #[instrument(skip(self), level = "trace")] - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone())); - // LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8 - Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions( - self.cx(), - origin, - a, - b, - )) - } - - #[instrument(skip(self), level = "trace")] - fn consts( - &mut self, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - self.fields.infcx.super_combine_consts(self, a, b) - } - - fn binders( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate>, - { - // LUB of a binder and itself is just itself - if a == b { - return Ok(a); - } - - debug!("binders(a={:?}, b={:?})", a, b); - if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() { - // When higher-ranked types are involved, computing the LUB is - // very challenging, switch to invariance. This is obviously - // overly conservative but works ok in practice. - self.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b)?; - Ok(a) - } else { - Ok(ty::Binder::dummy(self.relate(a.skip_binder(), b.skip_binder())?)) - } - } -} - -impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> { - fn infcx(&self) -> &'infcx InferCtxt<'tcx> { - self.fields.infcx - } - - fn cause(&self) -> &ObligationCause<'tcx> { - &self.fields.trace.cause - } - - fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(); - sub.relate(a, v)?; - sub.relate(b, v)?; - Ok(()) - } - - fn define_opaque_types(&self) -> DefineOpaqueTypes { - self.fields.define_opaque_types - } -} - -impl<'tcx> PredicateEmittingRelation> for Lub<'_, '_, 'tcx> { - fn span(&self) -> Span { - self.fields.trace.span() - } - - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - StructurallyRelateAliases::No - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.fields.param_env - } - - fn register_predicates( - &mut self, - obligations: impl IntoIterator, ty::Predicate<'tcx>>>, - ) { - self.fields.register_predicates(obligations); - } - - fn register_goals( - &mut self, - obligations: impl IntoIterator>>, - ) { - self.fields.register_obligations(obligations) - } - - fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) { - self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - // FIXME(deferred_projection_equality): This isn't right, I think? - ty::AliasRelationDirection::Equate, - ))]); - } -} diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index 183ea5b3309..edc0c4f078a 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -10,8 +10,6 @@ #[allow(hidden_glob_reexports)] pub(super) mod combine; mod generalize; -mod glb; mod higher_ranked; mod lattice; -mod lub; mod type_relating;