diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 152a7674490c7..e2d684e12a816 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -616,9 +616,4 @@ impl<'b, 'tcx> PredicateEmittingRelation> for NllTypeRelating<'_ } })]); } - - fn try_eagerly_normalize_alias(&mut self, _alias: ty::AliasTy<'tcx>) -> Ty<'tcx> { - // Past hir typeck, so we don't have to worry about type inference anymore. - self.type_checker.infcx.next_ty_var(self.span()) - } } diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 3487286d58830..70e3d7dc9fef0 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -140,9 +140,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { ty::Contravariant, actual, self.cause.span, - &mut |alias| { - self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias) - }, ) .map(|goals| self.goals_to_obligations(goals)) } else { @@ -176,9 +173,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { ty::Covariant, actual, self.cause.span, - &mut |alias| { - self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias) - }, ) .map(|goals| self.goals_to_obligations(goals)) } else { @@ -231,9 +225,6 @@ impl<'a, 'tcx> At<'a, 'tcx> { ty::Invariant, actual, self.cause.span, - &mut |alias| { - self.infcx.try_eagerly_normalize_alias(self.param_env, self.cause.span, alias) - }, ) .map(|goals| self.goals_to_obligations(goals)) } else { diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e7082f961d0b1..10e7b1e72f446 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,5 +1,5 @@ use std::cell::{Cell, RefCell}; -use std::{fmt, mem}; +use std::fmt; pub use at::DefineOpaqueTypes; use free_regions::RegionRelations; @@ -21,7 +21,6 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::extension; pub use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::bug; -use rustc_middle::hooks::TypeErasedInfcx; use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::select; @@ -1529,17 +1528,6 @@ impl<'tcx> InferCtxt<'tcx> { } } - pub fn try_eagerly_normalize_alias<'a>( - &'a self, - param_env: ty::ParamEnv<'tcx>, - span: Span, - alias: ty::AliasTy<'tcx>, - ) -> Ty<'tcx> { - let erased = - unsafe { mem::transmute::<&'a InferCtxt<'tcx>, TypeErasedInfcx<'a, 'tcx>>(self) }; - self.tcx.try_eagerly_normalize_alias(erased, param_env, span, alias) - } - /// Attach a callback to be invoked on each root obligation evaluated in the new trait solver. pub fn attach_obligation_inspector(&self, inspector: ObligationInspector<'tcx>) { debug_assert!( diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index b2d591327fea2..69c090b662e54 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -51,7 +51,7 @@ impl<'tcx> InferCtxt<'tcx> { /// `TypeRelation`. Do not use this, and instead please use `At::eq`, for all /// other usecases (i.e. setting the value of a type var). #[instrument(level = "debug", skip(self, relation))] - pub fn instantiate_ty_var>( + pub fn instantiate_ty_var>>( &self, relation: &mut R, target_is_expected: bool, @@ -61,56 +61,29 @@ impl<'tcx> InferCtxt<'tcx> { ) -> RelateResult<'tcx, ()> { debug_assert!(self.inner.borrow_mut().type_variables().probe(target_vid).is_unknown()); - let generalized_ty = if self.next_trait_solver() - && matches!(relation.structurally_relate_aliases(), StructurallyRelateAliases::No) - && let ty::Alias(_, alias) = source_ty.kind() - { - let normalized_alias = relation.try_eagerly_normalize_alias(*alias); - - if normalized_alias.is_ty_var() { - normalized_alias - } else { - let Generalization { value_may_be_infer: generalized_ty } = self.generalize( - relation.span(), - GeneralizerState::ShallowStructurallyRelateAliases, - target_vid, - instantiation_variance, - normalized_alias, - &mut |alias| relation.try_eagerly_normalize_alias(alias), - )?; - - // The only way to get a tyvar back is if the outermost type is an alias. - // However, here, though we know it *is* an alias, we initialize the generalizer - // with `ShallowStructurallyRelateAliases` so we treat the outermost alias as rigid, - // ensuring this is never a tyvar. - assert!(!generalized_ty.is_ty_var()); + // Generalize `source_ty` depending on the current variance. As an example, assume + // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference + // variable. + // + // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh + // region/type inference variables. + // + // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and + // `?1 <: ?3`. + let Generalization { value_may_be_infer: generalized_ty } = self.generalize( + relation.span(), + relation.structurally_relate_aliases(), + target_vid, + instantiation_variance, + source_ty, + )?; - generalized_ty - } + // Constrain `b_vid` to the generalized type `generalized_ty`. + if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() { + self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid); } else { - // Generalize `source_ty` depending on the current variance. As an example, assume - // `?target <: &'x ?1`, where `'x` is some free region and `?1` is an inference - // variable. - // - // Then the `generalized_ty` would be `&'?2 ?3`, where `'?2` and `?3` are fresh - // region/type inference variables. - // - // We then relate `generalized_ty <: source_ty`, adding constraints like `'x: '?2` and - // `?1 <: ?3`. - let Generalization { value_may_be_infer: generalized_ty } = self.generalize( - relation.span(), - match relation.structurally_relate_aliases() { - StructurallyRelateAliases::No => GeneralizerState::Default, - StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases, - }, - target_vid, - instantiation_variance, - source_ty, - &mut |alias| relation.try_eagerly_normalize_alias(alias), - )?; - - generalized_ty - }; + self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty); + } // Finally, relate `generalized_ty` to `source_ty`, as described in previous comment. // @@ -118,10 +91,7 @@ impl<'tcx> InferCtxt<'tcx> { // relations wind up attributed to the same spans. We need // to associate causes/spans with each of the relations in // the stack to get this right. - if let &ty::Infer(ty::TyVar(generalized_vid)) = generalized_ty.kind() { - // Constrain `b_vid` to the generalized type variable. - self.inner.borrow_mut().type_variables().equate(target_vid, generalized_vid); - + if generalized_ty.is_ty_var() { // This happens for cases like `::Assoc == ?0`. // We can't instantiate `?0` here as that would result in a // cyclic type. We instead delay the unification in case @@ -162,9 +132,6 @@ impl<'tcx> InferCtxt<'tcx> { } } } else { - // Constrain `b_vid` to the generalized type `generalized_ty`. - self.inner.borrow_mut().type_variables().instantiate(target_vid, generalized_ty); - // NOTE: The `instantiation_variance` is not the same variance as // used by the relation. When instantiating `b`, `target_is_expected` // is flipped and the `instantiation_variance` is also flipped. To @@ -239,14 +206,10 @@ impl<'tcx> InferCtxt<'tcx> { // constants and generic expressions are not yet handled correctly. let Generalization { value_may_be_infer: generalized_ct } = self.generalize( relation.span(), - match relation.structurally_relate_aliases() { - StructurallyRelateAliases::No => GeneralizerState::Default, - StructurallyRelateAliases::Yes => GeneralizerState::StructurallyRelateAliases, - }, + relation.structurally_relate_aliases(), target_vid, ty::Invariant, source_ct, - &mut |alias| relation.try_eagerly_normalize_alias(alias), )?; debug_assert!(!generalized_ct.is_ct_infer()); @@ -282,11 +245,10 @@ impl<'tcx> InferCtxt<'tcx> { fn generalize> + Relate>>( &self, span: Span, - initial_state: GeneralizerState, + structurally_relate_aliases: StructurallyRelateAliases, target_vid: impl Into, ambient_variance: ty::Variance, source_term: T, - normalize: &mut dyn FnMut(ty::AliasTy<'tcx>) -> Ty<'tcx>, ) -> RelateResult<'tcx, Generalization> { assert!(!source_term.has_escaping_bound_vars()); let (for_universe, root_vid) = match target_vid.into() { @@ -302,13 +264,13 @@ impl<'tcx> InferCtxt<'tcx> { let mut generalizer = Generalizer { infcx: self, span, + structurally_relate_aliases, root_vid, for_universe, root_term: source_term.into(), ambient_variance, - state: initial_state, + in_alias: false, cache: Default::default(), - normalize, }; let value_may_be_infer = generalizer.relate(source_term, source_term)?; @@ -355,54 +317,6 @@ impl<'tcx> TypeVisitor> for MaxUniverse { } } -/// This state determines how generalization treats aliases. -/// -/// Based on which state we're in, we treat them either as rigid or normalizable, -/// which might change depending on what types the generalization visitor encounters. -/// See `handle_alias_ty` for the logic of how we change states. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -enum GeneralizerState { - /// Treat aliases as potentially normalizable. - /// - /// This is the default state that generalization starts in, unless we're - /// treating aliases as rigid. It also means we're not currently inside an - /// alias, since then we change the state to `IncompletelyRelateAliasArgs`. - Default, - /// We enter this state when we're generalizing the arguments of a - /// potentially normalizeable alias. - /// - /// The behavior here is different between the old and the new solver: - /// - /// In the old solver, the difference between this and `Default` is needed to - /// correctly handle `::Assoc>::Assoc == ?0`. That - /// equality can hold by either normalizing the outer or the inner - /// associated type. In the old solver, we always structurally relate - /// aliases. If we we encounter an occurs check failure, we propagate the - /// failure to the outermost alias, for which we then emit a `Projection` - /// goal instead. - /// - /// In the new solver, we rarely get into this state. - /// When we encounter aliases we instead attempt to normalize them, and treat - /// them as rigid using `ShallowStructurallyRelate`. Only when an alias has - /// escaping bound variables do we continue with similar logic to the old - /// solver, except now we also explicitly relate the type and consts in the - /// arguments of aliases while in this mode. - /// - /// FIXME: Because we relate the type and consts in the arguments of aliases - /// while in this mode, this is incomplete. - IncompletelyRelateAliasArgs, - /// During generalization, when we encounter aliases, we will first attempt - /// to normalize them when we're using the next trait solver. We can now - /// treat the normalized alias as rigid, but only for "one layer", hence - /// shallow. New aliases encountered inside the arguments of the outer alias - /// should once again be related as normal. - ShallowStructurallyRelateAliases, - /// Treat aliases as rigid when relating them. - /// - /// This corresponds to `relation.structurally_relate_aliases()`. - StructurallyRelateAliases, -} - /// The "generalizer" is used when handling inference variables. /// /// The basic strategy for handling a constraint like `?A <: B` is to @@ -421,6 +335,10 @@ struct Generalizer<'me, 'tcx> { span: Span, + /// Whether aliases should be related structurally. If not, we have to + /// be careful when generalizing aliases. + structurally_relate_aliases: StructurallyRelateAliases, + /// The vid of the type variable that is in the process of being /// instantiated. If we find this within the value we are folding, /// that means we would have created a cyclic value. @@ -438,17 +356,14 @@ struct Generalizer<'me, 'tcx> { /// some other type. What will be the variance at this point? ambient_variance: ty::Variance, - /// This field keeps track of how we treat aliases during generalization. + /// This is set once we're generalizing the arguments of an alias. /// - /// Refer to [`GeneralizerState`]'s docs for more information about the - /// all the possible values this can have, and when we use which. - state: GeneralizerState, + /// This is necessary to correctly handle + /// `::Assoc>::Assoc == ?0`. This equality can + /// hold by either normalizing the outer or the inner associated type. + in_alias: bool, - cache: SsoHashMap<(Ty<'tcx>, ty::Variance, GeneralizerState), Ty<'tcx>>, - - /// Normalize an alias in the trait solver. - /// If normalization fails, a fresh infer var is returned. - normalize: &'me mut dyn FnMut(ty::AliasTy<'tcx>) -> Ty<'tcx>, + cache: SsoHashMap<(Ty<'tcx>, ty::Variance, bool), Ty<'tcx>>, } impl<'tcx> Generalizer<'_, 'tcx> { @@ -484,51 +399,27 @@ impl<'tcx> Generalizer<'_, 'tcx> { /// continue generalizing the alias. This ends up pulling down the universe of the /// inference variable and is incomplete in case the alias would normalize to a type /// which does not mention that inference variable. - fn handle_alias_ty( + fn generalize_alias_ty( &mut self, - alias_ty: Ty<'tcx>, alias: ty::AliasTy<'tcx>, ) -> Result, TypeError<'tcx>> { - match self.state { - GeneralizerState::ShallowStructurallyRelateAliases => { - // We can switch back to default, we've treated one layer as rigid by doing this operation. - self.state = GeneralizerState::Default; - let res = relate::structurally_relate_tys(self, alias_ty, alias_ty); - self.state = GeneralizerState::ShallowStructurallyRelateAliases; - return res; - } - GeneralizerState::StructurallyRelateAliases => { - return relate::structurally_relate_tys(self, alias_ty, alias_ty); - } - GeneralizerState::Default - if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() => - { - // We do not eagerly replace aliases with inference variables if they have - // escaping bound vars, see the method comment for details. However, when we - // are inside of an alias with escaping bound vars replacing nested aliases - // with inference variables can cause incorrect ambiguity. - // - // cc trait-system-refactor-initiative#110 - let normalized_alias = (self.normalize)(alias); - - self.state = GeneralizerState::ShallowStructurallyRelateAliases; - // recursively generalize, treat the outer alias as rigid to avoid infinite recursion - let res = self.relate(normalized_alias, normalized_alias); - - // only one way to get here - self.state = GeneralizerState::Default; - - return res; - } - GeneralizerState::Default | GeneralizerState::IncompletelyRelateAliasArgs => {} + // We do not eagerly replace aliases with inference variables if they have + // escaping bound vars, see the method comment for details. However, when we + // are inside of an alias with escaping bound vars replacing nested aliases + // with inference variables can cause incorrect ambiguity. + // + // cc trait-system-refactor-initiative#110 + if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias { + return Ok(self.next_ty_var_for_alias()); } - let previous_state = - mem::replace(&mut self.state, GeneralizerState::IncompletelyRelateAliasArgs); + let is_nested_alias = mem::replace(&mut self.in_alias, true); let result = match self.relate(alias, alias) { Ok(alias) => Ok(alias.to_ty(self.cx())), - Err(e) => match previous_state { - GeneralizerState::Default => { + Err(e) => { + if is_nested_alias { + return Err(e); + } else { let mut visitor = MaxUniverse::new(); alias.visit_with(&mut visitor); let infer_replacement_is_complete = @@ -541,14 +432,9 @@ impl<'tcx> Generalizer<'_, 'tcx> { debug!("generalization failure in alias"); Ok(self.next_ty_var_for_alias()) } - GeneralizerState::IncompletelyRelateAliasArgs => return Err(e), - - // Early return. - GeneralizerState::ShallowStructurallyRelateAliases - | GeneralizerState::StructurallyRelateAliases => unreachable!(), - }, + } }; - self.state = previous_state; + self.in_alias = is_nested_alias; result } } @@ -602,7 +488,7 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be == - if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.state)) { + if let Some(&result) = self.cache.get(&(t, self.ambient_variance, self.in_alias)) { return Ok(result); } @@ -650,7 +536,6 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // of each other. This is currently only used for diagnostics. // To see why, see the docs in the `type_variables` module. inner.type_variables().sub_unify(vid, new_var_id); - // If we're in the new solver and create a new inference // variable inside of an alias we eagerly constrain that // inference variable to prevent unexpected ambiguity errors. @@ -668,15 +553,9 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // cc trait-system-refactor-initiative#108 if self.infcx.next_trait_solver() && !matches!(self.infcx.typing_mode(), TypingMode::Coherence) + && self.in_alias { - match self.state { - GeneralizerState::IncompletelyRelateAliasArgs => { - inner.type_variables().equate(vid, new_var_id); - } - GeneralizerState::Default - | GeneralizerState::ShallowStructurallyRelateAliases - | GeneralizerState::StructurallyRelateAliases => {} - } + inner.type_variables().equate(vid, new_var_id); } debug!("replacing original vid={:?} with new={:?}", vid, new_var_id); @@ -705,12 +584,15 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { } } - ty::Alias(_, data) => self.handle_alias_ty(t, data), + ty::Alias(_, data) => match self.structurally_relate_aliases { + StructurallyRelateAliases::No => self.generalize_alias_ty(data), + StructurallyRelateAliases::Yes => relate::structurally_relate_tys(self, t, t), + }, _ => relate::structurally_relate_tys(self, t, t), }?; - self.cache.insert((t, self.ambient_variance, self.state), g); + self.cache.insert((t, self.ambient_variance, self.in_alias), g); Ok(g) } @@ -801,15 +683,9 @@ impl<'tcx> TypeRelation> for Generalizer<'_, 'tcx> { // for more details. if self.infcx.next_trait_solver() && !matches!(self.infcx.typing_mode(), TypingMode::Coherence) + && self.in_alias { - match self.state { - GeneralizerState::IncompletelyRelateAliasArgs => { - variable_table.union(vid, new_var_id); - } - GeneralizerState::Default - | GeneralizerState::ShallowStructurallyRelateAliases - | GeneralizerState::StructurallyRelateAliases => {} - } + variable_table.union(vid, new_var_id); } Ok(ty::Const::new_var(self.cx(), new_var_id)) } diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 7e480df7dda63..a05e2d40e829f 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -299,8 +299,4 @@ impl<'tcx> PredicateEmittingRelation> for LatticeOp<'_, 'tcx> { ty::AliasRelationDirection::Equate, ))]); } - - fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy<'tcx>) -> Ty<'tcx> { - self.infcx.try_eagerly_normalize_alias(self.param_env(), self.span(), alias) - } } diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 67f9dc69a4a65..96a0375f5fba6 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -396,13 +396,4 @@ impl<'tcx> PredicateEmittingRelation> for TypeRelating<'_, 'tcx> } })]); } - - fn try_eagerly_normalize_alias( - &mut self, - _alias: rustc_type_ir::AliasTy< as rustc_type_ir::InferCtxtLike>::Interner>, - ) -> < as rustc_type_ir::InferCtxtLike>::Interner as rustc_type_ir::Interner>::Ty - { - // We only try to eagerly normalize aliases if we're using the new solver. - unreachable!() - } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 28f51095966d5..6b7f31521d441 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -904,7 +904,7 @@ pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { rustc_hir_typeck::provide(&mut providers.queries); ty::provide(&mut providers.queries); traits::provide(&mut providers.queries); - solve::provide(providers); + solve::provide(&mut providers.queries); rustc_passes::provide(&mut providers.queries); rustc_traits::provide(&mut providers.queries); rustc_ty_utils::provide(&mut providers.queries); diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index 1f339ea0cabf6..691096f4e47c2 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -3,16 +3,14 @@ //! similar to queries, but queries come with a lot of machinery for caching and incremental //! compilation, whereas hooks are just plain function pointers without any of the query magic. -use std::marker::PhantomData; - use rustc_hir::def_id::{DefId, DefPathHash}; use rustc_session::StableCrateId; use rustc_span::def_id::{CrateNum, LocalDefId}; -use rustc_span::{ExpnHash, ExpnId, Span}; +use rustc_span::{ExpnHash, ExpnId}; +use crate::mir; use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex}; use crate::ty::{Ty, TyCtxt}; -use crate::{mir, ty}; macro_rules! declare_hooks { ($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => { @@ -117,29 +115,6 @@ declare_hooks! { encoder: &mut CacheEncoder<'_, 'tcx>, query_result_index: &mut EncodedDepNodeIndex ) -> (); - - /// Tries to normalize an alias, ignoring any errors. - /// - /// Generalization with the new trait solver calls into this, - /// when generalizing outside of the trait solver in `hir_typeck`. - hook try_eagerly_normalize_alias( - type_erased_infcx: TypeErasedInfcx<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - span: Span, - alias: ty::AliasTy<'tcx> - ) -> Ty<'tcx>; -} - -/// The `try_eagerly_normalize_alias` hook passes an `Infcx` from where it's called (in `rustc_infer`) -/// to where it's provided (in `rustc_trait_selection`). -/// Both of those crates have that type available, but `rustc_middle` does not. -/// Instead we pass this type-erased `Infcx` and transmute on both sides. -/// -/// Has to be `repr(transparent)` so we can transmute a `&'a Infcx<'tcx>` to this struct. -#[repr(transparent)] -pub struct TypeErasedInfcx<'a, 'tcx> { - _infcx: *const (), - phantom: PhantomData<&'a mut &'tcx ()>, } #[cold] diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index e469451da993e..ce2be24adc586 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -177,11 +177,7 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { cache: Default::default(), }; let param_env = param_env.fold_with(&mut env_canonicalizer); - debug_assert!( - env_canonicalizer.sub_root_lookup_table.is_empty(), - "{:?}", - env_canonicalizer.sub_root_lookup_table - ); + debug_assert!(env_canonicalizer.sub_root_lookup_table.is_empty()); ( param_env, env_canonicalizer.variables, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 456fe5246d801..cd74e87b670f1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -987,12 +987,7 @@ where let replacement = self.ecx.instantiate_binder_with_infer(*replacement); self.nested.extend( self.ecx - .relate_and_get_goals( - self.param_env, - alias_term, - ty::Invariant, - replacement.projection_term, - ) + .eq_and_get_goals(self.param_env, alias_term, replacement.projection_term) .expect("expected to be able to unify goal projection with dyn's projection"), ); 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 fedb6390d9588..6841fe1c5124e 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 @@ -408,7 +408,7 @@ where /// Recursively evaluates `goal`, returning whether any inference vars have /// been constrained and the certainty of the result. - pub(super) fn evaluate_goal( + fn evaluate_goal( &mut self, source: GoalSource, goal: Goal, @@ -1018,8 +1018,7 @@ where variance: ty::Variance, rhs: T, ) -> Result<(), NoSolution> { - let goals = self.relate_and_get_goals(param_env, lhs, variance, rhs)?; - + let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?; for &goal in goals.iter() { let source = match goal.predicate.kind().skip_binder() { ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => { @@ -1040,37 +1039,13 @@ where /// If possible, try using `eq` instead which automatically handles nested /// goals correctly. #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn relate_and_get_goals>( - &mut self, + pub(super) fn eq_and_get_goals>( + &self, param_env: I::ParamEnv, lhs: T, - variance: ty::Variance, rhs: T, ) -> Result>, NoSolution> { - let cx = self.cx(); - let delegate = self.delegate; - let origin_span = self.origin_span; - - let mut normalize = |alias: ty::AliasTy| { - let inference_var = self.next_ty_infer(); - - let goal = Goal::new( - cx, - param_env, - ty::PredicateKind::AliasRelate( - alias.to_ty(cx).into(), - inference_var.into(), - ty::AliasRelationDirection::Equate, - ), - ); - - // Ignore the result. If we can't eagerly normalize, returning the inference variable is enough. - let _ = self.evaluate_goal(GoalSource::TypeRelating, goal, None); - - self.resolve_vars_if_possible(inference_var) - }; - - Ok(delegate.relate(param_env, lhs, variance, rhs, origin_span, &mut normalize)?) + Ok(self.delegate.relate(param_env, lhs, ty::Variance::Invariant, rhs, self.origin_span)?) } pub(super) fn instantiate_binder_with_infer + Copy>( diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index c7699f31a0f95..5d200c4d340ba 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -1,8 +1,3 @@ -use std::mem; - -use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::{Obligation, ObligationCause}; -use rustc_middle::hooks::TypeErasedInfcx; pub use rustc_next_trait_solver::solve::*; mod delegate; @@ -18,13 +13,10 @@ pub use normalize::{ deeply_normalize, deeply_normalize_with_skipped_universes, deeply_normalize_with_skipped_universes_and_ambiguous_coroutine_goals, }; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_middle::util::Providers; -use rustc_span::Span; +use rustc_middle::query::Providers; +use rustc_middle::ty::TyCtxt; pub use select::InferCtxtSelectExt; -use crate::traits::ObligationCtxt; - fn evaluate_root_goal_for_proof_tree_raw<'tcx>( tcx: TyCtxt<'tcx>, canonical_input: CanonicalInput>, @@ -35,46 +27,6 @@ fn evaluate_root_goal_for_proof_tree_raw<'tcx>( ) } -fn try_eagerly_normalize_alias<'a, 'tcx>( - tcx: TyCtxt<'tcx>, - type_erased_infcx: TypeErasedInfcx<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - span: Span, - alias: ty::AliasTy<'tcx>, -) -> Ty<'tcx> { - let infcx = unsafe { - mem::transmute::, &'a InferCtxt<'tcx>>(type_erased_infcx) - }; - - let ocx = ObligationCtxt::new(infcx); - - let infer_term = infcx.next_ty_var(span); - - // Dummy because we ignore the error anyway. - // We do provide a span, because this span is used when registering opaque types. - // For example, if we don't provide a span here, some diagnostics talking about TAIT will refer to a dummy span. - let cause = ObligationCause::dummy_with_span(span); - let obligation = Obligation::new( - tcx, - cause, - param_env, - ty::PredicateKind::AliasRelate( - alias.to_ty(tcx).into(), - infer_term.into(), - ty::AliasRelationDirection::Equate, - ), - ); - - ocx.register_obligation(obligation); - - // We only use this to constrain inference variables. - // We don't care if it errors. - let _ = ocx.try_evaluate_obligations(); - - infcx.resolve_vars_if_possible(infer_term) -} - pub fn provide(providers: &mut Providers) { - providers.hooks.try_eagerly_normalize_alias = try_eagerly_normalize_alias; - providers.queries.evaluate_root_goal_for_proof_tree_raw = evaluate_root_goal_for_proof_tree_raw; + *providers = Providers { evaluate_root_goal_for_proof_tree_raw, ..*providers }; } diff --git a/compiler/rustc_type_ir/src/relate/combine.rs b/compiler/rustc_type_ir/src/relate/combine.rs index 72d54c23733ee..64b87fac77f94 100644 --- a/compiler/rustc_type_ir/src/relate/combine.rs +++ b/compiler/rustc_type_ir/src/relate/combine.rs @@ -40,8 +40,6 @@ where /// Register `AliasRelate` obligation(s) that both types must be related to each other. fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty); - - fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy) -> I::Ty; } pub fn super_combine_tys( diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index 541b2531fe749..82ee4f75fcb0a 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -15,7 +15,6 @@ pub trait RelateExt: InferCtxtLike { variance: ty::Variance, rhs: T, span: ::Span, - normalize: &mut dyn FnMut(ty::AliasTy) -> ::Ty, ) -> Result< Vec::Predicate>>, TypeError, @@ -33,46 +32,40 @@ pub trait RelateExt: InferCtxtLike { >; } -impl> RelateExt for Infcx { - fn relate>( +impl RelateExt for Infcx { + fn relate>( &self, - param_env: I::ParamEnv, + param_env: ::ParamEnv, lhs: T, variance: ty::Variance, rhs: T, - span: I::Span, - normalize: &mut dyn FnMut(ty::AliasTy) -> I::Ty, - ) -> Result>, TypeError> { - let mut relate = SolverRelating::new( - self, - StructurallyRelateAliases::No, - variance, - param_env, - span, - normalize, - ); + span: ::Span, + ) -> Result< + Vec::Predicate>>, + TypeError, + > { + let mut relate = + SolverRelating::new(self, StructurallyRelateAliases::No, variance, param_env, span); relate.relate(lhs, rhs)?; Ok(relate.goals) } - fn eq_structurally_relating_aliases>( + fn eq_structurally_relating_aliases>( &self, - param_env: I::ParamEnv, + param_env: ::ParamEnv, lhs: T, rhs: T, - span: I::Span, - ) -> Result>, TypeError> { - // Structurally relating, we treat aliases as rigid, - // so we shouldn't ever try to normalize them. - let mut normalize_unreachable = |_alias| unreachable!(); - + span: ::Span, + ) -> Result< + Vec::Predicate>>, + TypeError, + > { let mut relate = SolverRelating::new( self, StructurallyRelateAliases::Yes, ty::Invariant, param_env, span, - &mut normalize_unreachable, ); relate.relate(lhs, rhs)?; Ok(relate.goals) @@ -82,14 +75,12 @@ impl> RelateExt for Infcx { /// Enforce that `a` is equal to or a subtype of `b`. pub struct SolverRelating<'infcx, Infcx, I: Interner> { infcx: &'infcx Infcx, - // Immutable fields. structurally_relate_aliases: StructurallyRelateAliases, param_env: I::ParamEnv, span: I::Span, // Mutable fields. ambient_variance: ty::Variance, - normalize: &'infcx mut dyn FnMut(ty::AliasTy) -> I::Ty, goals: Vec>, /// The cache only tracks the `ambient_variance` as it's the /// only field which is mutable and which meaningfully changes @@ -127,14 +118,12 @@ where ambient_variance: ty::Variance, param_env: I::ParamEnv, span: I::Span, - normalize: &'infcx mut dyn FnMut(ty::AliasTy) -> I::Ty, ) -> Self { SolverRelating { infcx, structurally_relate_aliases, span, ambient_variance, - normalize, param_env, goals: vec![], cache: Default::default(), @@ -417,8 +406,4 @@ where } })]); } - - fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy) -> I::Ty { - (self.normalize)(alias) - } } diff --git a/tests/ui/impl-trait/unsized_coercion.next.stderr b/tests/ui/impl-trait/unsized_coercion.next.stderr new file mode 100644 index 0000000000000..bea5ddb0aefcc --- /dev/null +++ b/tests/ui/impl-trait/unsized_coercion.next.stderr @@ -0,0 +1,11 @@ +error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time + --> $DIR/unsized_coercion.rs:14:17 + | +LL | let x = hello(); + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/unsized_coercion.rs b/tests/ui/impl-trait/unsized_coercion.rs index f77f2198be0ef..2cbf0d25d7ec6 100644 --- a/tests/ui/impl-trait/unsized_coercion.rs +++ b/tests/ui/impl-trait/unsized_coercion.rs @@ -3,7 +3,7 @@ //@ revisions: next old //@[next] compile-flags: -Znext-solver -//@ check-pass +//@[old] check-pass trait Trait {} @@ -12,6 +12,7 @@ impl Trait for u32 {} fn hello() -> Box { if true { let x = hello(); + //[next]~^ ERROR: the size for values of type `dyn Trait` cannot be known at compilation time let y: Box = x; } Box::new(1u32) diff --git a/tests/ui/impl-trait/unsized_coercion3.next.stderr b/tests/ui/impl-trait/unsized_coercion3.next.stderr index db758761d7954..a480a69a38641 100644 --- a/tests/ui/impl-trait/unsized_coercion3.next.stderr +++ b/tests/ui/impl-trait/unsized_coercion3.next.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `dyn Send: Trait` is not satisfied - --> $DIR/unsized_coercion3.rs:14:17 + --> $DIR/unsized_coercion3.rs:13:17 | LL | let x = hello(); | ^^^^^^^ the trait `Trait` is not implemented for `dyn Send` @@ -9,37 +9,7 @@ help: the trait `Trait` is implemented for `u32` | LL | impl Trait for u32 {} | ^^^^^^^^^^^^^^^^^^ -note: required by a bound in `Box` - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL -error[E0308]: mismatched types - --> $DIR/unsized_coercion3.rs:19:5 - | -LL | fn hello() -> Box { - | ------------------------ - | | | - | | the expected opaque type - | expected `Box` because of return type -... -LL | Box::new(1u32) - | ^^^^^^^^^^^^^^ types differ - | - = note: expected struct `Box` - found struct `Box` - -error[E0277]: the trait bound `dyn Send: Trait` is not satisfied - --> $DIR/unsized_coercion3.rs:11:1 - | -LL | fn hello() -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `dyn Send` - | -help: the trait `Trait` is implemented for `u32` - --> $DIR/unsized_coercion3.rs:9:1 - | -LL | impl Trait for u32 {} - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/unsized_coercion3.old.stderr b/tests/ui/impl-trait/unsized_coercion3.old.stderr index 3bb9f9c209510..52a72b84a8dd6 100644 --- a/tests/ui/impl-trait/unsized_coercion3.old.stderr +++ b/tests/ui/impl-trait/unsized_coercion3.old.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `impl Trait + ?Sized` cannot be known at compilation time - --> $DIR/unsized_coercion3.rs:16:32 + --> $DIR/unsized_coercion3.rs:15:32 | LL | let y: Box = x; | ^ doesn't have a size known at compile-time diff --git a/tests/ui/impl-trait/unsized_coercion3.rs b/tests/ui/impl-trait/unsized_coercion3.rs index c1dd5350e229a..ebfbb2955de55 100644 --- a/tests/ui/impl-trait/unsized_coercion3.rs +++ b/tests/ui/impl-trait/unsized_coercion3.rs @@ -9,7 +9,6 @@ trait Trait {} impl Trait for u32 {} fn hello() -> Box { - //[next]~^ ERROR: the trait bound `dyn Send: Trait` is not satisfied if true { let x = hello(); //[next]~^ ERROR: the trait bound `dyn Send: Trait` is not satisfied @@ -17,7 +16,6 @@ fn hello() -> Box { //[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know } Box::new(1u32) - //[next]~^ ERROR: mismatched types } fn main() {} diff --git a/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr b/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr index 4652bf5e3c586..afacb3a7d5213 100644 --- a/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr +++ b/tests/ui/methods/rigid-alias-bound-is-not-inherent.next.stderr @@ -9,7 +9,7 @@ note: candidate #1 is defined in the trait `Trait1` | LL | fn method(&self) { | ^^^^^^^^^^^^^^^^ -note: candidate #2 is defined in an impl of the trait `Trait2` for the type `T` +note: candidate #2 is defined in the trait `Trait2` --> $DIR/rigid-alias-bound-is-not-inherent.rs:27:5 | LL | fn method(&self) { diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed index 1c45a2c0adb3e..ba46a447802c8 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed @@ -8,5 +8,6 @@ fn main() { //[next]~^^ ERROR expected a `FnMut(& as Iterator>::Item)` closure, found let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //[current]~^ ERROR type mismatch in closure arguments - //[next]~^^ ERROR expected a `FnMut(& as Iterator>::Item)` closure, found + //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` + //[next]~| ERROR expected a `FnMut(& as Iterator>::Item)` closure, found } diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr index 36e49c20c4331..7912ed4d7071a 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr @@ -12,6 +12,12 @@ LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL +error[E0271]: expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:24 + | +LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); + | ^^^^ expected `&&i32`, found integer + error[E0277]: expected a `FnMut(& as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:9:29: 9:40}` --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:29 | @@ -26,6 +32,7 @@ LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); note: required by a bound in `find` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs index 20d6fed3b35b8..0fd56707763e9 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs @@ -8,5 +8,6 @@ fn main() { //[next]~^^ ERROR expected a `FnMut(& as Iterator>::Item)` closure, found let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); //[current]~^ ERROR type mismatch in closure arguments - //[next]~^^ ERROR expected a `FnMut(& as Iterator>::Item)` closure, found + //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` + //[next]~| ERROR expected a `FnMut(& as Iterator>::Item)` closure, found } diff --git a/tests/ui/traits/next-solver/generalize/constrain-inference-during-normalize.rs b/tests/ui/traits/next-solver/generalize/constrain-inference-during-normalize.rs new file mode 100644 index 0000000000000..c3942b008ccbc --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/constrain-inference-during-normalize.rs @@ -0,0 +1,25 @@ +// revisions: next old +//[next] compile-flags: -Znext-solver +//@ check-pass +// Regression test for https://github.com/rust-lang/rust/issues/154173. +// The ICE there was caused by a (flawed) attempt to eagerly normalize during generalization. +// The normalize would constrain other inference variables, which we couldn't deal with. + +trait Trait { + type Assoc; +} + +impl Trait for () { + type Assoc = u32; +} + +trait Eq {} +impl, T> Eq for (C, T, >::Assoc) {} +fn foo() +where + ((), A, A): Eq +{} + +fn main() { + foo::<_>(); +} diff --git a/tests/ui/traits/next-solver/generalize/eagely-normalizing-aliases.rs b/tests/ui/traits/next-solver/generalize/eagely-normalizing-aliases.rs deleted file mode 100644 index 463fe49e55315..0000000000000 --- a/tests/ui/traits/next-solver/generalize/eagely-normalizing-aliases.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ revisions: old next -//@[next] compile-flags: -Znext-solver -//@ ignore-compare-mode-next-solver (explicit revisions) -//@ check-pass -// Regression test for trait-system-refactor-initiative#262 - -trait View {} -trait HasAssoc { - type Assoc; -} - -struct StableVec(T); -impl View for StableVec {} - -fn assert_view(f: F) -> F { f } - - -fn store(x: StableVec) -where - T: HasAssoc, - StableVec: View, -{ - let _: StableVec = assert_view(x); -} - -fn main() {}