Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion compiler/rustc_infer/src/infer/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
&self,
u: ty::UniverseIndex,
) -> Option<rustc_type_ir::region_constraint::Assumptions<TyCtxt<'tcx>>> {
self.placeholder_assumptions_for_next_solver.borrow().get(&u).unwrap().as_ref().cloned()
// FIXME(-Zassumptions_on_binders): We should actually make sure that
// we always register placeholder assumptions.
self.placeholder_assumptions_for_next_solver.borrow().get(&u)?.as_ref().cloned()
}

fn get_solver_region_constraint(
Expand Down
26 changes: 22 additions & 4 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ use rustc_middle::traits::select;
use rustc_middle::traits::solve::Goal;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{
self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs,
GenericArgsRef, GenericParamDefKind, InferConst, IntVid, OpaqueTypeKey, ProvisionalHiddenType,
PseudoCanonicalInput, Term, TermKind, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder,
TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, fold_regions,
self, AliasTermKind, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind,
GenericArgs, GenericArgsRef, GenericParamDefKind, InferConst, IntVid, OpaqueTypeKey,
ProvisionalHiddenType, PseudoCanonicalInput, Term, TermKind, Ty, TyCtxt, TyVid, TypeFoldable,
TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode,
fold_regions,
};
use rustc_span::{DUMMY_SP, Span, Symbol};
use rustc_type_ir::MayBeErased;
Expand Down Expand Up @@ -962,6 +963,23 @@ impl<'tcx> InferCtxt<'tcx> {
}
}

pub fn next_term_var_for_alias(
&self,
alias: ty::AliasTerm<'tcx>,
span: Span,
) -> ty::Term<'tcx> {
match alias.kind(self.tcx) {
AliasTermKind::ProjectionTy { .. }
| AliasTermKind::InherentTy { .. }
| AliasTermKind::OpaqueTy { .. }
| AliasTermKind::FreeTy { .. } => self.next_ty_var(span).into(),
AliasTermKind::UnevaluatedConst { .. }
| AliasTermKind::ProjectionConst { .. }
| AliasTermKind::FreeConst { .. }
| AliasTermKind::InherentConst { .. } => self.next_const_var(span).into(),
}
}

/// Return the universe that the region `r` was created in. For
/// most regions (e.g., `'static`, named regions from the user,
/// etc) this is the root universe U0. For inference variables or
Expand Down
11 changes: 2 additions & 9 deletions compiler/rustc_middle/src/ty/fast_reject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,7 @@ pub use rustc_type_ir::fast_reject::*;

use super::TyCtxt;

pub type DeepRejectCtxt<
'tcx,
const INSTANTIATE_LHS_WITH_INFER: bool,
const INSTANTIATE_RHS_WITH_INFER: bool,
> = rustc_type_ir::fast_reject::DeepRejectCtxt<
TyCtxt<'tcx>,
INSTANTIATE_LHS_WITH_INFER,
INSTANTIATE_RHS_WITH_INFER,
>;
pub type DeepRejectCtxt<'tcx, const HANDLE_LHS: u8, const HANDLE_RHS: u8> =
rustc_type_ir::fast_reject::DeepRejectCtxt<TyCtxt<'tcx>, HANDLE_LHS, HANDLE_RHS>;

pub type SimplifiedType = rustc_type_ir::fast_reject::SimplifiedType<DefId>;
173 changes: 100 additions & 73 deletions compiler/rustc_next_trait_solver/src/normalize.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::fmt::Debug;

use rustc_data_structures::sso::{SsoHashMap, SsoHashSet};
use rustc_type_ir::data_structures::ensure_sufficient_stack;
use rustc_type_ir::inherent::*;
use rustc_type_ir::solve::{Goal, NoSolution};
use rustc_type_ir::{
self as ty, Binder, FallibleTypeFolder, InferConst, InferCtxtLike, InferTy, Interner,
TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
self as ty, AliasTerm, Binder, FallibleTypeFolder, InferConst, InferCtxtLike, InferTy,
Interner, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
TypeVisitor, UniverseIndex,
};
use tracing::instrument;
Expand All @@ -13,19 +15,25 @@ use crate::placeholder::{BoundVarReplacer, PlaceholderReplacer};
/// This folder normalizes value and collects ambiguous goals.
///
/// Note that for ambiguous alias which contains escaping bound vars,
/// we just return the original alias and don't collect the ambiguous goal.
/// we just return the original alias.
pub struct NormalizationFolder<'a, Infcx, I, F>
where
Infcx: InferCtxtLike<Interner = I>,
I: Interner,
{
infcx: &'a Infcx,
universes: Vec<Option<UniverseIndex>>,
stalled_goals: Vec<Goal<I, I::Predicate>>,
normalize: F,
cache: SsoHashMap<I::Ty, I::Ty>,
}

