Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/cast.rs')
-rw-r--r--crates/hir-ty/src/infer/cast.rs351
1 files changed, 171 insertions, 180 deletions
diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs
index 4cd6144a14..00a1dfff6d 100644
--- a/crates/hir-ty/src/infer/cast.rs
+++ b/crates/hir-ty/src/infer/cast.rs
@@ -1,17 +1,18 @@
//! Type cast logic. Basically coercion + additional casts.
-use chalk_ir::{Mutability, Scalar, TyVariableKind, UintTy};
use hir_def::{AdtId, hir::ExprId, signatures::TraitFlags};
+use rustc_ast_ir::Mutability;
+use rustc_type_ir::{
+ Flags, InferTy, TypeFlags, UintTy,
+ inherent::{AdtDef, BoundExistentialPredicates as _, IntoKind, SliceLike, Ty as _},
+};
use stdx::never;
-use crate::infer::coerce::CoerceNever;
use crate::{
- Binders, DynTy, InferenceDiagnostic, Interner, PlaceholderIndex, QuantifiedWhereClauses, Ty,
- TyExt, TyKind, TypeFlags, WhereClause,
+ InferenceDiagnostic,
db::HirDatabase,
- from_chalk_trait_id,
- infer::{AllowTwoPhase, InferenceContext},
- next_solver::mapping::ChalkToNextSolver,
+ infer::{AllowTwoPhase, InferenceContext, expr::ExprIsRead},
+ next_solver::{BoundExistentialPredicates, DbInterner, ParamTy, Ty, TyKind},
};
#[derive(Debug)]
@@ -25,24 +26,24 @@ pub(crate) enum Int {
}
#[derive(Debug)]
-pub(crate) enum CastTy {
+pub(crate) enum CastTy<'db> {
Int(Int),
Float,
FnPtr,
- Ptr(Ty, Mutability),
+ Ptr(Ty<'db>, Mutability),
// `DynStar` is Not supported yet in r-a
}
-impl CastTy {
- pub(crate) fn from_ty(db: &dyn HirDatabase, t: &Ty) -> Option<Self> {
- match t.kind(Interner) {
- TyKind::Scalar(Scalar::Bool) => Some(Self::Int(Int::Bool)),
- TyKind::Scalar(Scalar::Char) => Some(Self::Int(Int::Char)),
- TyKind::Scalar(Scalar::Int(_)) => Some(Self::Int(Int::I)),
- TyKind::Scalar(Scalar::Uint(it)) => Some(Self::Int(Int::U(*it))),
- TyKind::InferenceVar(_, TyVariableKind::Integer) => Some(Self::Int(Int::InferenceVar)),
- TyKind::InferenceVar(_, TyVariableKind::Float) => Some(Self::Float),
- TyKind::Scalar(Scalar::Float(_)) => Some(Self::Float),
+impl<'db> CastTy<'db> {
+ pub(crate) fn from_ty(db: &dyn HirDatabase, t: Ty<'db>) -> Option<Self> {
+ match t.kind() {
+ TyKind::Bool => Some(Self::Int(Int::Bool)),
+ TyKind::Char => Some(Self::Int(Int::Char)),
+ TyKind::Int(_) => Some(Self::Int(Int::I)),
+ TyKind::Uint(it) => Some(Self::Int(Int::U(it))),
+ TyKind::Infer(InferTy::IntVar(_)) => Some(Self::Int(Int::InferenceVar)),
+ TyKind::Infer(InferTy::FloatVar(_)) => Some(Self::Float),
+ TyKind::Float(_) => Some(Self::Float),
TyKind::Adt(..) => {
let (AdtId::EnumId(id), _) = t.as_adt()? else {
return None;
@@ -50,8 +51,8 @@ impl CastTy {
let enum_data = id.enum_variants(db);
if enum_data.is_payload_free(db) { Some(Self::Int(Int::CEnum)) } else { None }
}
- TyKind::Raw(m, ty) => Some(Self::Ptr(ty.clone(), *m)),
- TyKind::Function(_) => Some(Self::FnPtr),
+ TyKind::RawPtr(ty, m) => Some(Self::Ptr(ty, m)),
+ TyKind::FnPtr(..) => Some(Self::FnPtr),
_ => None,
}
}
@@ -77,39 +78,49 @@ pub enum CastError {
}
impl CastError {
- fn into_diagnostic(self, expr: ExprId, expr_ty: Ty, cast_ty: Ty) -> InferenceDiagnostic {
+ fn into_diagnostic<'db>(
+ self,
+ expr: ExprId,
+ expr_ty: Ty<'db>,
+ cast_ty: Ty<'db>,
+ ) -> InferenceDiagnostic<'db> {
InferenceDiagnostic::InvalidCast { expr, error: self, expr_ty, cast_ty }
}
}
#[derive(Clone, Debug)]
-pub(super) struct CastCheck {
+pub(super) struct CastCheck<'db> {
expr: ExprId,
source_expr: ExprId,
- expr_ty: Ty,
- cast_ty: Ty,
+ expr_ty: Ty<'db>,
+ cast_ty: Ty<'db>,
}
-impl CastCheck {
- pub(super) fn new(expr: ExprId, source_expr: ExprId, expr_ty: Ty, cast_ty: Ty) -> Self {
+impl<'db> CastCheck<'db> {
+ pub(super) fn new(
+ expr: ExprId,
+ source_expr: ExprId,
+ expr_ty: Ty<'db>,
+ cast_ty: Ty<'db>,
+ ) -> Self {
Self { expr, source_expr, expr_ty, cast_ty }
}
pub(super) fn check(
&mut self,
- ctx: &mut InferenceContext<'_>,
- ) -> Result<(), InferenceDiagnostic> {
- self.expr_ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(self.expr_ty.clone());
- self.cast_ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(self.cast_ty.clone());
+ ctx: &mut InferenceContext<'_, 'db>,
+ ) -> Result<(), InferenceDiagnostic<'db>> {
+ self.expr_ty = ctx.table.try_structurally_resolve_type(self.expr_ty);
+ self.cast_ty = ctx.table.try_structurally_resolve_type(self.cast_ty);
// This should always come first so that we apply the coercion, which impacts infer vars.
if ctx
.coerce(
self.source_expr.into(),
- self.expr_ty.to_nextsolver(ctx.table.interner),
- self.cast_ty.to_nextsolver(ctx.table.interner),
+ self.expr_ty,
+ self.cast_ty,
AllowTwoPhase::No,
- CoerceNever::Yes,
+ ExprIsRead::Yes,
)
.is_ok()
{
@@ -117,83 +128,82 @@ impl CastCheck {
return Ok(());
}
- if self.expr_ty.contains_unknown() || self.cast_ty.contains_unknown() {
+ if self.expr_ty.references_non_lt_error() || self.cast_ty.references_non_lt_error() {
return Ok(());
}
- if !self.cast_ty.data(Interner).flags.contains(TypeFlags::HAS_TY_INFER)
- && !ctx.table.is_sized(&self.cast_ty)
+ if !self.cast_ty.flags().contains(TypeFlags::HAS_TY_INFER)
+ && !ctx.table.is_sized(self.cast_ty)
{
return Err(InferenceDiagnostic::CastToUnsized {
expr: self.expr,
- cast_ty: self.cast_ty.clone(),
+ cast_ty: self.cast_ty,
});
}
// Chalk doesn't support trait upcasting and fails to solve some obvious goals
// when the trait environment contains some recursive traits (See issue #18047)
// We skip cast checks for such cases for now, until the next-gen solver.
- if contains_dyn_trait(&self.cast_ty) {
+ if contains_dyn_trait(self.cast_ty) {
return Ok(());
}
- self.do_check(ctx)
- .map_err(|e| e.into_diagnostic(self.expr, self.expr_ty.clone(), self.cast_ty.clone()))
+ self.do_check(ctx).map_err(|e| e.into_diagnostic(self.expr, self.expr_ty, self.cast_ty))
}
- fn do_check(&self, ctx: &mut InferenceContext<'_>) -> Result<(), CastError> {
- let (t_from, t_cast) = match (
- CastTy::from_ty(ctx.db, &self.expr_ty),
- CastTy::from_ty(ctx.db, &self.cast_ty),
- ) {
- (Some(t_from), Some(t_cast)) => (t_from, t_cast),
- (None, Some(t_cast)) => match self.expr_ty.kind(Interner) {
- TyKind::FnDef(..) => {
- let sig = self.expr_ty.callable_sig(ctx.db).expect("FnDef had no sig");
- let sig = ctx.table.eagerly_normalize_and_resolve_shallow_in(sig);
- let fn_ptr = TyKind::Function(sig.to_fn_ptr()).intern(Interner);
- if ctx
- .coerce(
- self.source_expr.into(),
- self.expr_ty.to_nextsolver(ctx.table.interner),
- fn_ptr.to_nextsolver(ctx.table.interner),
- AllowTwoPhase::No,
- CoerceNever::Yes,
- )
- .is_ok()
- {
- } else {
- return Err(CastError::IllegalCast);
- }
+ fn do_check(&self, ctx: &mut InferenceContext<'_, 'db>) -> Result<(), CastError> {
+ let (t_from, t_cast) =
+ match (CastTy::from_ty(ctx.db, self.expr_ty), CastTy::from_ty(ctx.db, self.cast_ty)) {
+ (Some(t_from), Some(t_cast)) => (t_from, t_cast),
+ (None, Some(t_cast)) => match self.expr_ty.kind() {
+ TyKind::FnDef(..) => {
+ let sig =
+ self.expr_ty.callable_sig(ctx.interner()).expect("FnDef had no sig");
+ let sig = ctx.table.normalize_associated_types_in(sig);
+ let fn_ptr = Ty::new_fn_ptr(ctx.interner(), sig);
+ if ctx
+ .coerce(
+ self.source_expr.into(),
+ self.expr_ty,
+ fn_ptr,
+ AllowTwoPhase::No,
+ ExprIsRead::Yes,
+ )
+ .is_ok()
+ {
+ } else {
+ return Err(CastError::IllegalCast);
+ }
- (CastTy::FnPtr, t_cast)
- }
- TyKind::Ref(mutbl, _, inner_ty) => {
- return match t_cast {
- CastTy::Int(_) | CastTy::Float => match inner_ty.kind(Interner) {
- TyKind::Scalar(Scalar::Int(_) | Scalar::Uint(_) | Scalar::Float(_))
- | TyKind::InferenceVar(
- _,
- TyVariableKind::Integer | TyVariableKind::Float,
- ) => Err(CastError::NeedDeref),
-
- _ => Err(CastError::NeedViaPtr),
- },
- // array-ptr-cast
- CastTy::Ptr(t, m) => {
- let t = ctx.table.eagerly_normalize_and_resolve_shallow_in(t);
- if !ctx.table.is_sized(&t) {
- return Err(CastError::IllegalCast);
+ (CastTy::FnPtr, t_cast)
+ }
+ TyKind::Ref(_, inner_ty, mutbl) => {
+ return match t_cast {
+ CastTy::Int(_) | CastTy::Float => match inner_ty.kind() {
+ TyKind::Int(_)
+ | TyKind::Uint(_)
+ | TyKind::Float(_)
+ | TyKind::Infer(InferTy::IntVar(_) | InferTy::FloatVar(_)) => {
+ Err(CastError::NeedDeref)
+ }
+
+ _ => Err(CastError::NeedViaPtr),
+ },
+ // array-ptr-cast
+ CastTy::Ptr(t, m) => {
+ let t = ctx.table.try_structurally_resolve_type(t);
+ if !ctx.table.is_sized(t) {
+ return Err(CastError::IllegalCast);
+ }
+ self.check_ref_cast(ctx, inner_ty, mutbl, t, m)
}
- self.check_ref_cast(ctx, inner_ty, *mutbl, &t, m)
- }
- _ => Err(CastError::NonScalar),
- };
- }
+ _ => Err(CastError::NonScalar),
+ };
+ }
+ _ => return Err(CastError::NonScalar),
+ },
_ => return Err(CastError::NonScalar),
- },
- _ => return Err(CastError::NonScalar),
- };
+ };
// rustc checks whether the `expr_ty` is foreign adt with `non_exhaustive` sym
@@ -207,10 +217,10 @@ impl CastCheck {
}
(CastTy::Int(Int::Bool | Int::CEnum | Int::Char) | CastTy::Float, CastTy::Ptr(..))
| (CastTy::Ptr(..) | CastTy::FnPtr, CastTy::Float) => Err(CastError::IllegalCast),
- (CastTy::Ptr(src, _), CastTy::Ptr(dst, _)) => self.check_ptr_ptr_cast(ctx, &src, &dst),
- (CastTy::Ptr(src, _), CastTy::Int(_)) => self.check_ptr_addr_cast(ctx, &src),
- (CastTy::Int(_), CastTy::Ptr(dst, _)) => self.check_addr_ptr_cast(ctx, &dst),
- (CastTy::FnPtr, CastTy::Ptr(dst, _)) => self.check_fptr_ptr_cast(ctx, &dst),
+ (CastTy::Ptr(src, _), CastTy::Ptr(dst, _)) => self.check_ptr_ptr_cast(ctx, src, dst),
+ (CastTy::Ptr(src, _), CastTy::Int(_)) => self.check_ptr_addr_cast(ctx, src),
+ (CastTy::Int(_), CastTy::Ptr(dst, _)) => self.check_addr_ptr_cast(ctx, dst),
+ (CastTy::FnPtr, CastTy::Ptr(dst, _)) => self.check_fptr_ptr_cast(ctx, dst),
(CastTy::Int(Int::CEnum), CastTy::Int(_)) => Ok(()),
(CastTy::Int(Int::Char | Int::Bool), CastTy::Int(_)) => Ok(()),
(CastTy::Int(_) | CastTy::Float, CastTy::Int(_) | CastTy::Float) => Ok(()),
@@ -220,25 +230,25 @@ impl CastCheck {
fn check_ref_cast(
&self,
- ctx: &mut InferenceContext<'_>,
- t_expr: &Ty,
+ ctx: &mut InferenceContext<'_, 'db>,
+ t_expr: Ty<'db>,
m_expr: Mutability,
- t_cast: &Ty,
+ t_cast: Ty<'db>,
m_cast: Mutability,
) -> Result<(), CastError> {
// Mutability order is opposite to rustc. `Mut < Not`
if m_expr <= m_cast
- && let TyKind::Array(ety, _) = t_expr.kind(Interner)
+ && let TyKind::Array(ety, _) = t_expr.kind()
{
// Coerce to a raw pointer so that we generate RawPtr in MIR.
- let array_ptr_type = TyKind::Raw(m_expr, t_expr.clone()).intern(Interner);
+ let array_ptr_type = Ty::new_ptr(ctx.interner(), t_expr, m_expr);
if ctx
.coerce(
self.source_expr.into(),
- self.expr_ty.to_nextsolver(ctx.table.interner),
- array_ptr_type.to_nextsolver(ctx.table.interner),
+ self.expr_ty,
+ array_ptr_type,
AllowTwoPhase::No,
- CoerceNever::Yes,
+ ExprIsRead::Yes,
)
.is_ok()
{
@@ -253,13 +263,7 @@ impl CastCheck {
// This is a less strict condition than rustc's `demand_eqtype`,
// but false negative is better than false positive
if ctx
- .coerce(
- self.source_expr.into(),
- ety.to_nextsolver(ctx.table.interner),
- t_cast.to_nextsolver(ctx.table.interner),
- AllowTwoPhase::No,
- CoerceNever::Yes,
- )
+ .coerce(self.source_expr.into(), ety, t_cast, AllowTwoPhase::No, ExprIsRead::Yes)
.is_ok()
{
return Ok(());
@@ -271,9 +275,9 @@ impl CastCheck {
fn check_ptr_ptr_cast(
&self,
- ctx: &mut InferenceContext<'_>,
- src: &Ty,
- dst: &Ty,
+ ctx: &mut InferenceContext<'_, 'db>,
+ src: Ty<'db>,
+ dst: Ty<'db>,
) -> Result<(), CastError> {
let src_kind = pointer_kind(src, ctx).map_err(|_| CastError::Unknown)?;
let dst_kind = pointer_kind(dst, ctx).map_err(|_| CastError::Unknown)?;
@@ -286,24 +290,13 @@ impl CastCheck {
(_, Some(PointerKind::Thin)) => Ok(()),
(Some(PointerKind::Thin), _) => Err(CastError::SizedUnsizedCast),
(Some(PointerKind::VTable(src_tty)), Some(PointerKind::VTable(dst_tty))) => {
- let principal = |tty: &Binders<QuantifiedWhereClauses>| {
- tty.skip_binders().as_slice(Interner).first().and_then(|pred| {
- if let WhereClause::Implemented(tr) = pred.skip_binders() {
- Some(tr.trait_id)
- } else {
- None
- }
- })
- };
- match (principal(&src_tty), principal(&dst_tty)) {
+ match (src_tty.principal_def_id(), dst_tty.principal_def_id()) {
(Some(src_principal), Some(dst_principal)) => {
if src_principal == dst_principal {
return Ok(());
}
- let src_principal =
- ctx.db.trait_signature(from_chalk_trait_id(src_principal));
- let dst_principal =
- ctx.db.trait_signature(from_chalk_trait_id(dst_principal));
+ let src_principal = ctx.db.trait_signature(src_principal.0);
+ let dst_principal = ctx.db.trait_signature(dst_principal.0);
if src_principal.flags.contains(TraitFlags::AUTO)
&& dst_principal.flags.contains(TraitFlags::AUTO)
{
@@ -322,8 +315,8 @@ impl CastCheck {
fn check_ptr_addr_cast(
&self,
- ctx: &mut InferenceContext<'_>,
- expr_ty: &Ty,
+ ctx: &mut InferenceContext<'_, 'db>,
+ expr_ty: Ty<'db>,
) -> Result<(), CastError> {
match pointer_kind(expr_ty, ctx).map_err(|_| CastError::Unknown)? {
// None => Err(CastError::UnknownExprPtrKind),
@@ -336,8 +329,8 @@ impl CastCheck {
fn check_addr_ptr_cast(
&self,
- ctx: &mut InferenceContext<'_>,
- cast_ty: &Ty,
+ ctx: &mut InferenceContext<'_, 'db>,
+ cast_ty: Ty<'db>,
) -> Result<(), CastError> {
match pointer_kind(cast_ty, ctx).map_err(|_| CastError::Unknown)? {
// None => Err(CastError::UnknownCastPtrKind),
@@ -352,8 +345,8 @@ impl CastCheck {
fn check_fptr_ptr_cast(
&self,
- ctx: &mut InferenceContext<'_>,
- cast_ty: &Ty,
+ ctx: &mut InferenceContext<'_, 'db>,
+ cast_ty: Ty<'db>,
) -> Result<(), CastError> {
match pointer_kind(cast_ty, ctx).map_err(|_| CastError::Unknown)? {
// None => Err(CastError::UnknownCastPtrKind),
@@ -366,30 +359,34 @@ impl CastCheck {
}
#[derive(Debug, PartialEq, Eq)]
-enum PointerKind {
+enum PointerKind<'db> {
// thin pointer
Thin,
// trait object
- VTable(Binders<QuantifiedWhereClauses>),
+ VTable(BoundExistentialPredicates<'db>),
// slice
Length,
OfAlias,
- OfParam(PlaceholderIndex),
+ OfParam(ParamTy),
Error,
}
-fn pointer_kind(ty: &Ty, ctx: &mut InferenceContext<'_>) -> Result<Option<PointerKind>, ()> {
- let ty = ctx.table.eagerly_normalize_and_resolve_shallow_in(ty.clone());
+fn pointer_kind<'db>(
+ ty: Ty<'db>,
+ ctx: &mut InferenceContext<'_, 'db>,
+) -> Result<Option<PointerKind<'db>>, ()> {
+ let ty = ctx.table.try_structurally_resolve_type(ty);
- if ctx.table.is_sized(&ty) {
+ if ctx.table.is_sized(ty) {
return Ok(Some(PointerKind::Thin));
}
- match ty.kind(Interner) {
+ match ty.kind() {
TyKind::Slice(_) | TyKind::Str => Ok(Some(PointerKind::Length)),
- TyKind::Dyn(DynTy { bounds, .. }) => Ok(Some(PointerKind::VTable(bounds.clone()))),
- TyKind::Adt(chalk_ir::AdtId(id), subst) => {
- let AdtId::StructId(id) = *id else {
+ TyKind::Dynamic(bounds, _) => Ok(Some(PointerKind::VTable(bounds))),
+ TyKind::Adt(adt_def, subst) => {
+ let id = adt_def.def_id().0;
+ let AdtId::StructId(id) = id else {
never!("`{:?}` should be sized but is not?", ty);
return Err(());
};
@@ -397,69 +394,63 @@ fn pointer_kind(ty: &Ty, ctx: &mut InferenceContext<'_>) -> Result<Option<Pointe
let struct_data = id.fields(ctx.db);
if let Some((last_field, _)) = struct_data.fields().iter().last() {
let last_field_ty =
- ctx.db.field_types(id.into())[last_field].clone().substitute(Interner, subst);
- pointer_kind(&last_field_ty, ctx)
+ ctx.db.field_types(id.into())[last_field].instantiate(ctx.interner(), subst);
+ pointer_kind(last_field_ty, ctx)
} else {
Ok(Some(PointerKind::Thin))
}
}
- TyKind::Tuple(_, subst) => {
- match subst.iter(Interner).last().and_then(|arg| arg.ty(Interner)) {
- None => Ok(Some(PointerKind::Thin)),
- Some(ty) => pointer_kind(ty, ctx),
- }
- }
+ TyKind::Tuple(subst) => match subst.iter().next_back() {
+ None => Ok(Some(PointerKind::Thin)),
+ Some(ty) => pointer_kind(ty, ctx),
+ },
TyKind::Foreign(_) => Ok(Some(PointerKind::Thin)),
- TyKind::Alias(_) | TyKind::AssociatedType(..) | TyKind::OpaqueType(..) => {
- Ok(Some(PointerKind::OfAlias))
- }
- TyKind::Error => Ok(Some(PointerKind::Error)),
- TyKind::Placeholder(idx) => Ok(Some(PointerKind::OfParam(*idx))),
- TyKind::BoundVar(_) | TyKind::InferenceVar(..) => Ok(None),
- TyKind::Scalar(_)
+ TyKind::Alias(..) => Ok(Some(PointerKind::OfAlias)),
+ TyKind::Error(_) => Ok(Some(PointerKind::Error)),
+ TyKind::Param(idx) => Ok(Some(PointerKind::OfParam(idx))),
+ TyKind::Bound(..) | TyKind::Placeholder(..) | TyKind::Infer(..) => Ok(None),
+ TyKind::Int(_)
+ | TyKind::Uint(_)
+ | TyKind::Float(_)
+ | TyKind::Bool
+ | TyKind::Char
| TyKind::Array(..)
| TyKind::CoroutineWitness(..)
- | TyKind::Raw(..)
+ | TyKind::RawPtr(..)
| TyKind::Ref(..)
| TyKind::FnDef(..)
- | TyKind::Function(_)
+ | TyKind::FnPtr(..)
| TyKind::Closure(..)
| TyKind::Coroutine(..)
+ | TyKind::CoroutineClosure(..)
| TyKind::Never => {
never!("`{:?}` should be sized but is not?", ty);
Err(())
}
+ TyKind::UnsafeBinder(..) | TyKind::Pat(..) => {
+ never!("we don't produce these types: {ty:?}");
+ Err(())
+ }
}
}
-fn contains_dyn_trait(ty: &Ty) -> bool {
+fn contains_dyn_trait<'db>(ty: Ty<'db>) -> bool {
use std::ops::ControlFlow;
- use chalk_ir::{
- DebruijnIndex,
- visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
- };
+ use rustc_type_ir::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
struct DynTraitVisitor;
- impl TypeVisitor<Interner> for DynTraitVisitor {
- type BreakTy = ();
-
- fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
- self
- }
-
- fn interner(&self) -> Interner {
- Interner
- }
+ impl<'db> TypeVisitor<DbInterner<'db>> for DynTraitVisitor {
+ type Result = ControlFlow<()>;
- fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow<Self::BreakTy> {
- match ty.kind(Interner) {
- TyKind::Dyn(_) => ControlFlow::Break(()),
- _ => ty.super_visit_with(self.as_dyn(), outer_binder),
+ fn visit_ty(&mut self, ty: Ty<'db>) -> ControlFlow<()> {
+ match ty.kind() {
+ TyKind::Dynamic(..) => ControlFlow::Break(()),
+ _ => ty.super_visit_with(self),
}
}
}
- ty.visit_with(DynTraitVisitor.as_dyn(), DebruijnIndex::INNERMOST).is_break()
+ ty.visit_with(&mut DynTraitVisitor).is_break()
}