Convert more of dyn_compatibility to next-solver
diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs
index 48c0c81..54d78de 100644
--- a/crates/hir-ty/src/dyn_compatibility.rs
+++ b/crates/hir-ty/src/dyn_compatibility.rs
@@ -2,11 +2,7 @@
use std::ops::ControlFlow;
-use chalk_ir::{
- DebruijnIndex,
- visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
-};
-use chalk_solve::rust_ir::InlineBound;
+use chalk_ir::DebruijnIndex;
use hir_def::{
AssocItemId, ConstId, CrateRootModuleId, FunctionId, GenericDefId, HasModule, TraitId,
TypeAliasId, lang_item::LangItem, signatures::TraitFlags,
@@ -21,14 +17,14 @@
use smallvec::SmallVec;
use crate::{
- AliasEq, AliasTy, Binders, BoundVar, ImplTraitId, Interner, ProjectionTyExt, Ty, TyKind,
- WhereClause, all_super_traits,
+ ImplTraitId, Interner, TyKind, WhereClause, all_super_traits,
db::{HirDatabase, InternedOpaqueTyId},
- from_assoc_type_id, from_chalk_trait_id,
+ from_chalk_trait_id,
generics::trait_self_param_idx,
+ lower_nextsolver::associated_ty_item_bounds,
next_solver::{
- Clauses, DbInterner, GenericArgs, ParamEnv, SolverDefId, TraitPredicate, TypingMode,
- infer::DbInternerInferExt, mk_param,
+ Clause, Clauses, DbInterner, GenericArgs, ParamEnv, SolverDefId, TraitPredicate,
+ TypingMode, infer::DbInternerInferExt, mk_param,
},
traits::next_trait_solve_in_ctxt,
utils::elaborate_clause_supertraits,
@@ -165,7 +161,7 @@
// but we don't have good way to render such locations.
// So, just return single boolean value for existence of such `Self` reference
fn predicates_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool {
- db.generic_predicates(trait_.into())
+ db.generic_predicates_ns(trait_.into())
.iter()
.any(|pred| predicate_references_self(db, trait_, pred, AllowSelfProjection::No))
}
@@ -177,37 +173,18 @@
.items
.iter()
.filter_map(|(_, it)| match *it {
- AssocItemId::TypeAliasId(id) => {
- let assoc_ty_data = db.associated_ty_data(id);
- Some(assoc_ty_data)
- }
+ AssocItemId::TypeAliasId(id) => Some(associated_ty_item_bounds(db, id)),
_ => None,
})
- .any(|assoc_ty_data| {
- assoc_ty_data.binders.skip_binders().bounds.iter().any(|bound| {
- let def = from_assoc_type_id(assoc_ty_data.id).into();
- match bound.skip_binders() {
- InlineBound::TraitBound(it) => it.args_no_self.iter().any(|arg| {
- contains_illegal_self_type_reference(
- db,
- def,
- trait_,
- arg,
- DebruijnIndex::ONE,
- AllowSelfProjection::Yes,
- )
- }),
- InlineBound::AliasEqBound(it) => it.parameters.iter().any(|arg| {
- contains_illegal_self_type_reference(
- db,
- def,
- trait_,
- arg,
- DebruijnIndex::ONE,
- AllowSelfProjection::Yes,
- )
- }),
- }
+ .any(|bounds| {
+ bounds.skip_binder().iter().any(|pred| match pred.skip_binder() {
+ rustc_type_ir::ExistentialPredicate::Trait(it) => it.args.iter().any(|arg| {
+ contains_illegal_self_type_reference(db, trait_, &arg, AllowSelfProjection::Yes)
+ }),
+ rustc_type_ir::ExistentialPredicate::Projection(it) => it.args.iter().any(|arg| {
+ contains_illegal_self_type_reference(db, trait_, &arg, AllowSelfProjection::Yes)
+ }),
+ rustc_type_ir::ExistentialPredicate::AutoTrait(_) => false,
})
})
}
@@ -218,120 +195,26 @@
No,
}
-fn predicate_references_self(
- db: &dyn HirDatabase,
+fn predicate_references_self<'db>(
+ db: &'db dyn HirDatabase,
trait_: TraitId,
- predicate: &Binders<Binders<WhereClause>>,
+ predicate: &Clause<'db>,
allow_self_projection: AllowSelfProjection,
) -> bool {
- match predicate.skip_binders().skip_binders() {
- WhereClause::Implemented(trait_ref) => {
- trait_ref.substitution.iter(Interner).skip(1).any(|arg| {
- contains_illegal_self_type_reference(
- db,
- trait_.into(),
- trait_,
- arg,
- DebruijnIndex::ONE,
- allow_self_projection,
- )
- })
- }
- WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(proj), .. }) => {
- proj.substitution.iter(Interner).skip(1).any(|arg| {
- contains_illegal_self_type_reference(
- db,
- trait_.into(),
- trait_,
- arg,
- DebruijnIndex::ONE,
- allow_self_projection,
- )
+ match predicate.kind().skip_binder() {
+ ClauseKind::Trait(trait_pred) => trait_pred.trait_ref.args.iter().skip(1).any(|arg| {
+ contains_illegal_self_type_reference(db, trait_, &arg, allow_self_projection)
+ }),
+ ClauseKind::Projection(proj_pred) => {
+ proj_pred.projection_term.args.iter().skip(1).any(|arg| {
+ contains_illegal_self_type_reference(db, trait_, &arg, allow_self_projection)
})
}
_ => false,
}
}
-fn contains_illegal_self_type_reference<T: TypeVisitable<Interner>>(
- db: &dyn HirDatabase,
- def: GenericDefId,
- trait_: TraitId,
- t: &T,
- outer_binder: DebruijnIndex,
- allow_self_projection: AllowSelfProjection,
-) -> bool {
- let Some(trait_self_param_idx) = trait_self_param_idx(db, def) else {
- return false;
- };
- struct IllegalSelfTypeVisitor<'a> {
- db: &'a dyn HirDatabase,
- trait_: TraitId,
- super_traits: Option<SmallVec<[TraitId; 4]>>,
- trait_self_param_idx: usize,
- allow_self_projection: AllowSelfProjection,
- }
- impl TypeVisitor<Interner> for IllegalSelfTypeVisitor<'_> {
- type BreakTy = ();
-
- fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
- self
- }
-
- fn interner(&self) -> Interner {
- Interner
- }
-
- fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow<Self::BreakTy> {
- match ty.kind(Interner) {
- TyKind::BoundVar(BoundVar { debruijn, index }) => {
- if *debruijn == outer_binder && *index == self.trait_self_param_idx {
- ControlFlow::Break(())
- } else {
- ty.super_visit_with(self.as_dyn(), outer_binder)
- }
- }
- TyKind::Alias(AliasTy::Projection(proj)) => match self.allow_self_projection {
- AllowSelfProjection::Yes => {
- let trait_ = proj.trait_(self.db);
- if self.super_traits.is_none() {
- self.super_traits = Some(all_super_traits(self.db, self.trait_));
- }
- if self.super_traits.as_ref().is_some_and(|s| s.contains(&trait_)) {
- ControlFlow::Continue(())
- } else {
- ty.super_visit_with(self.as_dyn(), outer_binder)
- }
- }
- AllowSelfProjection::No => ty.super_visit_with(self.as_dyn(), outer_binder),
- },
- _ => ty.super_visit_with(self.as_dyn(), outer_binder),
- }
- }
-
- fn visit_const(
- &mut self,
- constant: &chalk_ir::Const<Interner>,
- outer_binder: DebruijnIndex,
- ) -> std::ops::ControlFlow<Self::BreakTy> {
- constant.data(Interner).ty.super_visit_with(self.as_dyn(), outer_binder)
- }
- }
-
- let mut visitor = IllegalSelfTypeVisitor {
- db,
- trait_,
- super_traits: None,
- trait_self_param_idx,
- allow_self_projection,
- };
- t.visit_with(visitor.as_dyn(), outer_binder).is_break()
-}
-
-fn contains_illegal_self_type_reference_ns<
- 'db,
- T: rustc_type_ir::TypeVisitable<DbInterner<'db>>,
->(
+fn contains_illegal_self_type_reference<'db, T: rustc_type_ir::TypeVisitable<DbInterner<'db>>>(
db: &'db dyn HirDatabase,
trait_: TraitId,
t: &T,
@@ -440,13 +323,17 @@
}
let sig = db.callable_item_signature_ns(func.into());
- if sig.skip_binder().inputs().iter().skip(1).any(|ty| {
- contains_illegal_self_type_reference_ns(db, trait_, &ty, AllowSelfProjection::Yes)
- }) {
+ if sig
+ .skip_binder()
+ .inputs()
+ .iter()
+ .skip(1)
+ .any(|ty| contains_illegal_self_type_reference(db, trait_, &ty, AllowSelfProjection::Yes))
+ {
cb(MethodViolationCode::ReferencesSelfInput)?;
}
- if contains_illegal_self_type_reference_ns(
+ if contains_illegal_self_type_reference(
db,
trait_,
&sig.skip_binder().output(),
@@ -496,7 +383,7 @@
continue;
}
- if contains_illegal_self_type_reference_ns(db, trait_, &pred, AllowSelfProjection::Yes) {
+ if contains_illegal_self_type_reference(db, trait_, &pred, AllowSelfProjection::Yes) {
cb(MethodViolationCode::WhereClauseReferencesSelf)?;
break;
}
diff --git a/crates/hir-ty/src/lower_nextsolver.rs b/crates/hir-ty/src/lower_nextsolver.rs
index 15c675b..2777869 100644
--- a/crates/hir-ty/src/lower_nextsolver.rs
+++ b/crates/hir-ty/src/lower_nextsolver.rs
@@ -62,9 +62,10 @@
lower::{Diagnostics, PathDiagnosticCallbackData, create_diagnostics},
next_solver::{
AdtDef, AliasTy, Binder, BoundExistentialPredicates, BoundRegionKind, BoundTyKind,
- BoundVarKind, BoundVarKinds, Clause, Const, DbInterner, EarlyBinder, EarlyParamRegion,
- ErrorGuaranteed, GenericArgs, PolyFnSig, Predicate, Region, SolverDefId, TraitPredicate,
- TraitRef, Ty, Tys, abi::Safety, generics::GenericParamDefKind, mapping::ChalkToNextSolver,
+ BoundVarKind, BoundVarKinds, Clause, Clauses, Const, DbInterner, EarlyBinder,
+ EarlyParamRegion, ErrorGuaranteed, GenericArgs, PolyFnSig, Predicate, Region, SolverDefId,
+ TraitPredicate, TraitRef, Ty, Tys, abi::Safety, generics::GenericParamDefKind,
+ mapping::ChalkToNextSolver,
},
};
@@ -1593,6 +1594,95 @@
}))
}
+pub(crate) fn associated_ty_item_bounds<'db>(
+ db: &'db dyn HirDatabase,
+ type_alias: TypeAliasId,
+) -> EarlyBinder<'db, BoundExistentialPredicates<'db>> {
+ let trait_ = match type_alias.lookup(db).container {
+ ItemContainerId::TraitId(t) => t,
+ _ => panic!("associated type not in trait"),
+ };
+
+ let type_alias_data = db.type_alias_signature(type_alias);
+ let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db);
+ let interner = DbInterner::new_with(db, Some(resolver.krate()), None);
+ let mut ctx = TyLoweringContext::new(
+ db,
+ &resolver,
+ &type_alias_data.store,
+ type_alias.into(),
+ LifetimeElisionKind::AnonymousReportError,
+ );
+ // FIXME: we should never create non-existential predicates in the first place
+ // For now, use an error type so we don't run into dummy binder issues
+ let self_ty = Ty::new_error(interner, ErrorGuaranteed);
+
+ let mut bounds = Vec::new();
+ for bound in &type_alias_data.bounds {
+ ctx.lower_type_bound(bound, self_ty, false).for_each(|pred| {
+ if let Some(bound) = pred
+ .kind()
+ .map_bound(|c| match c {
+ rustc_type_ir::ClauseKind::Trait(t) => {
+ let id = t.def_id();
+ let id = match id {
+ SolverDefId::TraitId(id) => id,
+ _ => unreachable!(),
+ };
+ let is_auto = db.trait_signature(id).flags.contains(TraitFlags::AUTO);
+ if is_auto {
+ Some(ExistentialPredicate::AutoTrait(t.def_id()))
+ } else {
+ Some(ExistentialPredicate::Trait(ExistentialTraitRef::new_from_args(
+ interner,
+ t.def_id(),
+ GenericArgs::new_from_iter(
+ interner,
+ t.trait_ref.args.iter().skip(1),
+ ),
+ )))
+ }
+ }
+ rustc_type_ir::ClauseKind::Projection(p) => Some(
+ ExistentialPredicate::Projection(ExistentialProjection::new_from_args(
+ interner,
+ p.def_id(),
+ GenericArgs::new_from_iter(
+ interner,
+ p.projection_term.args.iter().skip(1),
+ ),
+ p.term,
+ )),
+ ),
+ rustc_type_ir::ClauseKind::TypeOutlives(outlives_predicate) => None,
+ rustc_type_ir::ClauseKind::RegionOutlives(_)
+ | rustc_type_ir::ClauseKind::ConstArgHasType(_, _)
+ | rustc_type_ir::ClauseKind::WellFormed(_)
+ | rustc_type_ir::ClauseKind::ConstEvaluatable(_)
+ | rustc_type_ir::ClauseKind::HostEffect(_)
+ | rustc_type_ir::ClauseKind::UnstableFeature(_) => unreachable!(),
+ })
+ .transpose()
+ {
+ bounds.push(bound);
+ }
+ });
+ }
+
+ if !ctx.unsized_types.contains(&self_ty) {
+ let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate());
+ let sized_clause = Binder::dummy(ExistentialPredicate::Trait(ExistentialTraitRef::new(
+ interner,
+ SolverDefId::TraitId(trait_),
+ [] as [crate::next_solver::GenericArg<'_>; 0],
+ )));
+ bounds.push(sized_clause);
+ bounds.shrink_to_fit();
+ }
+
+ EarlyBinder::bind(BoundExistentialPredicates::new_from_iter(interner, bounds))
+}
+
pub(crate) fn associated_type_by_name_including_super_traits<'db>(
db: &'db dyn HirDatabase,
trait_ref: TraitRef<'db>,