#[derive(PartialEq, Eq, Debug)]
pub enum NormalizationWasAmbiguous {
Yes,
No,
}

#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Debug)]
enum HasEscapingBoundVars {
Yes,
No,
Expand All @@ -39,6 +47,7 @@ where
{
infcx: &'a Infcx,
max_universe: ty::UniverseIndex,
cache: SsoHashSet<I::Ty>,
}

impl<'a, Infcx, I> MaxUniverse<'a, Infcx, I>
Expand All @@ -47,7 +56,7 @@ where
I: Interner,
{
fn new(infcx: &'a Infcx) -> Self {
MaxUniverse { infcx, max_universe: ty::UniverseIndex::ROOT }
MaxUniverse { infcx, max_universe: ty::UniverseIndex::ROOT, cache: Default::default() }
}

fn max_universe(self) -> ty::UniverseIndex {
Expand All @@ -73,7 +82,9 @@ where
self.max_universe = self.max_universe.max(self.infcx.universe_of_ty(vid).unwrap());
}

t.super_visit_with(self)
if self.cache.insert(t) {
t.super_visit_with(self)
}
}

fn visit_const(&mut self, c: I::Const) {
Expand All @@ -97,34 +108,25 @@ where
}
}

impl<'a, Infcx, I, F> NormalizationFolder<'a, Infcx, I, F>
impl<'a, Infcx, I, F, E> NormalizationFolder<'a, Infcx, I, F>
where
Infcx: InferCtxtLike<Interner = I>,
I: Interner,
F: FnMut(I::Term) -> Result<(I::Term, Option<Goal<I, I::Predicate>>), NoSolution>,
F: FnMut(AliasTerm<I>) -> Result<(I::Term, NormalizationWasAmbiguous), E>,
{
pub fn new(
infcx: &'a Infcx,
universes: Vec<Option<UniverseIndex>>,
stalled_goals: Vec<Goal<I, I::Predicate>>,
normalize: F,
) -> Self {
Self { infcx, universes, stalled_goals, normalize }
}

pub fn stalled_goals(self) -> Vec<Goal<I, I::Predicate>> {
self.stalled_goals
pub fn new(infcx: &'a Infcx, universes: Vec<Option<UniverseIndex>>, normalize: F) -> Self {
Self { infcx, universes, normalize, cache: Default::default() }
}

fn normalize_alias_term(
&mut self,
alias_term: I::Term,
alias_term: AliasTerm<I>,
has_escaping: HasEscapingBoundVars,
) -> Result<I::Term, NoSolution> {
) -> Result<Option<I::Term>, E> {
let current_universe = self.infcx.universe();
self.infcx.create_next_universe();

let (normalized, ambig_goal) = (self.normalize)(alias_term)?;
let (normalized, normalization_was_ambiguous) = (self.normalize)(alias_term)?;

// Return ambiguous higher ranked alias as is, if
// - it contains escaping vars, and
Expand All @@ -134,27 +136,29 @@ where
// referencing the temporary placeholders.
//
// We can normalize the ambiguous alias again after the binder is instantiated.
if ambig_goal.is_some() && has_escaping == HasEscapingBoundVars::Yes {
if NormalizationWasAmbiguous::Yes == normalization_was_ambiguous
&& has_escaping == HasEscapingBoundVars::Yes
{
let mut visitor = MaxUniverse::new(self.infcx);
normalized.visit_with(&mut visitor);
let max_universe = visitor.max_universe();
if current_universe.cannot_name(max_universe) {
return Ok(alias_term);
return Ok(None);
}
}

self.stalled_goals.extend(ambig_goal);
Ok(normalized)
Ok(Some(normalized))
}
}

impl<'a, Infcx, I, F> FallibleTypeFolder<I> for NormalizationFolder<'a, Infcx, I, F>
impl<'a, Infcx, I, F, E> FallibleTypeFolder<I> for NormalizationFolder<'a, Infcx, I, F>
where
Infcx: InferCtxtLike<Interner = I>,
I: Interner,
F: FnMut(I::Term) -> Result<(I::Term, Option<Goal<I, I::Predicate>>), NoSolution>,
F: FnMut(AliasTerm<I>) -> Result<(I::Term, NormalizationWasAmbiguous), E>,
E: Debug,
{
type Error = NoSolution;
type Error = E;

fn cx(&self) -> I {
self.infcx.cx()
Expand All @@ -177,32 +181,42 @@ where
return Ok(ty);
}

if let Some(ty) = self.cache.get(&ty) {
return Ok(*ty);
}

// With eager normalization, we should normalize the args of alias before
// normalizing the alias itself.
let ty = ty.try_super_fold_with(self)?;
let ty::Alias(..) = ty.kind() else { return Ok(ty) };

if ty.has_escaping_bound_vars() {
let (ty, mapped_regions, mapped_types, mapped_consts) =
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ty);
let result = ensure_sufficient_stack(|| {
self.normalize_alias_term(ty.into(), HasEscapingBoundVars::Yes)
})?
.expect_ty();
Ok(PlaceholderReplacer::replace_placeholders(
infcx,
mapped_regions,
mapped_types,
mapped_consts,
&self.universes,
result,
))
let folded_ty = ty.try_super_fold_with(self)?;
let ty::Alias(alias_ty) = folded_ty.kind() else { return Ok(folded_ty) };

let result = if alias_ty.has_escaping_bound_vars() {
let (alias_ty, mapped_regions, mapped_types, mapped_consts) =
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, alias_ty);
match ensure_sufficient_stack(|| {
self.normalize_alias_term(alias_ty.into(), HasEscapingBoundVars::Yes)
})? {
Some(result) => PlaceholderReplacer::replace_placeholders(
infcx,
mapped_regions,
mapped_types,
mapped_consts,
&self.universes,
result.expect_ty(),
),
None => folded_ty,
}
} else {
Ok(ensure_sufficient_stack(|| {
self.normalize_alias_term(ty.into(), HasEscapingBoundVars::No)
})?
.expect_ty())
}
match ensure_sufficient_stack(|| {
self.normalize_alias_term(alias_ty.into(), HasEscapingBoundVars::No)
})? {
Some(term) => term.expect_ty(),
None => folded_ty,
}
};

assert!(self.cache.insert(ty, result).is_none(), "{ty:?} {result:?} {:?}", self.cache);
Ok(result)
}

