Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/dyn_compatibility.rs')
-rw-r--r--crates/hir-ty/src/dyn_compatibility.rs482
1 files changed, 205 insertions, 277 deletions
diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs
index 30949c83bf..437141e41d 100644
--- a/crates/hir-ty/src/dyn_compatibility.rs
+++ b/crates/hir-ty/src/dyn_compatibility.rs
@@ -2,27 +2,28 @@
use std::ops::ControlFlow;
-use chalk_ir::{
- DebruijnIndex,
- cast::Cast,
- visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
-};
-use chalk_solve::rust_ir::InlineBound;
use hir_def::{
AssocItemId, ConstId, CrateRootModuleId, FunctionId, GenericDefId, HasModule, TraitId,
- TypeAliasId, lang_item::LangItem, signatures::TraitFlags,
+ TypeAliasId, TypeOrConstParamId, TypeParamId, hir::generics::LocalTypeOrConstParamId,
+ lang_item::LangItem, signatures::TraitFlags,
};
use rustc_hash::FxHashSet;
+use rustc_type_ir::{
+ AliasTyKind, ClauseKind, PredicatePolarity, TypeSuperVisitable as _, TypeVisitable as _,
+ Upcast, elaborate,
+ inherent::{IntoKind, SliceLike},
+};
use smallvec::SmallVec;
use crate::{
- AliasEq, AliasTy, Binders, BoundVar, CallableSig, GoalData, ImplTraitId, Interner, OpaqueTyId,
- ProjectionTyExt, Solution, Substitution, TraitRef, Ty, TyKind, WhereClause, all_super_traits,
- db::HirDatabase,
- from_assoc_type_id, from_chalk_trait_id,
- generics::{generics, trait_self_param_idx},
- to_chalk_trait_id,
- utils::elaborate_clause_supertraits,
+ ImplTraitId,
+ db::{HirDatabase, InternedOpaqueTyId},
+ lower::associated_ty_item_bounds,
+ next_solver::{
+ Binder, Clause, Clauses, DbInterner, EarlyBinder, GenericArgs, Goal, ParamEnv, ParamTy,
+ SolverDefId, TraitPredicate, TraitRef, Ty, TypingMode, infer::DbInternerInferExt, mk_param,
+ },
+ traits::next_trait_solve_in_ctxt,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -52,13 +53,18 @@ pub fn dyn_compatibility(
db: &dyn HirDatabase,
trait_: TraitId,
) -> Option<DynCompatibilityViolation> {
- for super_trait in all_super_traits(db, trait_).into_iter().skip(1).rev() {
- if db.dyn_compatibility_of_trait(super_trait).is_some() {
- return Some(DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait));
+ let interner = DbInterner::new_with(db, Some(trait_.krate(db)), None);
+ for super_trait in elaborate::supertrait_def_ids(interner, trait_.into()) {
+ if let Some(v) = db.dyn_compatibility_of_trait(super_trait.0) {
+ return if super_trait.0 == trait_ {
+ Some(v)
+ } else {
+ Some(DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait.0))
+ };
}
}
- db.dyn_compatibility_of_trait(trait_)
+ None
}
pub fn dyn_compatibility_with_callback<F>(
@@ -69,8 +75,9 @@ pub fn dyn_compatibility_with_callback<F>(
where
F: FnMut(DynCompatibilityViolation) -> ControlFlow<()>,
{
- for super_trait in all_super_traits(db, trait_).into_iter().skip(1).rev() {
- if db.dyn_compatibility_of_trait(super_trait).is_some() {
+ let interner = DbInterner::new_with(db, Some(trait_.krate(db)), None);
+ for super_trait in elaborate::supertrait_def_ids(interner, trait_.into()).skip(1) {
+ if db.dyn_compatibility_of_trait(super_trait.0).is_some() {
cb(DynCompatibilityViolation::HasNonCompatibleSuperTrait(trait_))?;
}
}
@@ -128,28 +135,26 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b
return false;
};
- let Some(trait_self_param_idx) = trait_self_param_idx(db, def) else {
- return false;
- };
-
- let predicates = &*db.generic_predicates(def);
- let predicates = predicates.iter().map(|p| p.skip_binders().skip_binders().clone());
- elaborate_clause_supertraits(db, predicates).any(|pred| match pred {
- WhereClause::Implemented(trait_ref) => {
- if from_chalk_trait_id(trait_ref.trait_id) == sized {
- if let TyKind::BoundVar(it) =
- *trait_ref.self_type_parameter(Interner).kind(Interner)
+ let interner = DbInterner::new_with(db, Some(krate), None);
+ let predicates = db.generic_predicates(def);
+ // FIXME: We should use `explicit_predicates_of` here, which hasn't been implemented to
+ // rust-analyzer yet
+ // https://github.com/rust-lang/rust/blob/ddaf12390d3ffb7d5ba74491a48f3cd528e5d777/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L490
+ elaborate::elaborate(interner, predicates.iter().copied()).any(|pred| {
+ match pred.kind().skip_binder() {
+ ClauseKind::Trait(trait_pred) => {
+ if sized == trait_pred.def_id().0
+ && let rustc_type_ir::TyKind::Param(param_ty) =
+ trait_pred.trait_ref.self_ty().kind()
+ && param_ty.index == 0
{
- // Since `generic_predicates` is `Binder<Binder<..>>`, the `DebrujinIndex` of
- // self-parameter is `1`
- return it
- .index_if_bound_at(DebruijnIndex::ONE)
- .is_some_and(|idx| idx == trait_self_param_idx);
+ true
+ } else {
+ false
}
}
- false
+ _ => false,
}
- _ => false,
})
}
@@ -169,37 +174,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,
})
})
}
@@ -210,114 +196,80 @@ 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,
+fn contains_illegal_self_type_reference<'db, T: rustc_type_ir::TypeVisitable<DbInterner<'db>>>(
+ db: &'db dyn HirDatabase,
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,
+ struct IllegalSelfTypeVisitor<'db> {
+ db: &'db 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 = ();
+ impl<'db> rustc_type_ir::TypeVisitor<DbInterner<'db>> for IllegalSelfTypeVisitor<'db> {
+ type Result = ControlFlow<()>;
- 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 {
+ fn visit_ty(
+ &mut self,
+ ty: <DbInterner<'db> as rustc_type_ir::Interner>::Ty,
+ ) -> Self::Result {
+ let interner = DbInterner::new_with(self.db, None, None);
+ match ty.kind() {
+ rustc_type_ir::TyKind::Param(param) if param.index == 0 => ControlFlow::Break(()),
+ rustc_type_ir::TyKind::Param(_) => ControlFlow::Continue(()),
+ rustc_type_ir::TyKind::Alias(AliasTyKind::Projection, proj) => match self
+ .allow_self_projection
+ {
AllowSelfProjection::Yes => {
- let trait_ = proj.trait_(self.db);
+ let trait_ = proj.trait_def_id(DbInterner::new_with(self.db, None, None));
+ let trait_ = match trait_ {
+ SolverDefId::TraitId(id) => id,
+ _ => unreachable!(),
+ };
if self.super_traits.is_none() {
- self.super_traits = Some(all_super_traits(self.db, self.trait_));
+ self.super_traits = Some(
+ elaborate::supertrait_def_ids(interner, self.trait_.into())
+ .map(|super_trait| super_trait.0)
+ .collect(),
+ )
}
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)
+ ty.super_visit_with(self)
}
}
- AllowSelfProjection::No => ty.super_visit_with(self.as_dyn(), outer_binder),
+ AllowSelfProjection::No => ty.super_visit_with(self),
},
- _ => ty.super_visit_with(self.as_dyn(), outer_binder),
+ _ => ty.super_visit_with(self),
}
}
-
- 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()
+ let mut visitor =
+ IllegalSelfTypeVisitor { db, trait_, super_traits: None, allow_self_projection };
+ t.visit_with(&mut visitor).is_break()
}
fn dyn_compatibility_violation_for_assoc_item<F>(
@@ -377,34 +329,29 @@ where
}
let sig = db.callable_item_signature(func.into());
- if sig.skip_binders().params().iter().skip(1).any(|ty| {
- contains_illegal_self_type_reference(
- db,
- func.into(),
- trait_,
- ty,
- DebruijnIndex::INNERMOST,
- 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(
db,
- func.into(),
trait_,
- sig.skip_binders().ret(),
- DebruijnIndex::INNERMOST,
+ &sig.skip_binder().output(),
AllowSelfProjection::Yes,
) {
cb(MethodViolationCode::ReferencesSelfOutput)?;
}
- if !func_data.is_async() {
- if let Some(mvc) = contains_illegal_impl_trait_in_trait(db, &sig) {
- cb(mvc)?;
- }
+ if !func_data.is_async()
+ && let Some(mvc) = contains_illegal_impl_trait_in_trait(db, &sig)
+ {
+ cb(mvc)?;
}
let generic_params = db.generic_params(func.into());
@@ -417,39 +364,27 @@ where
}
let predicates = &*db.generic_predicates_without_parent(func.into());
- let trait_self_idx = trait_self_param_idx(db, func.into());
for pred in predicates {
- let pred = pred.skip_binders().skip_binders();
+ let pred = pred.kind().skip_binder();
- if matches!(pred, WhereClause::TypeOutlives(_)) {
+ if matches!(pred, ClauseKind::TypeOutlives(_)) {
continue;
}
// Allow `impl AutoTrait` predicates
- if let WhereClause::Implemented(TraitRef { trait_id, substitution }) = pred {
- let trait_data = db.trait_signature(from_chalk_trait_id(*trait_id));
- if trait_data.flags.contains(TraitFlags::AUTO)
- && substitution
- .as_slice(Interner)
- .first()
- .and_then(|arg| arg.ty(Interner))
- .and_then(|ty| ty.bound_var(Interner))
- .is_some_and(|b| {
- b.debruijn == DebruijnIndex::ONE && Some(b.index) == trait_self_idx
- })
- {
- continue;
- }
+ if let ClauseKind::Trait(TraitPredicate {
+ trait_ref: pred_trait_ref,
+ polarity: PredicatePolarity::Positive,
+ }) = pred
+ && let trait_data = db.trait_signature(pred_trait_ref.def_id.0)
+ && trait_data.flags.contains(TraitFlags::AUTO)
+ && let rustc_type_ir::TyKind::Param(ParamTy { index: 0, .. }) =
+ pred_trait_ref.self_ty().kind()
+ {
+ continue;
}
- if contains_illegal_self_type_reference(
- db,
- func.into(),
- trait_,
- pred,
- DebruijnIndex::ONE,
- AllowSelfProjection::Yes,
- ) {
+ if contains_illegal_self_type_reference(db, trait_, &pred, AllowSelfProjection::Yes) {
cb(MethodViolationCode::WhereClauseReferencesSelf)?;
break;
}
@@ -458,34 +393,29 @@ where
ControlFlow::Continue(())
}
-fn receiver_is_dispatchable(
+fn receiver_is_dispatchable<'db>(
db: &dyn HirDatabase,
trait_: TraitId,
func: FunctionId,
- sig: &Binders<CallableSig>,
+ sig: &EarlyBinder<'db, Binder<'db, rustc_type_ir::FnSig<DbInterner<'db>>>>,
) -> bool {
- let Some(trait_self_idx) = trait_self_param_idx(db, func.into()) else {
- return false;
- };
+ let sig = sig.instantiate_identity();
+
+ let interner: DbInterner<'_> = DbInterner::new_with(db, Some(trait_.krate(db)), None);
+ let self_param_id = TypeParamId::from_unchecked(TypeOrConstParamId {
+ parent: trait_.into(),
+ local_id: LocalTypeOrConstParamId::from_raw(la_arena::RawIdx::from_u32(0)),
+ });
+ let self_param_ty =
+ Ty::new(interner, rustc_type_ir::TyKind::Param(ParamTy { index: 0, id: self_param_id }));
// `self: Self` can't be dispatched on, but this is already considered dyn-compatible
// See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437
- if sig
- .skip_binders()
- .params()
- .first()
- .and_then(|receiver| receiver.bound_var(Interner))
- .is_some_and(|b| {
- b == BoundVar { debruijn: DebruijnIndex::INNERMOST, index: trait_self_idx }
- })
- {
+ if sig.inputs().iter().next().is_some_and(|p| p.skip_binder() == self_param_ty) {
return true;
}
- let placeholder_subst = generics(db, func.into()).placeholder_subst(db);
-
- let substituted_sig = sig.clone().substitute(Interner, &placeholder_subst);
- let Some(receiver_ty) = substituted_sig.params().first() else {
+ let Some(&receiver_ty) = sig.inputs().skip_binder().as_slice().first() else {
return false;
};
@@ -498,103 +428,101 @@ fn receiver_is_dispatchable(
return false;
};
- // Type `U`
- let unsized_self_ty =
- TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::U32)).intern(Interner);
- // `Receiver[Self => U]`
- let Some(unsized_receiver_ty) = receiver_for_self_ty(db, func, unsized_self_ty.clone()) else {
+ let meta_sized_did = LangItem::MetaSized.resolve_trait(db, krate);
+ let Some(meta_sized_did) = meta_sized_did else {
return false;
};
- let self_ty = placeholder_subst.as_slice(Interner)[trait_self_idx].assert_ty_ref(Interner);
- let unsized_predicate = WhereClause::Implemented(TraitRef {
- trait_id: to_chalk_trait_id(unsize_did),
- substitution: Substitution::from_iter(Interner, [self_ty.clone(), unsized_self_ty.clone()]),
- });
- let trait_predicate = WhereClause::Implemented(TraitRef {
- trait_id: to_chalk_trait_id(trait_),
- substitution: Substitution::from_iter(
- Interner,
- std::iter::once(unsized_self_ty.cast(Interner))
- .chain(placeholder_subst.iter(Interner).skip(1).cloned()),
- ),
- });
+ // Type `U`
+ // FIXME: That seems problematic to fake a generic param like that?
+ let unsized_self_ty = Ty::new_param(interner, self_param_id, u32::MAX);
+ // `Receiver[Self => U]`
+ let unsized_receiver_ty = receiver_for_self_ty(interner, func, receiver_ty, unsized_self_ty);
- let generic_predicates = &*db.generic_predicates(func.into());
+ let param_env = {
+ let generic_predicates = &*db.generic_predicates(func.into());
- let clauses = std::iter::once(unsized_predicate)
- .chain(std::iter::once(trait_predicate))
- .chain(generic_predicates.iter().map(|pred| {
- pred.clone().substitute(Interner, &placeholder_subst).into_value_and_skipped_binders().0
- }))
- .map(|pred| {
- pred.cast::<chalk_ir::ProgramClause<Interner>>(Interner).into_from_env_clause(Interner)
- });
- let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses);
+ // Self: Unsize<U>
+ let unsize_predicate =
+ TraitRef::new(interner, unsize_did.into(), [self_param_ty, unsized_self_ty]);
- let obligation = WhereClause::Implemented(TraitRef {
- trait_id: to_chalk_trait_id(dispatch_from_dyn_did),
- substitution: Substitution::from_iter(Interner, [receiver_ty.clone(), unsized_receiver_ty]),
- });
- let goal = GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(obligation)).intern(Interner);
-
- let in_env = chalk_ir::InEnvironment::new(&env, goal);
+ // U: Trait<Arg1, ..., ArgN>
+ let args = GenericArgs::for_item(interner, trait_.into(), |index, kind, _| {
+ if index == 0 { unsized_self_ty.into() } else { mk_param(interner, index, kind) }
+ });
+ let trait_predicate = TraitRef::new_from_args(interner, trait_.into(), args);
+
+ let meta_sized_predicate =
+ TraitRef::new(interner, meta_sized_did.into(), [unsized_self_ty]);
+
+ ParamEnv {
+ clauses: Clauses::new_from_iter(
+ interner,
+ generic_predicates.iter().copied().chain([
+ unsize_predicate.upcast(interner),
+ trait_predicate.upcast(interner),
+ meta_sized_predicate.upcast(interner),
+ ]),
+ ),
+ }
+ };
- let mut table = chalk_solve::infer::InferenceTable::<Interner>::new();
- let canonicalized = table.canonicalize(Interner, in_env);
- let solution = db.trait_solve(krate, None, canonicalized.quantified);
+ // Receiver: DispatchFromDyn<Receiver[Self => U]>
+ let predicate =
+ TraitRef::new(interner, dispatch_from_dyn_did.into(), [receiver_ty, unsized_receiver_ty]);
+ let goal = Goal::new(interner, param_env, predicate);
- matches!(solution, Some(Solution::Unique(_)))
+ let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis());
+ // the receiver is dispatchable iff the obligation holds
+ let res = next_trait_solve_in_ctxt(&infcx, goal);
+ res.map_or(false, |res| matches!(res.1, rustc_type_ir::solve::Certainty::Yes))
}
-fn receiver_for_self_ty(db: &dyn HirDatabase, func: FunctionId, ty: Ty) -> Option<Ty> {
- let generics = generics(db, func.into());
- let trait_self_idx = trait_self_param_idx(db, func.into())?;
- let subst = generics.placeholder_subst(db);
- let subst = Substitution::from_iter(
- Interner,
- subst.iter(Interner).enumerate().map(|(idx, arg)| {
- if idx == trait_self_idx { ty.clone().cast(Interner) } else { arg.clone() }
- }),
- );
- let sig = db.callable_item_signature(func.into());
- let sig = sig.substitute(Interner, &subst);
- sig.params_and_return.first().cloned()
+fn receiver_for_self_ty<'db>(
+ interner: DbInterner<'db>,
+ func: FunctionId,
+ receiver_ty: Ty<'db>,
+ self_ty: Ty<'db>,
+) -> Ty<'db> {
+ let args = GenericArgs::for_item(interner, SolverDefId::FunctionId(func), |index, kind, _| {
+ if index == 0 { self_ty.into() } else { mk_param(interner, index, kind) }
+ });
+
+ EarlyBinder::bind(receiver_ty).instantiate(interner, args)
}
-fn contains_illegal_impl_trait_in_trait(
- db: &dyn HirDatabase,
- sig: &Binders<CallableSig>,
+fn contains_illegal_impl_trait_in_trait<'db>(
+ db: &'db dyn HirDatabase,
+ sig: &EarlyBinder<'db, Binder<'db, rustc_type_ir::FnSig<DbInterner<'db>>>>,
) -> Option<MethodViolationCode> {
- struct OpaqueTypeCollector(FxHashSet<OpaqueTyId>);
-
- impl TypeVisitor<Interner> for OpaqueTypeCollector {
- type BreakTy = ();
+ struct OpaqueTypeCollector(FxHashSet<InternedOpaqueTyId>);
- fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
- self
- }
-
- fn interner(&self) -> Interner {
- Interner
- }
+ impl<'db> rustc_type_ir::TypeVisitor<DbInterner<'db>> for OpaqueTypeCollector {
+ type Result = ControlFlow<()>;
- fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow<Self::BreakTy> {
- if let TyKind::OpaqueType(opaque_ty_id, _) = ty.kind(Interner) {
- self.0.insert(*opaque_ty_id);
+ fn visit_ty(
+ &mut self,
+ ty: <DbInterner<'db> as rustc_type_ir::Interner>::Ty,
+ ) -> Self::Result {
+ if let rustc_type_ir::TyKind::Alias(AliasTyKind::Opaque, op) = ty.kind() {
+ let id = match op.def_id {
+ SolverDefId::InternedOpaqueTyId(id) => id,
+ _ => unreachable!(),
+ };
+ self.0.insert(id);
}
- ty.super_visit_with(self.as_dyn(), outer_binder)
+ ty.super_visit_with(self)
}
}
- let ret = sig.skip_binders().ret();
+ let ret = sig.skip_binder().output();
let mut visitor = OpaqueTypeCollector(FxHashSet::default());
- _ = ret.visit_with(visitor.as_dyn(), DebruijnIndex::INNERMOST);
+ _ = ret.visit_with(&mut visitor);
// Since we haven't implemented RPITIT in proper way like rustc yet,
// just check whether `ret` contains RPIT for now
for opaque_ty in visitor.0 {
- let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty.into());
+ let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty);
if matches!(impl_trait_id, ImplTraitId::ReturnTypeImplTrait(..)) {
return Some(MethodViolationCode::ReferencesImplTraitInTrait);
}