Convert more of dyn_compatibility to next-solver

This commit is contained in:
jackh726 2025-08-12 06:07:02 +00:00
parent 064f1c7c83
commit d10e5d10fe
2 changed files with 130 additions and 153 deletions

View file

@ -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 rustc_type_ir::{
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 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b
// 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 @@ fn bounds_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool {
.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 @@ enum AllowSelfProjection {
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 @@ where
}
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 @@ where
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;
}

View file

@ -62,9 +62,10 @@ use crate::{
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 @@ fn fn_sig_for_enum_variant_constructor<'db>(
}))
}
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>,