#[instrument(level = "trace", skip(self), ret)]
Expand All @@ -215,28 +229,41 @@ where
// With eager normalization, we should normalize the args of alias before
// normalizing the alias itself.
let ct = ct.try_super_fold_with(self)?;
let ty::ConstKind::Unevaluated(..) = ct.kind() else { return Ok(ct) };
let ty::ConstKind::Unevaluated(uv) = ct.kind() else { return Ok(ct) };

if ct.has_escaping_bound_vars() {
let (ct, mapped_regions, mapped_types, mapped_consts) =
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, ct);
let result = ensure_sufficient_stack(|| {
self.normalize_alias_term(ct.into(), HasEscapingBoundVars::Yes)
})?
.expect_const();
Ok(PlaceholderReplacer::replace_placeholders(
infcx,
mapped_regions,
mapped_types,
mapped_consts,
&self.universes,
result,
))
let (uv, mapped_regions, mapped_types, mapped_consts) =
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, uv);
match ensure_sufficient_stack(|| {
self.normalize_alias_term(
AliasTerm::from_unevaluated_const(infcx.cx(), uv),
HasEscapingBoundVars::Yes,
)
})? {
Some(result) => Ok(PlaceholderReplacer::replace_placeholders(
infcx,
mapped_regions,
mapped_types,
mapped_consts,
&self.universes,
result.expect_const(),
)),
None => Ok(ct),
}
} else {
Ok(ensure_sufficient_stack(|| {
self.normalize_alias_term(ct.into(), HasEscapingBoundVars::No)
})?
.expect_const())
match ensure_sufficient_stack(|| {
self.normalize_alias_term(
AliasTerm::from_unevaluated_const(infcx.cx(), uv),
HasEscapingBoundVars::No,
)
})? {
Some(term) => Ok(term.expect_const()),
None => Ok(ct),
}
}
}

fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::Error> {
if p.allow_normalization() { p.try_super_fold_with(self) } else { Ok(p) }
}
}
4 changes: 2 additions & 2 deletions compiler/rustc_next_trait_solver/src/solve/alias_relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ where
self.add_goal(
GoalSource::TypeRelating,
goal.with(cx, ty::NormalizesTo { alias, term }),
);
)?;
term
} else {
lhs
Expand All @@ -65,7 +65,7 @@ where
self.add_goal(
GoalSource::TypeRelating,
goal.with(cx, ty::NormalizesTo { alias, term }),
);
)?;
term
} else {
rhs
Expand Down
Loading
Loading