diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 8da4d80badfec..47f2b3a38ef43 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -134,6 +134,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { self.type_checker.infcx.instantiate_ty_var( self, + StructurallyRelateAliases::No, opaque_is_expected, ty_vid, variance, @@ -353,9 +354,14 @@ impl<'bccx, 'tcx> TypeRelation> for NllTypeRelating<'_, 'bccx, 'tcx ); } - (&ty::Infer(ty::TyVar(a_vid)), _) => { - infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)? - } + (&ty::Infer(ty::TyVar(a_vid)), _) => infcx.instantiate_ty_var( + self, + StructurallyRelateAliases::No, + true, + a_vid, + self.ambient_variance, + b, + )?, ( &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }), @@ -524,10 +530,6 @@ impl<'bccx, 'tcx> PredicateEmittingRelation> for NllTypeRelating self.locations.span(self.type_checker.body) } - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - StructurallyRelateAliases::No - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.type_checker.param_env } diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 9f6a17638664e..f53e179208ba2 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -29,7 +29,7 @@ use rustc_middle::bug; use rustc_middle::ty::{Const, ImplSubject}; use super::*; -use crate::infer::relate::{Relate, StructurallyRelateAliases, TypeRelation}; +use crate::infer::relate::{Relate, TypeRelation}; use crate::traits::Obligation; /// Whether we should define opaque types or just treat them opaquely. @@ -160,7 +160,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { self.param_env, define_opaque_types, ); - fields.equate(StructurallyRelateAliases::No).relate(expected, actual)?; + fields.equate().relate(expected, actual)?; Ok(InferOk { value: (), obligations: fields @@ -178,28 +178,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { }) } - /// Equates `expected` and `found` while structurally relating aliases. - /// This should only be used inside of the next generation trait solver - /// when relating rigid aliases. - pub fn eq_structurally_relating_aliases( - self, - expected: T, - actual: T, - ) -> InferResult<'tcx, ()> - where - T: ToTrace<'tcx>, - { - assert!(self.infcx.next_trait_solver()); - let mut fields = CombineFields::new( - self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), - self.param_env, - DefineOpaqueTypes::Yes, - ); - fields.equate(StructurallyRelateAliases::Yes).relate(expected, actual)?; - Ok(InferOk { value: (), obligations: fields.into_obligations() }) - } - pub fn relate( self, define_opaque_types: DefineOpaqueTypes, @@ -249,25 +227,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { Ok(fields.goals) } - /// Used in the new solver since we don't care about tracking an `ObligationCause`. - pub fn eq_structurally_relating_aliases_no_trace( - self, - expected: T, - actual: T, - ) -> Result>>, NoSolution> - where - T: Relate>, - { - let mut fields = CombineFields::new( - self.infcx, - TypeTrace::dummy(self.cause), - self.param_env, - DefineOpaqueTypes::Yes, - ); - fields.equate(StructurallyRelateAliases::Yes).relate(expected, actual)?; - Ok(fields.goals) - } - /// Computes the least-upper-bound, or mutual supertype, of two /// values. The order of the arguments doesn't matter, but since /// this can result in an error (e.g., if asked to compute LUB of diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index f35a8162d96f1..db5baca3d8787 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -1,14 +1,17 @@ ///! Definition of `InferCtxtLike` from the librarified type layer. use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::traits::solve::{Goal, NoSolution, SolverMode}; +use rustc_middle::infer::unify_key::EffectVarValue; +use rustc_middle::traits::solve::SolverMode; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::DUMMY_SP; -use rustc_type_ir::relate::Relate; +use rustc_span::{ErrorGuaranteed, DUMMY_SP}; +use rustc_type_ir::relate::combine::PredicateEmittingRelation; +use rustc_type_ir::relate::StructurallyRelateAliases; use rustc_type_ir::InferCtxtLike; use super::{BoundRegionConversionTime, InferCtxt, SubregionOrigin}; +use crate::infer::RelateResult; impl<'tcx> InferCtxtLike for InferCtxt<'tcx> { type Interner = TyCtxt<'tcx>; @@ -131,30 +134,14 @@ impl<'tcx> InferCtxtLike for InferCtxt<'tcx> { self.enter_forall(value, f) } - fn relate>>( - &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) - } - - fn eq_structurally_relating_aliases>>( - &self, - param_env: ty::ParamEnv<'tcx>, - lhs: T, - rhs: T, - ) -> Result>>, NoSolution> { - self.at(&ObligationCause::dummy(), param_env) - .eq_structurally_relating_aliases_no_trace(lhs, rhs) - } - fn shallow_resolve(&self, ty: Ty<'tcx>) -> Ty<'tcx> { self.shallow_resolve(ty) } + fn shallow_resolve_const(&self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + self.shallow_resolve_const(ct) + } + fn resolve_vars_if_possible(&self, value: T) -> T where T: TypeFoldable>, @@ -167,10 +154,105 @@ impl<'tcx> InferCtxtLike for InferCtxt<'tcx> { } fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>) { - self.sub_regions(SubregionOrigin::RelateRegionParamBound(DUMMY_SP), sub, sup) + self.inner.borrow_mut().unwrap_region_constraints().make_subregion( + SubregionOrigin::RelateRegionParamBound(DUMMY_SP), + sub, + sup, + ); + } + + fn equate_regions(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) { + self.inner.borrow_mut().unwrap_region_constraints().make_eqregion( + SubregionOrigin::RelateRegionParamBound(DUMMY_SP), + a, + b, + ); } fn register_ty_outlives(&self, ty: Ty<'tcx>, r: ty::Region<'tcx>) { self.register_region_obligation_with_cause(ty, r, &ObligationCause::dummy()); } + + fn equate_ty_vids_raw(&self, a: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) { + self.inner.borrow_mut().type_variables().equate(a, b); + } + + fn equate_int_vids_raw(&self, a: rustc_type_ir::IntVid, b: rustc_type_ir::IntVid) { + self.inner.borrow_mut().int_unification_table().union(a, b); + } + + fn equate_float_vids_raw(&self, a: rustc_type_ir::FloatVid, b: rustc_type_ir::FloatVid) { + self.inner.borrow_mut().float_unification_table().union(a, b); + } + + fn equate_const_vids_raw(&self, a: rustc_type_ir::ConstVid, b: rustc_type_ir::ConstVid) { + self.inner.borrow_mut().const_unification_table().union(a, b); + } + + fn equate_effect_vids_raw(&self, a: rustc_type_ir::EffectVid, b: rustc_type_ir::EffectVid) { + self.inner.borrow_mut().effect_unification_table().union(a, b); + } + + fn instantiate_ty_var_raw>( + &self, + relation: &mut R, + structurally_relate_aliases: StructurallyRelateAliases, + target_is_expected: bool, + target_vid: rustc_type_ir::TyVid, + instantiation_variance: rustc_type_ir::Variance, + source_ty: Ty<'tcx>, + ) -> RelateResult<'tcx, ()> { + self.instantiate_ty_var( + relation, + structurally_relate_aliases, + target_is_expected, + target_vid, + instantiation_variance, + source_ty, + ) + } + + fn instantiate_int_var_raw( + &self, + vid: rustc_type_ir::IntVid, + value: rustc_type_ir::IntVarValue, + ) { + self.inner.borrow_mut().int_unification_table().union_value(vid, value); + } + + fn instantiate_float_var_raw( + &self, + vid: rustc_type_ir::FloatVid, + value: rustc_type_ir::FloatVarValue, + ) { + self.inner.borrow_mut().float_unification_table().union_value(vid, value); + } + + fn instantiate_effect_var_raw(&self, vid: rustc_type_ir::EffectVid, value: ty::Const<'tcx>) { + self.inner + .borrow_mut() + .effect_unification_table() + .union_value(vid, EffectVarValue::Known(value)); + } + + fn instantiate_const_var_raw>( + &self, + relation: &mut R, + structurally_relate_aliases: StructurallyRelateAliases, + target_is_expected: bool, + target_vid: rustc_type_ir::ConstVid, + source_ct: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ()> { + self.instantiate_const_var( + relation, + structurally_relate_aliases, + target_is_expected, + target_vid, + source_ct, + ) + } + + fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { + self.set_tainted_by_errors(e) + } } diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 5751ce466d982..4cc8a2bfbe312 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -1,7 +1,7 @@ //! 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 +//! Each implements the trait [`TypeRelation`](super::TypeRelation) and contains methods for //! combining two instances of various things and yielding a new instance. //! These combiner methods always yield a `Result`. To relate two //! types, you can use `infcx.at(cause, param_env)` which then allows @@ -134,15 +134,8 @@ impl<'tcx> InferCtxt<'tcx> { } (_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => { - match relation.structurally_relate_aliases() { - StructurallyRelateAliases::Yes => { - relate::structurally_relate_tys(relation, a, b) - } - StructurallyRelateAliases::No => { - relation.register_alias_relate_predicate(a, b); - Ok(a) - } - } + relation.register_alias_relate_predicate(a, b); + Ok(a) } // All other cases of inference are errors @@ -215,12 +208,12 @@ impl<'tcx> InferCtxt<'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - self.instantiate_const_var(relation, true, vid, b)?; + self.instantiate_const_var(relation, StructurallyRelateAliases::No, true, vid, b)?; Ok(b) } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - self.instantiate_const_var(relation, false, vid, a)?; + self.instantiate_const_var(relation, StructurallyRelateAliases::No, false, vid, a)?; Ok(a) } @@ -235,24 +228,17 @@ impl<'tcx> InferCtxt<'tcx> { (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) if self.tcx.features().generic_const_exprs || self.next_trait_solver() => { - match relation.structurally_relate_aliases() { - StructurallyRelateAliases::No => { - relation.register_predicates([if self.next_trait_solver() { - ty::PredicateKind::AliasRelate( - a.into(), - b.into(), - ty::AliasRelationDirection::Equate, - ) - } else { - ty::PredicateKind::ConstEquate(a, b) - }]); - - Ok(b) - } - StructurallyRelateAliases::Yes => { - relate::structurally_relate_consts(relation, a, b) - } - } + relation.register_predicates([if self.next_trait_solver() { + ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Equate, + ) + } else { + ty::PredicateKind::ConstEquate(a, b) + }]); + + Ok(b) } _ => relate::structurally_relate_consts(relation, a, b), } @@ -282,19 +268,16 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.infcx.tcx } - pub fn equate<'a>( - &'a mut self, - structurally_relate_aliases: StructurallyRelateAliases, - ) -> TypeRelating<'a, 'infcx, 'tcx> { - TypeRelating::new(self, structurally_relate_aliases, ty::Invariant) + pub fn equate<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> { + TypeRelating::new(self, ty::Invariant) } pub fn sub<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> { - TypeRelating::new(self, StructurallyRelateAliases::No, ty::Covariant) + TypeRelating::new(self, ty::Covariant) } pub fn sup<'a>(&'a mut self) -> TypeRelating<'a, 'infcx, 'tcx> { - TypeRelating::new(self, StructurallyRelateAliases::No, ty::Contravariant) + TypeRelating::new(self, ty::Contravariant) } pub fn lub<'a>(&'a mut self) -> Lub<'a, 'infcx, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 542104fa10ba0..e26d54482c4cd 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -35,6 +35,7 @@ impl<'tcx> InferCtxt<'tcx> { pub fn instantiate_ty_var>>( &self, relation: &mut R, + structurally_relate_aliases: StructurallyRelateAliases, target_is_expected: bool, target_vid: ty::TyVid, instantiation_variance: ty::Variance, @@ -53,7 +54,7 @@ impl<'tcx> InferCtxt<'tcx> { let Generalization { value_may_be_infer: generalized_ty, has_unconstrained_ty_var } = self .generalize( relation.span(), - relation.structurally_relate_aliases(), + structurally_relate_aliases, target_vid, instantiation_variance, source_ty, @@ -180,9 +181,10 @@ impl<'tcx> InferCtxt<'tcx> { /// /// See `tests/ui/const-generics/occurs-check/` for more examples where this is relevant. #[instrument(level = "debug", skip(self, relation))] - pub(super) fn instantiate_const_var>>( + pub(crate) fn instantiate_const_var>>( &self, relation: &mut R, + structurally_relate_aliases: StructurallyRelateAliases, target_is_expected: bool, target_vid: ty::ConstVid, source_ct: ty::Const<'tcx>, @@ -192,7 +194,7 @@ impl<'tcx> InferCtxt<'tcx> { let Generalization { value_may_be_infer: generalized_ct, has_unconstrained_ty_var } = self .generalize( relation.span(), - relation.structurally_relate_aliases(), + structurally_relate_aliases, target_vid, ty::Invariant, source_ct, diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index 4f2cf2c43e7cc..3cab99e28c915 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -7,7 +7,6 @@ use rustc_span::Span; use super::combine::{CombineFields, PredicateEmittingRelation}; use super::lattice::{self, LatticeDir}; -use super::StructurallyRelateAliases; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::ObligationCause; @@ -35,7 +34,7 @@ impl<'tcx> TypeRelation> for Glb<'_, '_, 'tcx> { b: T, ) -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b), + ty::Invariant => self.fields.equate().relate(a, b), ty::Covariant => self.relate(a, b), // FIXME(#41044) -- not correct, need test ty::Bivariant => Ok(a), @@ -125,10 +124,6 @@ impl<'tcx> PredicateEmittingRelation> for Glb<'_, '_, 'tcx> { self.fields.trace.span() } - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - StructurallyRelateAliases::No - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index 046e93b63e4cb..faa3430879867 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -7,7 +7,6 @@ use rustc_span::Span; use super::combine::{CombineFields, PredicateEmittingRelation}; use super::lattice::{self, LatticeDir}; -use super::StructurallyRelateAliases; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::ObligationCause; @@ -35,7 +34,7 @@ impl<'tcx> TypeRelation> for Lub<'_, '_, 'tcx> { b: T, ) -> RelateResult<'tcx, T> { match variance { - ty::Invariant => self.fields.equate(StructurallyRelateAliases::No).relate(a, b), + ty::Invariant => self.fields.equate().relate(a, b), ty::Covariant => self.relate(a, b), // FIXME(#41044) -- not correct, need test ty::Bivariant => Ok(a), @@ -124,10 +123,6 @@ impl<'tcx> PredicateEmittingRelation> for Lub<'_, '_, 'tcx> { self.fields.trace.span() } - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - StructurallyRelateAliases::No - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { self.fields.param_env } diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index ec600c60b240b..49472612da85f 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -13,17 +13,15 @@ use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; /// Enforce that `a` is equal to or a subtype of `b`. pub struct TypeRelating<'combine, 'a, 'tcx> { fields: &'combine mut CombineFields<'a, 'tcx>, - structurally_relate_aliases: StructurallyRelateAliases, ambient_variance: ty::Variance, } impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> { pub fn new( f: &'combine mut CombineFields<'infcx, 'tcx>, - structurally_relate_aliases: StructurallyRelateAliases, ambient_variance: ty::Variance, ) -> TypeRelating<'combine, 'infcx, 'tcx> { - TypeRelating { fields: f, structurally_relate_aliases, ambient_variance } + TypeRelating { fields: f, ambient_variance } } } @@ -116,11 +114,19 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { } (&ty::Infer(TyVar(a_vid)), _) => { - infcx.instantiate_ty_var(self, true, a_vid, self.ambient_variance, b)?; + infcx.instantiate_ty_var( + self, + StructurallyRelateAliases::No, + true, + a_vid, + self.ambient_variance, + b, + )?; } (_, &ty::Infer(TyVar(b_vid))) => { infcx.instantiate_ty_var( self, + StructurallyRelateAliases::No, false, b_vid, self.ambient_variance.xform(ty::Contravariant), @@ -302,10 +308,6 @@ impl<'tcx> PredicateEmittingRelation> for TypeRelating<'_, '_, ' self.fields.param_env } - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases { - self.structurally_relate_aliases - } - fn register_predicates( &mut self, obligations: impl IntoIterator, ty::Predicate<'tcx>>>, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8f8fd09c9e4d9..ea5986debb98e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -703,6 +703,12 @@ impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_featu } } +impl<'tcx> rustc_type_ir::inherent::Span> for Span { + fn dummy() -> Self { + DUMMY_SP + } +} + type InternedSet<'tcx, T> = ShardedHashMap, ()>; pub struct CtxtInterners<'tcx> { diff --git a/compiler/rustc_next_trait_solver/src/relate.rs b/compiler/rustc_next_trait_solver/src/relate.rs index db819961bbd75..713903cfc8156 100644 --- a/compiler/rustc_next_trait_solver/src/relate.rs +++ b/compiler/rustc_next_trait_solver/src/relate.rs @@ -1,15 +1,504 @@ +use rustc_type_ir::error::{ExpectedFound, TypeError}; +use rustc_type_ir::inherent::*; pub use rustc_type_ir::relate::*; +use rustc_type_ir::solve::{Goal, NoSolution}; +use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; +use tracing::{debug, instrument}; -pub mod combine; - -/// Whether aliases should be related structurally or not. Used -/// to adjust the behavior of generalization and combine. -/// -/// This should always be `No` unless in a few special-cases when -/// instantiating canonical responses and in the new solver. Each -/// such case should have a comment explaining why it is used. -#[derive(Debug, Copy, Clone)] -pub enum StructurallyRelateAliases { - Yes, - No, +use self::combine::PredicateEmittingRelation; + +pub trait RelateExt: InferCtxtLike { + fn relate>( + &self, + param_env: ::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result::Predicate>>, NoSolution>; + + fn eq_structurally_relating_aliases>( + &self, + param_env: ::ParamEnv, + lhs: T, + rhs: T, + ) -> Result::Predicate>>, NoSolution>; +} + +impl RelateExt for Infcx { + fn relate>( + &self, + param_env: ::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result::Predicate>>, NoSolution> + { + let mut relate = + SolverRelating::new(self, StructurallyRelateAliases::No, variance, param_env); + relate.relate(lhs, rhs)?; + Ok(relate.goals) + } + + fn eq_structurally_relating_aliases>( + &self, + param_env: ::ParamEnv, + lhs: T, + rhs: T, + ) -> Result::Predicate>>, NoSolution> + { + let mut relate = + SolverRelating::new(self, StructurallyRelateAliases::Yes, ty::Invariant, param_env); + relate.relate(lhs, rhs)?; + Ok(relate.goals) + } +} + +#[allow(unused)] +/// Enforce that `a` is equal to or a subtype of `b`. +pub struct SolverRelating<'infcx, Infcx, I: Interner> { + infcx: &'infcx Infcx, + structurally_relate_aliases: StructurallyRelateAliases, + ambient_variance: ty::Variance, + param_env: I::ParamEnv, + goals: Vec>, +} + +impl<'infcx, Infcx, I> SolverRelating<'infcx, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + fn new( + infcx: &'infcx Infcx, + structurally_relate_aliases: StructurallyRelateAliases, + ambient_variance: ty::Variance, + param_env: I::ParamEnv, + ) -> Self { + SolverRelating { + infcx, + structurally_relate_aliases, + ambient_variance, + param_env, + goals: vec![], + } + } +} + +impl TypeRelation for SolverRelating<'_, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + fn cx(&self) -> I { + self.infcx.cx() + } + + fn relate_item_args( + &mut self, + item_def_id: I::DefId, + a_arg: I::GenericArgs, + b_arg: I::GenericArgs, + ) -> RelateResult { + if self.ambient_variance == ty::Invariant { + // Avoid fetching the variance if we are in an invariant + // context; no need, and it can induce dependency cycles + // (e.g., #41849). + relate_args_invariantly(self, a_arg, b_arg) + } else { + let tcx = self.cx(); + let opt_variances = tcx.variances_of(item_def_id); + relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, false) + } + } + + fn relate_with_variance>( + &mut self, + variance: ty::Variance, + _info: VarianceDiagInfo, + a: T, + b: T, + ) -> RelateResult { + let old_ambient_variance = self.ambient_variance; + self.ambient_variance = self.ambient_variance.xform(variance); + debug!(?self.ambient_variance, "new ambient variance"); + + let r = if self.ambient_variance == ty::Bivariant { Ok(a) } else { self.relate(a, b) }; + + self.ambient_variance = old_ambient_variance; + r + } + + #[instrument(skip(self), level = "trace")] + fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult { + if a == b { + return Ok(a); + } + + let infcx = self.infcx; + let a = infcx.shallow_resolve(a); + let b = infcx.shallow_resolve(b); + + match (a.kind(), b.kind()) { + (ty::Infer(ty::TyVar(a_id)), ty::Infer(ty::TyVar(b_id))) => { + match self.ambient_variance { + ty::Covariant => { + // can't make progress on `A <: B` if both A and B are + // type variables, so record an obligation. + self.goals.push(Goal::new( + self.cx(), + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { + a_is_expected: true, + a, + b, + })), + )); + } + ty::Contravariant => { + // can't make progress on `B <: A` if both A and B are + // type variables, so record an obligation. + self.goals.push(Goal::new( + self.cx(), + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate { + a_is_expected: false, + a: b, + b: a, + })), + )); + } + ty::Invariant => { + infcx.equate_ty_vids_raw(a_id, b_id); + } + ty::Bivariant => { + unreachable!("Expected bivariance to be handled in relate_with_variance") + } + } + Ok(a) + } + + (ty::Infer(ty::TyVar(a_vid)), _) => { + infcx.instantiate_ty_var_raw( + self, + self.structurally_relate_aliases, + true, + a_vid, + self.ambient_variance, + b, + )?; + Ok(a) + } + (_, ty::Infer(ty::TyVar(b_vid))) => { + infcx.instantiate_ty_var_raw( + self, + self.structurally_relate_aliases, + false, + b_vid, + self.ambient_variance.xform(ty::Contravariant), + a, + )?; + Ok(a) + } + + (ty::Error(e), _) | (_, ty::Error(e)) => { + infcx.set_tainted_by_errors(e); + Ok(Ty::new_error(self.cx(), e)) + } + + // Relate integral variables to other types + (ty::Infer(ty::IntVar(a_id)), ty::Infer(ty::IntVar(b_id))) => { + infcx.equate_int_vids_raw(a_id, b_id); + Ok(a) + } + (ty::Infer(ty::IntVar(v_id)), ty::Int(v)) => { + infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v)); + Ok(a) + } + (ty::Int(v), ty::Infer(ty::IntVar(v_id))) => { + infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::IntType(v)); + Ok(a) + } + (ty::Infer(ty::IntVar(v_id)), ty::Uint(v)) => { + infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v)); + Ok(a) + } + (ty::Uint(v), ty::Infer(ty::IntVar(v_id))) => { + infcx.instantiate_int_var_raw(v_id, ty::IntVarValue::UintType(v)); + Ok(a) + } + + // Relate floating-point variables to other types + (ty::Infer(ty::FloatVar(a_id)), ty::Infer(ty::FloatVar(b_id))) => { + infcx.equate_float_vids_raw(a_id, b_id); + Ok(a) + } + (ty::Infer(ty::FloatVar(v_id)), ty::Float(v)) => { + infcx.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v)); + Ok(a) + } + (ty::Float(v), ty::Infer(ty::FloatVar(v_id))) => { + infcx.instantiate_float_var_raw(v_id, ty::FloatVarValue::Known(v)); + Ok(a) + } + + (_, ty::Alias(..)) | (ty::Alias(..), _) => match self.structurally_relate_aliases { + StructurallyRelateAliases::Yes => structurally_relate_tys(self, a, b), + StructurallyRelateAliases::No => { + self.register_alias_relate_predicate(a, b); + Ok(a) + } + }, + + // All other cases of inference are errors + (ty::Infer(_), _) | (_, ty::Infer(_)) => { + Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) + } + + _ => structurally_relate_tys(self, a, b), + } + } + + #[instrument(skip(self), level = "trace")] + fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult { + match self.ambient_variance { + // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a) + ty::Covariant => { + self.infcx.sub_regions(b, a); + } + // Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b) + ty::Contravariant => { + self.infcx.sub_regions(a, b); + } + ty::Invariant => { + self.infcx.equate_regions(a, b); + } + ty::Bivariant => { + unreachable!("Expected bivariance to be handled in relate_with_variance") + } + } + + Ok(a) + } + + #[instrument(skip(self), level = "trace")] + fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult { + if a == b { + return Ok(a); + } + + let infcx = self.infcx; + let a = infcx.shallow_resolve_const(a); + let b = infcx.shallow_resolve_const(b); + + match (a.kind(), b.kind()) { + ( + ty::ConstKind::Infer(ty::InferConst::Var(a_vid)), + ty::ConstKind::Infer(ty::InferConst::Var(b_vid)), + ) => { + infcx.equate_const_vids_raw(a_vid, b_vid); + Ok(a) + } + + ( + ty::ConstKind::Infer(ty::InferConst::EffectVar(a_vid)), + ty::ConstKind::Infer(ty::InferConst::EffectVar(b_vid)), + ) => { + infcx.equate_effect_vids_raw(a_vid, b_vid); + Ok(a) + } + + // All other cases of inference with other variables are errors. + ( + ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)), + ty::ConstKind::Infer(_), + ) + | ( + ty::ConstKind::Infer(_), + ty::ConstKind::Infer(ty::InferConst::Var(_) | ty::InferConst::EffectVar(_)), + ) => { + panic!( + "tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var): {a:?} and {b:?}" + ) + } + + (ty::ConstKind::Infer(ty::InferConst::Var(vid)), _) => { + infcx.instantiate_const_var_raw( + self, + self.structurally_relate_aliases, + true, + vid, + b, + )?; + Ok(b) + } + + (_, ty::ConstKind::Infer(ty::InferConst::Var(vid))) => { + infcx.instantiate_const_var_raw( + self, + self.structurally_relate_aliases, + false, + vid, + a, + )?; + Ok(a) + } + + (ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)), _) => { + infcx.instantiate_effect_var_raw(vid, b); + Ok(a) + } + + (_, ty::ConstKind::Infer(ty::InferConst::EffectVar(vid))) => { + infcx.instantiate_effect_var_raw(vid, a); + Ok(a) + } + + (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) => { + match self.structurally_relate_aliases { + StructurallyRelateAliases::No => { + self.register_predicates([ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Equate, + )]); + + Ok(b) + } + StructurallyRelateAliases::Yes => structurally_relate_consts(self, a, b), + } + } + + _ => structurally_relate_consts(self, a, b), + } + } + + fn binders( + &mut self, + a: ty::Binder, + b: ty::Binder, + ) -> RelateResult> + where + T: Relate, + { + // If they're equal, then short-circuit. + if a == b { + return Ok(a); + } + + // If they have no bound vars, relate normally. + if let Some(a_inner) = a.no_bound_vars() { + if let Some(b_inner) = b.no_bound_vars() { + self.relate(a_inner, b_inner)?; + return Ok(a); + } + }; + + match self.ambient_variance { + // Checks whether `for<..> sub <: for<..> sup` holds. + // + // For this to hold, **all** instantiations of the super type + // have to be a super type of **at least one** instantiation of + // the subtype. + // + // This is implemented by first entering a new universe. + // We then replace all bound variables in `sup` with placeholders, + // and all bound variables in `sub` with inference vars. + // We can then just relate the two resulting types as normal. + // + // Note: this is a subtle algorithm. For a full explanation, please see + // the [rustc dev guide][rd] + // + // [rd]: https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference/placeholders_and_universes.html + ty::Covariant => { + self.infcx.enter_forall(b, |b| { + let a = self.infcx.instantiate_binder_with_infer(a); + self.relate(a, b) + })?; + } + ty::Contravariant => { + self.infcx.enter_forall(a, |a| { + let b = self.infcx.instantiate_binder_with_infer(b); + self.relate(a, b) + })?; + } + + // When **equating** binders, we check that there is a 1-to-1 + // correspondence between the bound vars in both types. + // + // We do so by separately instantiating one of the binders with + // placeholders and the other with inference variables and then + // equating the instantiated types. + // + // We want `for<..> A == for<..> B` -- therefore we want + // `exists<..> A == for<..> B` and `exists<..> B == for<..> A`. + // Check if `exists<..> A == for<..> B` + ty::Invariant => { + self.infcx.enter_forall(b, |b| { + let a = self.infcx.instantiate_binder_with_infer(a); + self.relate(a, b) + })?; + + // Check if `exists<..> B == for<..> A`. + self.infcx.enter_forall(a, |a| { + let b = self.infcx.instantiate_binder_with_infer(b); + self.relate(a, b) + })?; + } + ty::Bivariant => { + unreachable!("Expected bivariance to be handled in relate_with_variance") + } + } + Ok(a) + } +} + +impl PredicateEmittingRelation for SolverRelating<'_, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + fn span(&self) -> I::Span { + Span::dummy() + } + + fn param_env(&self) -> I::ParamEnv { + self.param_env + } + + fn register_predicates( + &mut self, + obligations: impl IntoIterator>, + ) { + self.goals.extend( + obligations.into_iter().map(|pred| Goal::new(self.infcx.cx(), self.param_env, pred)), + ); + } + + fn register_goals(&mut self, obligations: impl IntoIterator>) { + self.goals.extend(obligations); + } + + fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty) { + self.register_predicates([ty::Binder::dummy(match self.ambient_variance { + ty::Covariant => ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Subtype, + ), + // a :> b is b <: a + ty::Contravariant => ty::PredicateKind::AliasRelate( + b.into(), + a.into(), + ty::AliasRelationDirection::Subtype, + ), + ty::Invariant => ty::PredicateKind::AliasRelate( + a.into(), + b.into(), + ty::AliasRelationDirection::Equate, + ), + ty::Bivariant => { + unreachable!("Expected bivariance to be handled in relate_with_variance") + } + })]); + } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 2e521ddcec322..75c20711dc4c2 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -19,6 +19,7 @@ use tracing::{instrument, trace}; use crate::canonicalizer::{CanonicalizeMode, Canonicalizer}; use crate::delegate::SolverDelegate; +use crate::relate::RelateExt; use crate::resolve::EagerResolver; use crate::solve::eval_ctxt::NestedGoals; use crate::solve::{ diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index e328284c0010f..1af6d84f914df 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -14,6 +14,7 @@ use tracing::{instrument, trace}; use crate::coherence; use crate::delegate::SolverDelegate; +use crate::relate::RelateExt; use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ @@ -792,7 +793,7 @@ where let ctor_term = rigid_ctor.to_term(cx); let obligations = self.delegate.eq_structurally_relating_aliases(param_env, term, ctor_term)?; - debug_assert!(obligations.is_empty()); + debug_assert!(obligations.is_empty(), "{obligations:#?}"); self.relate(param_env, alias, variance, rigid_ctor) } else { Err(NoSolution) diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 1d0b2345b805f..7d895ef0af123 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -1,6 +1,7 @@ use crate::fold::TypeFoldable; -use crate::relate::Relate; -use crate::solve::{Goal, NoSolution, SolverMode}; +use crate::relate::combine::PredicateEmittingRelation; +use crate::relate::{RelateResult, StructurallyRelateAliases}; +use crate::solve::SolverMode; use crate::{self as ty, Interner}; pub trait InferCtxtLike: Sized { @@ -58,25 +59,47 @@ pub trait InferCtxtLike: Sized { f: impl FnOnce(T) -> U, ) -> U; - fn relate>( - &self, - param_env: ::ParamEnv, - lhs: T, - variance: ty::Variance, - rhs: T, - ) -> Result::Predicate>>, NoSolution>; + fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid); + fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid); + fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid); + fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid); + fn equate_effect_vids_raw(&self, a: ty::EffectVid, b: ty::EffectVid); - fn eq_structurally_relating_aliases>( + fn instantiate_ty_var_raw>( + &self, + relation: &mut R, + structurally_relate_aliases: StructurallyRelateAliases, + target_is_expected: bool, + target_vid: ty::TyVid, + instantiation_variance: ty::Variance, + source_ty: ::Ty, + ) -> RelateResult; + fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue); + fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue); + fn instantiate_effect_var_raw( + &self, + vid: ty::EffectVid, + value: ::Const, + ); + fn instantiate_const_var_raw>( &self, - param_env: ::ParamEnv, - lhs: T, - rhs: T, - ) -> Result::Predicate>>, NoSolution>; + relation: &mut R, + structurally_relate_aliases: StructurallyRelateAliases, + target_is_expected: bool, + target_vid: ty::ConstVid, + source_ct: ::Const, + ) -> RelateResult; + + fn set_tainted_by_errors(&self, e: ::ErrorGuaranteed); fn shallow_resolve( &self, ty: ::Ty, ) -> ::Ty; + fn shallow_resolve_const( + &self, + ty: ::Const, + ) -> ::Const; fn resolve_vars_if_possible(&self, value: T) -> T where @@ -90,6 +113,12 @@ pub trait InferCtxtLike: Sized { sup: ::Region, ); + fn equate_regions( + &self, + a: ::Region, + b: ::Region, + ); + fn register_ty_outlives( &self, ty: ::Ty, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 263ba676427c5..ddd462b083b1c 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -561,6 +561,10 @@ pub trait BoundExistentialPredicates: ) -> impl IntoIterator>>; } +pub trait Span: Copy + Debug + Hash + Eq + TypeFoldable { + fn dummy() -> Self; +} + pub trait SliceLike: Sized + Copy { type Item: Copy; type IntoIter: Iterator; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index c251540c0fc29..9a889ea9333f8 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -37,7 +37,7 @@ pub trait Interner: { type DefId: DefId; type LocalDefId: Copy + Debug + Hash + Eq + Into + TypeFoldable; - type Span: Copy + Debug + Hash + Eq + TypeFoldable; + type Span: Span; type GenericArgs: GenericArgs; type GenericArgsSlice: Copy + Debug + Hash + Eq + SliceLike; diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 9fd3534d1fa6b..ed26560bf3acb 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -9,6 +9,20 @@ use crate::fold::TypeFoldable; use crate::inherent::*; use crate::{self as ty, Interner}; +pub mod combine; + +/// Whether aliases should be related structurally or not. Used +/// to adjust the behavior of generalization and combine. +/// +/// This should always be `No` unless in a few special-cases when +/// instantiating canonical responses and in the new solver. Each +/// such case should have a comment explaining why it is used. +#[derive(Debug, Copy, Clone)] +pub enum StructurallyRelateAliases { + Yes, + No, +} + pub type RelateResult = Result>; /// Extra information about why we ended up with a particular variance. diff --git a/compiler/rustc_next_trait_solver/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs similarity index 64% rename from compiler/rustc_next_trait_solver/src/relate/combine.rs rename to compiler/rustc_type_ir/src/relate/combine.rs index 96968327d8ee3..23e4d988b1caf 100644 --- a/compiler/rustc_next_trait_solver/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -1,8 +1,6 @@ -pub use rustc_type_ir::relate::*; -use rustc_type_ir::solve::Goal; -use rustc_type_ir::{InferCtxtLike, Interner, Upcast}; - -use super::StructurallyRelateAliases; +use super::TypeRelation; +use crate::solve::Goal; +use crate::{InferCtxtLike, Interner, Upcast}; pub trait PredicateEmittingRelation::Interner>: TypeRelation @@ -14,11 +12,6 @@ where fn param_env(&self) -> I::ParamEnv; - /// Whether aliases should be related structurally. This is pretty much - /// always `No` unless you're equating in some specific locations of the - /// new solver. See the comments in these use-cases for more details. - fn structurally_relate_aliases(&self) -> StructurallyRelateAliases; - /// Register obligations that must hold in order for this relation to hold fn register_goals(&mut self, obligations: impl IntoIterator>);