diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs index f8e9db9ae5..71bc436e6f 100644 --- a/crates/hir_ty/src/autoderef.rs +++ b/crates/hir_ty/src/autoderef.rs @@ -6,14 +6,15 @@ use std::iter::successors; use base_db::CrateId; -use chalk_ir::cast::Cast; +use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind}; use hir_def::lang_item::LangItemTarget; use hir_expand::name::name; use log::{info, warn}; use crate::{ - db::HirDatabase, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, - InEnvironment, Interner, ProjectionTyExt, Solution, Ty, TyBuilder, TyKind, + db::HirDatabase, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, + DebruijnIndex, InEnvironment, Interner, ProjectionTyExt, Solution, Substitution, Ty, TyBuilder, + TyKind, }; const AUTODEREF_RECURSION_LIMIT: usize = 10; @@ -103,7 +104,7 @@ fn deref_by_trait( binders: CanonicalVarKinds::from_iter( &Interner, ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new( - chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), + VariableKind::Ty(chalk_ir::TyVariableKind::General), chalk_ir::UniverseIndex::ROOT, ))), ), @@ -136,7 +137,9 @@ fn deref_by_trait( return None; } } - Some(Canonical { + // FIXME: we remove lifetime variables here since they can confuse + // the method resolution code later + Some(fixup_lifetime_variables(Canonical { value: vars .value .subst @@ -144,7 +147,7 @@ fn deref_by_trait( .assert_ty_ref(&Interner) .clone(), binders: vars.binders.clone(), - }) + })) } Solution::Ambig(_) => { info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution); @@ -152,3 +155,32 @@ fn deref_by_trait( } } } + +fn fixup_lifetime_variables + HasInterner>( + c: Canonical, +) -> Canonical { + // Removes lifetime variables from the Canonical, replacing them by static lifetimes. + let mut i = 0; + let subst = Substitution::from_iter( + &Interner, + c.binders.iter(&Interner).map(|vk| match vk.kind { + VariableKind::Ty(_) => { + let index = i; + i += 1; + BoundVar::new(DebruijnIndex::INNERMOST, index).to_ty(&Interner).cast(&Interner) + } + VariableKind::Lifetime => static_lifetime().cast(&Interner), + VariableKind::Const(_) => unimplemented!(), + }), + ); + let binders = CanonicalVarKinds::from_iter( + &Interner, + c.binders.iter(&Interner).filter(|vk| match vk.kind { + VariableKind::Ty(_) => true, + VariableKind::Lifetime => false, + VariableKind::Const(_) => true, + }), + ); + let value = subst.apply(c.value, &Interner); + Canonical { binders, value } +} diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index be3e4f09ab..1b60cb7279 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs @@ -609,6 +609,7 @@ fn iterate_trait_method_candidates( } } known_implemented = true; + // FIXME: we shouldn't be ignoring the binders here if callback(&self_ty.value, *item) { return true; } diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs index b69f860502..9cd9f473d7 100644 --- a/crates/hir_ty/src/tests/regression.rs +++ b/crates/hir_ty/src/tests/regression.rs @@ -974,3 +974,41 @@ fn param_overrides_fn() { "#, ) } + +#[test] +fn lifetime_from_chalk_during_deref() { + check_types( + r#" + #[lang = "deref"] + pub trait Deref { + type Target; + } + + struct Box {} + impl Deref for Box { + type Target = T; + + fn deref(&self) -> &Self::Target { + loop {} + } + } + + trait Iterator { + type Item; + } + + pub struct Iter<'a, T: 'a> { + inner: Box + 'a>, + } + + trait IterTrait<'a, T: 'a>: Iterator { + fn clone_box(&self); + } + + fn clone_iter(s: Iter) { + s.inner.clone_box(); + //^^^^^^^^^^^^^^^^^^^ () + } + "#, + ) +}