diff options
author | Florian Diebold <[email protected]> | 2021-04-08 22:34:05 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2021-04-09 10:17:07 +0100 |
commit | 272a8dce4f603b38e7755bcd2dc8abb6437e6e64 (patch) | |
tree | 664e370487dae360665746ab32986b87e65b22a6 /crates/hir_ty/src | |
parent | 354151df3556c5e2989746aa01a5aeb620ee9baa (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.
Diffstat (limited to 'crates/hir_ty/src')
-rw-r--r-- | crates/hir_ty/src/autoderef.rs | 44 | ||||
-rw-r--r-- | crates/hir_ty/src/method_resolution.rs | 1 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/regression.rs | 38 |
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 @@ | |||
6 | use std::iter::successors; | 6 | use std::iter::successors; |
7 | 7 | ||
8 | use base_db::CrateId; | 8 | use base_db::CrateId; |
9 | use chalk_ir::cast::Cast; | 9 | use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind}; |
10 | use hir_def::lang_item::LangItemTarget; | 10 | use hir_def::lang_item::LangItemTarget; |
11 | use hir_expand::name::name; | 11 | use hir_expand::name::name; |
12 | use log::{info, warn}; | 12 | use log::{info, warn}; |
13 | 13 | ||
14 | use crate::{ | 14 | use 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 | ||
19 | const AUTODEREF_RECURSION_LIMIT: usize = 10; | 20 | const 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 | |||
159 | fn 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] | ||
979 | fn 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 | } | ||