Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/next_solver/util.rs')
-rw-r--r--crates/hir-ty/src/next_solver/util.rs475
1 files changed, 57 insertions, 418 deletions
diff --git a/crates/hir-ty/src/next_solver/util.rs b/crates/hir-ty/src/next_solver/util.rs
index a7f9817f9c..972c8e2da7 100644
--- a/crates/hir-ty/src/next_solver/util.rs
+++ b/crates/hir-ty/src/next_solver/util.rs
@@ -1,50 +1,31 @@
//! Various utilities for the next-trait-solver.
-use std::iter;
-use std::ops::{self, ControlFlow};
-
-use base_db::Crate;
-use hir_def::lang_item::LangItem;
-use hir_def::{BlockId, HasModule, ItemContainerId, Lookup};
-use intern::sym;
-use la_arena::Idx;
+use std::ops::ControlFlow;
+
+use hir_def::TraitId;
use rustc_abi::{Float, HasDataLayout, Integer, IntegerType, Primitive, ReprOptions};
-use rustc_type_ir::data_structures::IndexMap;
-use rustc_type_ir::inherent::{
- AdtDef, Const as _, GenericArg as _, GenericArgs as _, ParamEnv as _, Region as _, SliceLike,
- Ty as _,
-};
-use rustc_type_ir::lang_items::SolverTraitLangItem;
-use rustc_type_ir::solve::SizedTraitKind;
-use rustc_type_ir::{
- BoundVar, Canonical, DebruijnIndex, GenericArgKind, INNERMOST, Interner, PredicatePolarity,
- TypeFlags, TypeVisitable, TypeVisitableExt,
-};
use rustc_type_ir::{
- ConstKind, CoroutineArgs, FloatTy, IntTy, RegionKind, TypeFolder, TypeSuperFoldable,
- TypeSuperVisitable, TypeVisitor, UintTy, UniverseIndex, inherent::IntoKind,
+ ConstKind, CoroutineArgs, DebruijnIndex, FloatTy, INNERMOST, IntTy, Interner,
+ PredicatePolarity, RegionKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable,
+ TypeVisitableExt, TypeVisitor, UintTy, UniverseIndex, elaborate,
+ inherent::{AdtDef, GenericArg as _, IntoKind, ParamEnv as _, SliceLike, Ty as _},
+ lang_items::SolverTraitLangItem,
+ solve::SizedTraitKind,
};
-use rustc_type_ir::{InferCtxtLike, TypeFoldable};
-use crate::lower_nextsolver::{LifetimeElisionKind, TyLoweringContext};
-use crate::next_solver::infer::InferCtxt;
use crate::next_solver::{
- BoundConst, CanonicalVarKind, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst,
- PlaceholderRegion, TypingMode,
-};
-use crate::{
- db::HirDatabase,
- from_foreign_def_id,
- method_resolution::{TraitImpls, TyFingerprint},
+ BoundConst, FxIndexMap, ParamEnv, Placeholder, PlaceholderConst, PlaceholderRegion,
+ PolyTraitRef,
+ infer::{
+ InferCtxt,
+ traits::{Obligation, ObligationCause, PredicateObligation},
+ },
};
-use super::fold::{BoundVarReplacer, FnMutDelegate};
-use super::generics::generics;
use super::{
- AliasTerm, AliasTy, Binder, BoundRegion, BoundTy, BoundTyKind, BoundVarKind, BoundVarKinds,
- CanonicalVars, Clause, ClauseKind, Clauses, Const, DbInterner, EarlyBinder, GenericArg,
- GenericArgs, Predicate, PredicateKind, ProjectionPredicate, Region, SolverContext, SolverDefId,
- Term, TraitPredicate, TraitRef, Ty, TyKind,
+ Binder, BoundRegion, BoundTy, Clause, ClauseKind, Const, DbInterner, EarlyBinder, GenericArgs,
+ Predicate, PredicateKind, Region, SolverDefId, Ty, TyKind,
+ fold::{BoundVarReplacer, FnMutDelegate},
};
#[derive(Clone, Debug)]
@@ -398,54 +379,6 @@ where
}
}
-pub(crate) fn for_trait_impls(
- db: &dyn HirDatabase,
- krate: Crate,
- block: Option<BlockId>,
- trait_id: hir_def::TraitId,
- self_ty_fp: Option<TyFingerprint>,
- mut f: impl FnMut(&TraitImpls) -> ControlFlow<()>,
-) -> ControlFlow<()> {
- // Note: Since we're using `impls_for_trait` and `impl_provided_for`,
- // only impls where the trait can be resolved should ever reach Chalk.
- // `impl_datum` relies on that and will panic if the trait can't be resolved.
- let in_self_and_deps = db.trait_impls_in_deps(krate);
- let trait_module = trait_id.module(db);
- let type_module = match self_ty_fp {
- Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(db)),
- Some(TyFingerprint::ForeignType(type_id)) => Some(from_foreign_def_id(type_id).module(db)),
- Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(db)),
- _ => None,
- };
-
- let mut def_blocks =
- [trait_module.containing_block(), type_module.and_then(|it| it.containing_block())];
-
- let block_impls = iter::successors(block, |&block_id| {
- cov_mark::hit!(block_local_impls);
- block_id.loc(db).module.containing_block()
- })
- .inspect(|&block_id| {
- // make sure we don't search the same block twice
- def_blocks.iter_mut().for_each(|block| {
- if *block == Some(block_id) {
- *block = None;
- }
- });
- })
- .filter_map(|block_id| db.trait_impls_in_block(block_id));
- for it in in_self_and_deps.iter().map(ops::Deref::deref) {
- f(it)?;
- }
- for it in block_impls {
- f(&it)?;
- }
- for it in def_blocks.into_iter().flatten().filter_map(|it| db.trait_impls_in_block(it)) {
- f(&it)?;
- }
- ControlFlow::Continue(())
-}
-
// FIXME(next-trait-solver): uplift
pub fn sizedness_constraint_for_ty<'db>(
interner: DbInterner<'db>,
@@ -486,7 +419,7 @@ pub fn sizedness_constraint_for_ty<'db>(
Tuple(tys) => tys
.into_iter()
- .last()
+ .next_back()
.and_then(|ty| sizedness_constraint_for_ty(interner, sizedness, ty)),
Adt(adt, args) => {
@@ -514,322 +447,17 @@ pub fn apply_args_to_binder<'db, T: TypeFoldable<DbInterner<'db>>>(
b.skip_binder().fold_with(&mut instantiate)
}
-pub(crate) fn mini_canonicalize<'db, T: TypeFoldable<DbInterner<'db>>>(
- mut context: SolverContext<'db>,
- val: T,
-) -> Canonical<DbInterner<'db>, T> {
- let mut canon = MiniCanonicalizer {
- context: &mut context,
- db: DebruijnIndex::ZERO,
- vars: IndexMap::default(),
- };
- let canon_val = val.fold_with(&mut canon);
- let vars = canon.vars;
- Canonical {
- value: canon_val,
- max_universe: UniverseIndex::from_u32(1),
- variables: CanonicalVars::new_from_iter(
- context.cx(),
- vars.iter().enumerate().map(|(idx, (k, v))| match (*k).kind() {
- GenericArgKind::Type(ty) => match ty.kind() {
- TyKind::Int(..) | TyKind::Uint(..) => rustc_type_ir::CanonicalVarKind::Int,
- TyKind::Float(..) => rustc_type_ir::CanonicalVarKind::Float,
- _ => rustc_type_ir::CanonicalVarKind::Ty {
- ui: UniverseIndex::ZERO,
- sub_root: BoundVar::from_usize(idx),
- },
- },
- GenericArgKind::Lifetime(_) => {
- rustc_type_ir::CanonicalVarKind::Region(UniverseIndex::ZERO)
- }
- GenericArgKind::Const(_) => {
- rustc_type_ir::CanonicalVarKind::Const(UniverseIndex::ZERO)
- }
- }),
- ),
- }
-}
-
-struct MiniCanonicalizer<'a, 'db> {
- context: &'a mut SolverContext<'db>,
- db: DebruijnIndex,
- vars: IndexMap<GenericArg<'db>, usize>,
-}
-
-impl<'db> TypeFolder<DbInterner<'db>> for MiniCanonicalizer<'_, 'db> {
- fn cx(&self) -> DbInterner<'db> {
- self.context.cx()
- }
-
- fn fold_binder<T: TypeFoldable<DbInterner<'db>>>(
- &mut self,
- t: rustc_type_ir::Binder<DbInterner<'db>, T>,
- ) -> rustc_type_ir::Binder<DbInterner<'db>, T> {
- self.db.shift_in(1);
- let res = t.map_bound(|t| t.fold_with(self));
- self.db.shift_out(1);
- res
- }
-
- fn fold_ty(&mut self, t: Ty<'db>) -> Ty<'db> {
- match t.kind() {
- rustc_type_ir::TyKind::Bound(db, _) => {
- if db >= self.db {
- panic!("Unexpected bound var");
- }
- t
- }
- rustc_type_ir::TyKind::Infer(infer) => {
- let t = match infer {
- rustc_type_ir::InferTy::TyVar(vid) => {
- self.context.opportunistic_resolve_ty_var(vid)
- }
- rustc_type_ir::InferTy::IntVar(vid) => {
- self.context.opportunistic_resolve_int_var(vid)
- }
- rustc_type_ir::InferTy::FloatVar(vid) => {
- self.context.opportunistic_resolve_float_var(vid)
- }
- _ => t,
- };
- let len = self.vars.len();
- let var = *self.vars.entry(t.into()).or_insert(len);
- Ty::new(
- self.cx(),
- TyKind::Bound(
- self.db,
- BoundTy { kind: super::BoundTyKind::Anon, var: BoundVar::from_usize(var) },
- ),
- )
- }
- _ => t.super_fold_with(self),
- }
- }
-
- fn fold_region(
- &mut self,
- r: <DbInterner<'db> as rustc_type_ir::Interner>::Region,
- ) -> <DbInterner<'db> as rustc_type_ir::Interner>::Region {
- match r.kind() {
- RegionKind::ReBound(db, _) => {
- if db >= self.db {
- panic!("Unexpected bound var");
- }
- r
- }
- RegionKind::ReVar(vid) => {
- let len = self.vars.len();
- let var = *self.vars.entry(r.into()).or_insert(len);
- Region::new(
- self.cx(),
- RegionKind::ReBound(
- self.db,
- BoundRegion {
- kind: super::BoundRegionKind::Anon,
- var: BoundVar::from_usize(var),
- },
- ),
- )
- }
- _ => r,
- }
- }
-
- fn fold_const(
- &mut self,
- c: <DbInterner<'db> as rustc_type_ir::Interner>::Const,
- ) -> <DbInterner<'db> as rustc_type_ir::Interner>::Const {
- match c.kind() {
- ConstKind::Bound(db, _) => {
- if db >= self.db {
- panic!("Unexpected bound var");
- }
- c
- }
- ConstKind::Infer(infer) => {
- let len = self.vars.len();
- let var = *self.vars.entry(c.into()).or_insert(len);
- Const::new(
- self.cx(),
- ConstKind::Bound(self.db, BoundConst { var: BoundVar::from_usize(var) }),
- )
- }
- _ => c.super_fold_with(self),
- }
- }
-}
-
pub fn explicit_item_bounds<'db>(
interner: DbInterner<'db>,
def_id: SolverDefId,
-) -> EarlyBinder<'db, Clauses<'db>> {
+) -> EarlyBinder<'db, impl DoubleEndedIterator<Item = Clause<'db>> + ExactSizeIterator> {
let db = interner.db();
- match def_id {
- SolverDefId::TypeAliasId(type_alias) => {
- let trait_ = match type_alias.lookup(db).container {
- ItemContainerId::TraitId(t) => t,
- _ => panic!("associated type not in trait"),
- };
-
- // Lower bounds -- we could/should maybe move this to a separate query in `lower`
- let type_alias_data = db.type_alias_signature(type_alias);
- let generic_params = generics(db, type_alias.into());
- let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db);
- let mut ctx = TyLoweringContext::new(
- db,
- &resolver,
- &type_alias_data.store,
- type_alias.into(),
- LifetimeElisionKind::AnonymousReportError,
- );
-
- let item_args = GenericArgs::identity_for_item(interner, def_id);
- let interner_ty = Ty::new_projection_from_args(interner, def_id, item_args);
-
- let mut bounds = Vec::new();
- for bound in &type_alias_data.bounds {
- ctx.lower_type_bound(bound, interner_ty, false).for_each(|pred| {
- bounds.push(pred);
- });
- }
-
- if !ctx.unsized_types.contains(&interner_ty) {
- let sized_trait = LangItem::Sized
- .resolve_trait(ctx.db, interner.krate.expect("Must have interner.krate"));
- let sized_bound = sized_trait.map(|trait_id| {
- let trait_ref = TraitRef::new_from_args(
- interner,
- trait_id.into(),
- GenericArgs::new_from_iter(interner, [interner_ty.into()]),
- );
- Clause(Predicate::new(
- interner,
- Binder::dummy(rustc_type_ir::PredicateKind::Clause(
- rustc_type_ir::ClauseKind::Trait(TraitPredicate {
- trait_ref,
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- }),
- )),
- ))
- });
- bounds.extend(sized_bound);
- bounds.shrink_to_fit();
- }
-
- rustc_type_ir::EarlyBinder::bind(Clauses::new_from_iter(interner, bounds))
- }
- SolverDefId::InternedOpaqueTyId(id) => {
- let full_id = db.lookup_intern_impl_trait_id(id);
- match full_id {
- crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
- let datas = db
- .return_type_impl_traits_ns(func)
- .expect("impl trait id without impl traits");
- let datas = (*datas).as_ref().skip_binder();
- let data = &datas.impl_traits[Idx::from_raw(idx.into_raw())];
- EarlyBinder::bind(Clauses::new_from_iter(interner, data.predicates.clone()))
- }
- crate::ImplTraitId::TypeAliasImplTrait(alias, idx) => {
- let datas = db
- .type_alias_impl_traits_ns(alias)
- .expect("impl trait id without impl traits");
- let datas = (*datas).as_ref().skip_binder();
- let data = &datas.impl_traits[Idx::from_raw(idx.into_raw())];
- EarlyBinder::bind(Clauses::new_from_iter(interner, data.predicates.clone()))
- }
- crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
- if let Some((future_trait, future_output)) = LangItem::Future
- .resolve_trait(db, interner.krate.expect("Must have interner.krate"))
- .and_then(|trait_| {
- let alias = trait_.trait_items(db).associated_type_by_name(
- &hir_expand::name::Name::new_symbol_root(sym::Output.clone()),
- )?;
- Some((trait_, alias))
- })
- {
- let args = GenericArgs::identity_for_item(interner, def_id);
- let out = args.as_slice()[0];
- let mut predicates = vec![];
-
- let item_ty = Ty::new_alias(
- interner,
- rustc_type_ir::AliasTyKind::Opaque,
- AliasTy::new_from_args(interner, def_id, args),
- );
-
- let kind = PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- trait_ref: TraitRef::new_from_args(
- interner,
- future_trait.into(),
- GenericArgs::new_from_iter(interner, [item_ty.into()]),
- ),
- }));
- predicates.push(Clause(Predicate::new(
- interner,
- Binder::bind_with_vars(
- kind,
- BoundVarKinds::new_from_iter(
- interner,
- [BoundVarKind::Ty(BoundTyKind::Anon)],
- ),
- ),
- )));
- let sized_trait = LangItem::Sized
- .resolve_trait(db, interner.krate.expect("Must have interner.krate"));
- if let Some(sized_trait_) = sized_trait {
- let kind = PredicateKind::Clause(ClauseKind::Trait(TraitPredicate {
- polarity: rustc_type_ir::PredicatePolarity::Positive,
- trait_ref: TraitRef::new_from_args(
- interner,
- sized_trait_.into(),
- GenericArgs::new_from_iter(interner, [item_ty.into()]),
- ),
- }));
- predicates.push(Clause(Predicate::new(
- interner,
- Binder::bind_with_vars(
- kind,
- BoundVarKinds::new_from_iter(
- interner,
- [BoundVarKind::Ty(BoundTyKind::Anon)],
- ),
- ),
- )));
- }
- let kind =
- PredicateKind::Clause(ClauseKind::Projection(ProjectionPredicate {
- projection_term: AliasTerm::new_from_args(
- interner,
- future_output.into(),
- GenericArgs::new_from_iter(interner, [item_ty.into()]),
- ),
- term: match out.kind() {
- GenericArgKind::Lifetime(lt) => panic!(),
- GenericArgKind::Type(ty) => Term::Ty(ty),
- GenericArgKind::Const(const_) => Term::Const(const_),
- },
- }));
- predicates.push(Clause(Predicate::new(
- interner,
- Binder::bind_with_vars(
- kind,
- BoundVarKinds::new_from_iter(
- interner,
- [BoundVarKind::Ty(BoundTyKind::Anon)],
- ),
- ),
- )));
- EarlyBinder::bind(Clauses::new_from_iter(interner, predicates))
- } else {
- // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback.
- EarlyBinder::bind(Clauses::new_from_iter(interner, []))
- }
- }
- }
- }
- _ => panic!("Unexpected GeneridDefId"),
- }
+ let clauses = match def_id {
+ SolverDefId::TypeAliasId(type_alias) => crate::lower::type_alias_bounds(db, type_alias),
+ SolverDefId::InternedOpaqueTyId(id) => id.predicates(db),
+ _ => panic!("Unexpected GenericDefId"),
+ };
+ clauses.map_bound(|clauses| clauses.iter().copied())
}
pub struct ContainsTypeErrors;
@@ -993,26 +621,6 @@ impl<'db> TypeFolder<DbInterner<'db>> for PlaceholderReplacer<'_, 'db> {
}
}
-pub(crate) fn needs_normalization<'db, T: TypeVisitable<DbInterner<'db>>>(
- infcx: &InferCtxt<'db>,
- value: &T,
-) -> bool {
- let mut flags = TypeFlags::HAS_ALIAS;
-
- // Opaques are treated as rigid outside of `TypingMode::PostAnalysis`,
- // so we can ignore those.
- match infcx.typing_mode() {
- // FIXME(#132279): We likely want to reveal opaques during post borrowck analysis
- TypingMode::Coherence
- | TypingMode::Analysis { .. }
- | TypingMode::Borrowck { .. }
- | TypingMode::PostBorrowckAnalysis { .. } => flags.remove(TypeFlags::HAS_TY_OPAQUE),
- TypingMode::PostAnalysis => {}
- }
-
- value.has_type_flags(flags)
-}
-
pub fn sizedness_fast_path<'db>(
tcx: DbInterner<'db>,
predicate: Predicate<'db>,
@@ -1062,3 +670,34 @@ pub fn sizedness_fast_path<'db>(
false
}
+
+/// Casts a trait reference into a reference to one of its super
+/// traits; returns `None` if `target_trait_def_id` is not a
+/// supertrait.
+pub(crate) fn upcast_choices<'db>(
+ interner: DbInterner<'db>,
+ source_trait_ref: PolyTraitRef<'db>,
+ target_trait_def_id: TraitId,
+) -> Vec<PolyTraitRef<'db>> {
+ if source_trait_ref.def_id().0 == target_trait_def_id {
+ return vec![source_trait_ref]; // Shortcut the most common case.
+ }
+
+ elaborate::supertraits(interner, source_trait_ref)
+ .filter(|r| r.def_id().0 == target_trait_def_id)
+ .collect()
+}
+
+#[inline]
+pub(crate) fn clauses_as_obligations<'db>(
+ clauses: impl IntoIterator<Item = Clause<'db>>,
+ cause: ObligationCause,
+ param_env: ParamEnv<'db>,
+) -> impl Iterator<Item = PredicateObligation<'db>> {
+ clauses.into_iter().map(move |clause| Obligation {
+ cause: cause.clone(),
+ param_env,
+ predicate: clause.as_predicate(),
+ recursion_depth: 0,
+ })
+}