Rollup merge of #154257 - jdonszelmann:revert-eagerly-normalize-in-generalize, r=lcnr

Revert eagerly normalize in generalize

r? @lcnr

Reverts https://github.com/rust-lang/rust/pull/151746

We'll likely pull eager normalization out of generalization

Fixes rust-lang/rust#154173
Fixes rust-lang/rust#154244
This commit is contained in:
Jonathan Brouwer
2026-03-23 20:18:34 +01:00
committed by GitHub
25 changed files with 150 additions and 449 deletions
@@ -616,9 +616,4 @@ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
}
})]);
}
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())
}
}
-9
View File
@@ -140,9 +140,6 @@ pub fn sup<T>(
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 @@ pub fn sub<T>(
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 @@ pub fn eq_trace<T>(
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 {
+1 -13
View File
@@ -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_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 @@ pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar) -> boo
}
}
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!(
@@ -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<R: PredicateEmittingRelation<Self>>(
pub fn instantiate_ty_var<R: PredicateEmittingRelation<InferCtxt<'tcx>>>(
&self,
relation: &mut R,
target_is_expected: bool,
@@ -61,56 +61,29 @@ pub fn instantiate_ty_var<R: PredicateEmittingRelation<Self>>(
) -> 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);
// 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,
)?;
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());
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 @@ pub fn instantiate_ty_var<R: PredicateEmittingRelation<Self>>(
// 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 `<?0 as Trait>::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 @@ pub fn instantiate_ty_var<R: PredicateEmittingRelation<Self>>(
}
}
} 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 @@ pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<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 @@ pub(crate) fn instantiate_const_var<R: PredicateEmittingRelation<InferCtxt<'tcx>
fn generalize<T: Into<Term<'tcx>> + Relate<TyCtxt<'tcx>>>(
&self,
span: Span,
initial_state: GeneralizerState,
structurally_relate_aliases: StructurallyRelateAliases,
target_vid: impl Into<TermVid>,
ambient_variance: ty::Variance,
source_term: T,
normalize: &mut dyn FnMut(ty::AliasTy<'tcx>) -> Ty<'tcx>,
) -> RelateResult<'tcx, Generalization<T>> {
assert!(!source_term.has_escaping_bound_vars());
let (for_universe, root_vid) = match target_vid.into() {
@@ -302,13 +264,13 @@ fn generalize<T: Into<Term<'tcx>> + Relate<TyCtxt<'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 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) {
}
}
/// 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 `<T as Bar<<?0 as Foo>::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
/// `<T as Bar<<?0 as Foo>::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 @@ fn next_ty_var_for_alias(&self) -> Ty<'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<Ty<'tcx>, 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 @@ fn handle_alias_ty(
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 @@ fn relate_with_variance<T: Relate<TyCtxt<'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 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'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 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'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 @@ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'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 @@ fn consts(
// 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))
}
@@ -299,8 +299,4 @@ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'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)
}
}
@@ -396,13 +396,4 @@ fn register_alias_relate_predicate(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
}
})]);
}
fn try_eagerly_normalize_alias(
&mut self,
_alias: rustc_type_ir::AliasTy<<InferCtxt<'tcx> as rustc_type_ir::InferCtxtLike>::Interner>,
) -> <<InferCtxt<'tcx> 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!()
}
}
+1 -1
View File
@@ -904,7 +904,7 @@ pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) {
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);
+2 -27
View File
@@ -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 @@ fn clone(&self) -> Self { *self }
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]
@@ -177,11 +177,7 @@ fn canonicalize_param_env(
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,
@@ -987,12 +987,7 @@ fn try_eagerly_replace_alias(
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"),
);
@@ -408,7 +408,7 @@ pub(super) fn ignore_candidate_head_usages(&mut self, usages: CandidateHeadUsage
/// 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<I, I::Predicate>,
@@ -1018,8 +1018,7 @@ pub(super) fn relate<T: Relate<I>>(
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 @@ pub(super) fn relate<T: Relate<I>>(
/// 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<T: Relate<I>>(
&mut self,
pub(super) fn eq_and_get_goals<T: Relate<I>>(
&self,
param_env: I::ParamEnv,
lhs: T,
variance: ty::Variance,
rhs: T,
) -> Result<Vec<Goal<I, I::Predicate>>, NoSolution> {
let cx = self.cx();
let delegate = self.delegate;
let origin_span = self.origin_span;
let mut normalize = |alias: ty::AliasTy<I>| {
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<T: TypeFoldable<I> + Copy>(
+3 -51
View File
@@ -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 @@
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<TyCtxt<'tcx>>,
@@ -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::<TypeErasedInfcx<'a, 'tcx>, &'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 };
}
@@ -40,8 +40,6 @@ fn register_predicates(
/// 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>) -> I::Ty;
}
pub fn super_combine_tys<Infcx, I, R>(
@@ -15,7 +15,6 @@ fn relate<T: Relate<Self::Interner>>(
variance: ty::Variance,
rhs: T,
span: <Self::Interner as Interner>::Span,
normalize: &mut dyn FnMut(ty::AliasTy<Self::Interner>) -> <Self::Interner as Interner>::Ty,
) -> Result<
Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
TypeError<Self::Interner>,
@@ -33,46 +32,40 @@ fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
>;
}
impl<I: Interner, Infcx: InferCtxtLike<Interner = I>> RelateExt for Infcx {
fn relate<T: Relate<I>>(
impl<Infcx: InferCtxtLike> RelateExt for Infcx {
fn relate<T: Relate<Self::Interner>>(
&self,
param_env: I::ParamEnv,
param_env: <Self::Interner as Interner>::ParamEnv,
lhs: T,
variance: ty::Variance,
rhs: T,
span: I::Span,
normalize: &mut dyn FnMut(ty::AliasTy<I>) -> I::Ty,
) -> Result<Vec<Goal<I, I::Predicate>>, TypeError<I>> {
let mut relate = SolverRelating::new(
self,
StructurallyRelateAliases::No,
variance,
param_env,
span,
normalize,
);
span: <Self::Interner as Interner>::Span,
) -> Result<
Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
TypeError<Self::Interner>,
> {
let mut relate =
SolverRelating::new(self, StructurallyRelateAliases::No, variance, param_env, span);
relate.relate(lhs, rhs)?;
Ok(relate.goals)
}
fn eq_structurally_relating_aliases<T: Relate<I>>(
fn eq_structurally_relating_aliases<T: Relate<Self::Interner>>(
&self,
param_env: I::ParamEnv,
param_env: <Self::Interner as Interner>::ParamEnv,
lhs: T,
rhs: T,
span: I::Span,
) -> Result<Vec<Goal<I, I::Predicate>>, TypeError<I>> {
// Structurally relating, we treat aliases as rigid,
// so we shouldn't ever try to normalize them.
let mut normalize_unreachable = |_alias| unreachable!();
span: <Self::Interner as Interner>::Span,
) -> Result<
Vec<Goal<Self::Interner, <Self::Interner as Interner>::Predicate>>,
TypeError<Self::Interner>,
> {
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 @@ fn eq_structurally_relating_aliases<T: Relate<I>>(
/// 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>) -> I::Ty,
goals: Vec<Goal<I, I::Predicate>>,
/// The cache only tracks the `ambient_variance` as it's the
/// only field which is mutable and which meaningfully changes
@@ -127,14 +118,12 @@ pub fn new(
ambient_variance: ty::Variance,
param_env: I::ParamEnv,
span: I::Span,
normalize: &'infcx mut dyn FnMut(ty::AliasTy<I>) -> I::Ty,
) -> Self {
SolverRelating {
infcx,
structurally_relate_aliases,
span,
ambient_variance,
normalize,
param_env,
goals: vec![],
cache: Default::default(),
@@ -417,8 +406,4 @@ fn register_alias_relate_predicate(&mut self, a: I::Ty, b: I::Ty) {
}
})]);
}
fn try_eagerly_normalize_alias(&mut self, alias: ty::AliasTy<I>) -> I::Ty {
(self.normalize)(alias)
}
}
@@ -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`.
+2 -1
View File
@@ -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<impl Trait> {
if true {
let x = hello();
//[next]~^ ERROR: the size for values of type `dyn Trait` cannot be known at compilation time
let y: Box<dyn Trait> = x;
}
Box::new(1u32)
@@ -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<impl Trait + ?Sized> {
| ------------------------
| | |
| | the expected opaque type
| expected `Box<impl Trait + ?Sized>` because of return type
...
LL | Box::new(1u32)
| ^^^^^^^^^^^^^^ types differ
|
= note: expected struct `Box<impl Trait + ?Sized>`
found struct `Box<u32>`
error: aborting due to 1 previous error
error[E0277]: the trait bound `dyn Send: Trait` is not satisfied
--> $DIR/unsized_coercion3.rs:11:1
|
LL | fn hello() -> Box<impl Trait + ?Sized> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
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`.
@@ -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<dyn Send> = x;
| ^ doesn't have a size known at compile-time
-2
View File
@@ -9,7 +9,6 @@ trait Trait {}
impl Trait for u32 {}
fn hello() -> Box<impl Trait + ?Sized> {
//[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<impl Trait + ?Sized> {
//[old]~^ ERROR: the size for values of type `impl Trait + ?Sized` cannot be know
}
Box::new(1u32)
//[next]~^ ERROR: mismatched types
}
fn main() {}
@@ -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) {
@@ -8,5 +8,6 @@ fn main() {
//[next]~^^ ERROR expected a `FnMut(&<std::ops::RangeInclusive<{integer}> 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(&<std::ops::RangeInclusive<{integer}> 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(&<std::ops::RangeInclusive<{integer}> as Iterator>::Item)` closure, found
}
@@ -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(&<std::ops::RangeInclusive<{integer}> 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`.
@@ -8,5 +8,6 @@ fn main() {
//[next]~^^ ERROR expected a `FnMut(&<std::ops::RangeInclusive<{integer}> 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(&<std::ops::RangeInclusive<{integer}> 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(&<std::ops::RangeInclusive<{integer}> as Iterator>::Item)` closure, found
}
@@ -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<T> {
type Assoc;
}
impl Trait<u32> for () {
type Assoc = u32;
}
trait Eq {}
impl<C: Trait<T>, T> Eq for (C, T, <C as Trait<T>>::Assoc) {}
fn foo<A>()
where
((), A, A): Eq
{}
fn main() {
foo::<_>();
}
@@ -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>(T);
impl<T> View for StableVec<T> {}
fn assert_view<F: View>(f: F) -> F { f }
fn store<T>(x: StableVec<T::Assoc>)
where
T: HasAssoc,
StableVec<T>: View,
{
let _: StableVec<T::Assoc> = assert_view(x);
}
fn main() {}