Convert more of dyn_compatibility to next-solver
This commit is contained in:
parent
064f1c7c83
commit
d10e5d10fe
2 changed files with 130 additions and 153 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue