From 272a8dce4f603b38e7755bcd2dc8abb6437e6e64 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Thu, 8 Apr 2021 23:34:05 +0200 Subject: Fix crash on syn involving lifetimes returned by Chalk If we get lifetime variables back in autoderef, just immediately replace them by static lifetimes for now. Method resolution doesn't really deal correctly with new variables being introduced (this needs to be fixed more properly). This fixes `rust-analyzer analysis-stats --with-deps` crashing in the RA repo. --- crates/hir_ty/src/autoderef.rs | 44 +++++++++++++++++++++++++++++----- crates/hir_ty/src/method_resolution.rs | 1 + crates/hir_ty/src/tests/regression.rs | 38 +++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 6 deletions(-) (limited to 'crates/hir_ty') diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs index f8e9db9ae..71bc436e6 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 be3e4f09a..1b60cb727 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 b69f86050..9cd9f473d 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(); + //^^^^^^^^^^^^^^^^^^^ () + } + "#, + ) +} -- cgit v1.2.3