aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2021-04-08 22:34:05 +0100
committerFlorian Diebold <[email protected]>2021-04-09 10:17:07 +0100
commit272a8dce4f603b38e7755bcd2dc8abb6437e6e64 (patch)
tree664e370487dae360665746ab32986b87e65b22a6
parent354151df3556c5e2989746aa01a5aeb620ee9baa (diff)
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.
-rw-r--r--crates/hir_ty/src/autoderef.rs44
-rw-r--r--crates/hir_ty/src/method_resolution.rs1
-rw-r--r--crates/hir_ty/src/tests/regression.rs38
3 files changed, 77 insertions, 6 deletions
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 @@
6use std::iter::successors; 6use std::iter::successors;
7 7
8use base_db::CrateId; 8use base_db::CrateId;
9use chalk_ir::cast::Cast; 9use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind};
10use hir_def::lang_item::LangItemTarget; 10use hir_def::lang_item::LangItemTarget;
11use hir_expand::name::name; 11use hir_expand::name::name;
12use log::{info, warn}; 12use log::{info, warn};
13 13
14use crate::{ 14use crate::{
15 db::HirDatabase, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, 15 db::HirDatabase, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
16 InEnvironment, Interner, ProjectionTyExt, Solution, Ty, TyBuilder, TyKind, 16 DebruijnIndex, InEnvironment, Interner, ProjectionTyExt, Solution, Substitution, Ty, TyBuilder,
17 TyKind,
17}; 18};
18 19
19const AUTODEREF_RECURSION_LIMIT: usize = 10; 20const AUTODEREF_RECURSION_LIMIT: usize = 10;
@@ -103,7 +104,7 @@ fn deref_by_trait(
103 binders: CanonicalVarKinds::from_iter( 104 binders: CanonicalVarKinds::from_iter(
104 &Interner, 105 &Interner,
105 ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new( 106 ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new(
106 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), 107 VariableKind::Ty(chalk_ir::TyVariableKind::General),
107 chalk_ir::UniverseIndex::ROOT, 108 chalk_ir::UniverseIndex::ROOT,
108 ))), 109 ))),
109 ), 110 ),
@@ -136,7 +137,9 @@ fn deref_by_trait(
136 return None; 137 return None;
137 } 138 }
138 } 139 }
139 Some(Canonical { 140 // FIXME: we remove lifetime variables here since they can confuse
141 // the method resolution code later
142 Some(fixup_lifetime_variables(Canonical {
140 value: vars 143 value: vars
141 .value 144 .value
142 .subst 145 .subst
@@ -144,7 +147,7 @@ fn deref_by_trait(
144 .assert_ty_ref(&Interner) 147 .assert_ty_ref(&Interner)
145 .clone(), 148 .clone(),
146 binders: vars.binders.clone(), 149 binders: vars.binders.clone(),
147 }) 150 }))
148 } 151 }
149 Solution::Ambig(_) => { 152 Solution::Ambig(_) => {
150 info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution); 153 info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution);
@@ -152,3 +155,32 @@ fn deref_by_trait(
152 } 155 }
153 } 156 }
154} 157}
158
159fn fixup_lifetime_variables<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
160 c: Canonical<T>,
161) -> Canonical<T> {
162 // Removes lifetime variables from the Canonical, replacing them by static lifetimes.
163 let mut i = 0;
164 let subst = Substitution::from_iter(
165 &Interner,
166 c.binders.iter(&Interner).map(|vk| match vk.kind {
167 VariableKind::Ty(_) => {
168 let index = i;
169 i += 1;
170 BoundVar::new(DebruijnIndex::INNERMOST, index).to_ty(&Interner).cast(&Interner)
171 }
172 VariableKind::Lifetime => static_lifetime().cast(&Interner),
173 VariableKind::Const(_) => unimplemented!(),
174 }),
175 );
176 let binders = CanonicalVarKinds::from_iter(
177 &Interner,
178 c.binders.iter(&Interner).filter(|vk| match vk.kind {
179 VariableKind::Ty(_) => true,
180 VariableKind::Lifetime => false,
181 VariableKind::Const(_) => true,
182 }),
183 );
184 let value = subst.apply(c.value, &Interner);
185 Canonical { binders, value }
186}
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(
609 } 609 }
610 } 610 }
611 known_implemented = true; 611 known_implemented = true;
612 // FIXME: we shouldn't be ignoring the binders here
612 if callback(&self_ty.value, *item) { 613 if callback(&self_ty.value, *item) {
613 return true; 614 return true;
614 } 615 }
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() {
974 "#, 974 "#,
975 ) 975 )
976} 976}
977
978#[test]
979fn lifetime_from_chalk_during_deref() {
980 check_types(
981 r#"
982 #[lang = "deref"]
983 pub trait Deref {
984 type Target;
985 }
986
987 struct Box<T: ?Sized> {}
988 impl<T> Deref for Box<T> {
989 type Target = T;
990
991 fn deref(&self) -> &Self::Target {
992 loop {}
993 }
994 }
995
996 trait Iterator {
997 type Item;
998 }
999
1000 pub struct Iter<'a, T: 'a> {
1001 inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>,
1002 }
1003
1004 trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> {
1005 fn clone_box(&self);
1006 }
1007
1008 fn clone_iter<T>(s: Iter<T>) {
1009 s.inner.clone_box();
1010 //^^^^^^^^^^^^^^^^^^^ ()
1011 }
1012 "#,
1013 )
1014}