Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/autoderef.rs')
-rw-r--r--crates/hir-ty/src/autoderef.rs45
1 files changed, 33 insertions, 12 deletions
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index 2b5342314a..62feca5f8c 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -17,7 +17,7 @@ use crate::{
TraitEnvironment, Ty, TyBuilder, TyKind,
};
-static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);
+static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(20);
#[derive(Debug)]
pub(crate) enum AutoderefKind {
@@ -39,7 +39,7 @@ pub fn autoderef(
) -> impl Iterator<Item = Ty> {
let mut table = InferenceTable::new(db, env);
let ty = table.instantiate_canonical(ty);
- let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false);
+ let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false, false);
let mut v = Vec::new();
while let Some((ty, _steps)) = autoderef.next() {
// `ty` may contain unresolved inference variables. Since there's no chance they would be
@@ -49,7 +49,7 @@ pub fn autoderef(
// If the deref chain contains a cycle (e.g. `A` derefs to `B` and `B` derefs to `A`), we
// would revisit some already visited types. Stop here to avoid duplication.
//
- // XXX: The recursion limit for `Autoderef` is currently 10, so `Vec::contains()` shouldn't
+ // XXX: The recursion limit for `Autoderef` is currently 20, so `Vec::contains()` shouldn't
// be too expensive. Replace this duplicate check with `FxHashSet` if it proves to be more
// performant.
if v.contains(&resolved) {
@@ -89,12 +89,18 @@ pub(crate) struct Autoderef<'table, 'db, T = Vec<(AutoderefKind, Ty)>> {
at_start: bool,
steps: T,
explicit: bool,
+ use_receiver_trait: bool,
}
impl<'table, 'db> Autoderef<'table, 'db> {
- pub(crate) fn new(table: &'table mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self {
+ pub(crate) fn new(
+ table: &'table mut InferenceTable<'db>,
+ ty: Ty,
+ explicit: bool,
+ use_receiver_trait: bool,
+ ) -> Self {
let ty = table.resolve_ty_shallow(&ty);
- Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit }
+ Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit, use_receiver_trait }
}
pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] {
@@ -107,9 +113,10 @@ impl<'table, 'db> Autoderef<'table, 'db, usize> {
table: &'table mut InferenceTable<'db>,
ty: Ty,
explicit: bool,
+ use_receiver_trait: bool,
) -> Self {
let ty = table.resolve_ty_shallow(&ty);
- Autoderef { table, ty, at_start: true, steps: 0, explicit }
+ Autoderef { table, ty, at_start: true, steps: 0, explicit, use_receiver_trait }
}
}
@@ -137,7 +144,8 @@ impl<T: TrackAutoderefSteps> Iterator for Autoderef<'_, '_, T> {
return None;
}
- let (kind, new_ty) = autoderef_step(self.table, self.ty.clone(), self.explicit)?;
+ let (kind, new_ty) =
+ autoderef_step(self.table, self.ty.clone(), self.explicit, self.use_receiver_trait)?;
self.steps.push(kind, &self.ty);
self.ty = new_ty;
@@ -150,11 +158,12 @@ pub(crate) fn autoderef_step(
table: &mut InferenceTable<'_>,
ty: Ty,
explicit: bool,
+ use_receiver_trait: bool,
) -> Option<(AutoderefKind, Ty)> {
if let Some(derefed) = builtin_deref(table.db, &ty, explicit) {
Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
} else {
- Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
+ Some((AutoderefKind::Overloaded, deref_by_trait(table, ty, use_receiver_trait)?))
}
}
@@ -176,6 +185,7 @@ pub(crate) fn builtin_deref<'ty>(
pub(crate) fn deref_by_trait(
table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>,
ty: Ty,
+ use_receiver_trait: bool,
) -> Option<Ty> {
let _p = tracing::info_span!("deref_by_trait").entered();
if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() {
@@ -183,14 +193,25 @@ pub(crate) fn deref_by_trait(
return None;
}
- let deref_trait =
- db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?;
+ let trait_id = || {
+ if use_receiver_trait {
+ if let Some(receiver) =
+ db.lang_item(table.trait_env.krate, LangItem::Receiver).and_then(|l| l.as_trait())
+ {
+ return Some(receiver);
+ }
+ }
+ // Old rustc versions might not have `Receiver` trait.
+ // Fallback to `Deref` if they don't
+ db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())
+ };
+ let trait_id = trait_id()?;
let target = db
- .trait_data(deref_trait)
+ .trait_data(trait_id)
.associated_type_by_name(&Name::new_symbol_root(sym::Target.clone()))?;
let projection = {
- let b = TyBuilder::subst_for_def(db, deref_trait, None);
+ let b = TyBuilder::subst_for_def(db, trait_id, None);
if b.remaining() != 1 {
// the Target type + Deref trait should only have one generic parameter,
// namely Deref's Self type