diff options
Diffstat (limited to 'crates/hir_ty/src/autoderef.rs')
-rw-r--r-- | crates/hir_ty/src/autoderef.rs | 46 |
1 files changed, 40 insertions, 6 deletions
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs index f8e9db9ae..2c07494a9 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; |
@@ -35,6 +36,7 @@ pub(crate) fn deref( | |||
35 | krate: CrateId, | 36 | krate: CrateId, |
36 | ty: InEnvironment<&Canonical<Ty>>, | 37 | ty: InEnvironment<&Canonical<Ty>>, |
37 | ) -> Option<Canonical<Ty>> { | 38 | ) -> Option<Canonical<Ty>> { |
39 | let _p = profile::span("deref"); | ||
38 | if let Some(derefed) = builtin_deref(&ty.goal.value) { | 40 | if let Some(derefed) = builtin_deref(&ty.goal.value) { |
39 | Some(Canonical { value: derefed, binders: ty.goal.binders.clone() }) | 41 | Some(Canonical { value: derefed, binders: ty.goal.binders.clone() }) |
40 | } else { | 42 | } else { |
@@ -55,6 +57,7 @@ fn deref_by_trait( | |||
55 | krate: CrateId, | 57 | krate: CrateId, |
56 | ty: InEnvironment<&Canonical<Ty>>, | 58 | ty: InEnvironment<&Canonical<Ty>>, |
57 | ) -> Option<Canonical<Ty>> { | 59 | ) -> Option<Canonical<Ty>> { |
60 | let _p = profile::span("deref_by_trait"); | ||
58 | let deref_trait = match db.lang_item(krate, "deref".into())? { | 61 | let deref_trait = match db.lang_item(krate, "deref".into())? { |
59 | LangItemTarget::TraitId(it) => it, | 62 | LangItemTarget::TraitId(it) => it, |
60 | _ => return None, | 63 | _ => return None, |
@@ -103,7 +106,7 @@ fn deref_by_trait( | |||
103 | binders: CanonicalVarKinds::from_iter( | 106 | binders: CanonicalVarKinds::from_iter( |
104 | &Interner, | 107 | &Interner, |
105 | ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new( | 108 | ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new( |
106 | chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), | 109 | VariableKind::Ty(chalk_ir::TyVariableKind::General), |
107 | chalk_ir::UniverseIndex::ROOT, | 110 | chalk_ir::UniverseIndex::ROOT, |
108 | ))), | 111 | ))), |
109 | ), | 112 | ), |
@@ -136,7 +139,9 @@ fn deref_by_trait( | |||
136 | return None; | 139 | return None; |
137 | } | 140 | } |
138 | } | 141 | } |
139 | Some(Canonical { | 142 | // FIXME: we remove lifetime variables here since they can confuse |
143 | // the method resolution code later | ||
144 | Some(fixup_lifetime_variables(Canonical { | ||
140 | value: vars | 145 | value: vars |
141 | .value | 146 | .value |
142 | .subst | 147 | .subst |
@@ -144,7 +149,7 @@ fn deref_by_trait( | |||
144 | .assert_ty_ref(&Interner) | 149 | .assert_ty_ref(&Interner) |
145 | .clone(), | 150 | .clone(), |
146 | binders: vars.binders.clone(), | 151 | binders: vars.binders.clone(), |
147 | }) | 152 | })) |
148 | } | 153 | } |
149 | Solution::Ambig(_) => { | 154 | Solution::Ambig(_) => { |
150 | info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution); | 155 | info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution); |
@@ -152,3 +157,32 @@ fn deref_by_trait( | |||
152 | } | 157 | } |
153 | } | 158 | } |
154 | } | 159 | } |
160 | |||
161 | fn fixup_lifetime_variables<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>( | ||
162 | c: Canonical<T>, | ||
163 | ) -> Canonical<T> { | ||
164 | // Removes lifetime variables from the Canonical, replacing them by static lifetimes. | ||
165 | let mut i = 0; | ||
166 | let subst = Substitution::from_iter( | ||
167 | &Interner, | ||
168 | c.binders.iter(&Interner).map(|vk| match vk.kind { | ||
169 | VariableKind::Ty(_) => { | ||
170 | let index = i; | ||
171 | i += 1; | ||
172 | BoundVar::new(DebruijnIndex::INNERMOST, index).to_ty(&Interner).cast(&Interner) | ||
173 | } | ||
174 | VariableKind::Lifetime => static_lifetime().cast(&Interner), | ||
175 | VariableKind::Const(_) => unimplemented!(), | ||
176 | }), | ||
177 | ); | ||
178 | let binders = CanonicalVarKinds::from_iter( | ||
179 | &Interner, | ||
180 | c.binders.iter(&Interner).filter(|vk| match vk.kind { | ||
181 | VariableKind::Ty(_) => true, | ||
182 | VariableKind::Lifetime => false, | ||
183 | VariableKind::Const(_) => true, | ||
184 | }), | ||
185 | ); | ||
186 | let value = subst.apply(c.value, &Interner); | ||
187 | Canonical { binders, value } | ||
188 | } | ||