diff options
author | Florian Diebold <[email protected]> | 2019-05-01 16:57:56 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-05-04 17:18:30 +0100 |
commit | 0ad7317b24dc90c3787482f9ec563e7830d499fc (patch) | |
tree | b065393029bb8d886c3562af2e0fbcf1bc62a0e6 /crates/ra_hir/src/ty/method_resolution.rs | |
parent | ef77d8375130d12678d4b2316cc1708c90349dad (diff) |
Canonicalize before doing method resolution
Diffstat (limited to 'crates/ra_hir/src/ty/method_resolution.rs')
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 219 |
1 files changed, 109 insertions, 110 deletions
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index ea7da0b62..bc5033be6 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -16,7 +16,7 @@ use crate::{ | |||
16 | generics::HasGenericParams, | 16 | generics::HasGenericParams, |
17 | ty::primitive::{UncertainIntTy, UncertainFloatTy} | 17 | ty::primitive::{UncertainIntTy, UncertainFloatTy} |
18 | }; | 18 | }; |
19 | use super::{TraitRef, infer::Canonical, Substs}; | 19 | use super::{TraitRef, Canonical}; |
20 | 20 | ||
21 | /// This is used as a key for indexing impls. | 21 | /// This is used as a key for indexing impls. |
22 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 22 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
@@ -130,132 +130,123 @@ fn def_crate(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option<Crate> | |||
130 | } | 130 | } |
131 | } | 131 | } |
132 | 132 | ||
133 | impl Ty { | 133 | /// Look up the method with the given name, returning the actual autoderefed |
134 | /// Look up the method with the given name, returning the actual autoderefed | 134 | /// receiver type (but without autoref applied yet). |
135 | /// receiver type (but without autoref applied yet). | 135 | pub(crate) fn lookup_method( |
136 | pub(crate) fn lookup_method( | 136 | ty: &Canonical<Ty>, |
137 | self, | 137 | db: &impl HirDatabase, |
138 | db: &impl HirDatabase, | 138 | name: &Name, |
139 | name: &Name, | 139 | resolver: &Resolver, |
140 | resolver: &Resolver, | 140 | ) -> Option<(Ty, Function)> { |
141 | ) -> Option<(Ty, Function)> { | 141 | iterate_method_candidates(ty, db, resolver, Some(name), |ty, f| Some((ty.clone(), f))) |
142 | self.iterate_method_candidates(db, resolver, Some(name), |ty, f| Some((ty.clone(), f))) | 142 | } |
143 | } | ||
144 | 143 | ||
145 | // This would be nicer if it just returned an iterator, but that runs into | 144 | // This would be nicer if it just returned an iterator, but that runs into |
146 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. | 145 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. |
147 | pub(crate) fn iterate_method_candidates<T>( | 146 | pub(crate) fn iterate_method_candidates<T>( |
148 | self, | 147 | ty: &Canonical<Ty>, |
149 | db: &impl HirDatabase, | 148 | db: &impl HirDatabase, |
150 | resolver: &Resolver, | 149 | resolver: &Resolver, |
151 | name: Option<&Name>, | 150 | name: Option<&Name>, |
152 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 151 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
153 | ) -> Option<T> { | 152 | ) -> Option<T> { |
154 | // For method calls, rust first does any number of autoderef, and then one | 153 | // For method calls, rust first does any number of autoderef, and then one |
155 | // autoref (i.e. when the method takes &self or &mut self). We just ignore | 154 | // autoref (i.e. when the method takes &self or &mut self). We just ignore |
156 | // the autoref currently -- when we find a method matching the given name, | 155 | // the autoref currently -- when we find a method matching the given name, |
157 | // we assume it fits. | 156 | // we assume it fits. |
158 | 157 | ||
159 | // Also note that when we've got a receiver like &S, even if the method we | 158 | // Also note that when we've got a receiver like &S, even if the method we |
160 | // find in the end takes &self, we still do the autoderef step (just as | 159 | // find in the end takes &self, we still do the autoderef step (just as |
161 | // rustc does an autoderef and then autoref again). | 160 | // rustc does an autoderef and then autoref again). |
162 | 161 | ||
163 | let krate = resolver.krate()?; | 162 | let krate = resolver.krate()?; |
164 | for derefed_ty in self.autoderef(db) { | 163 | for derefed_ty in ty.value.clone().autoderef(db) { |
165 | if let Some(result) = | 164 | let derefed_ty = Canonical { value: derefed_ty, num_vars: ty.num_vars }; |
166 | derefed_ty.iterate_inherent_methods(db, name, krate, &mut callback) | 165 | if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback) |
167 | { | 166 | { |
168 | return Some(result); | 167 | return Some(result); |
169 | } | 168 | } |
170 | if let Some(result) = | 169 | if let Some(result) = |
171 | derefed_ty.iterate_trait_method_candidates(db, resolver, name, &mut callback) | 170 | iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback) |
172 | { | 171 | { |
173 | return Some(result); | 172 | return Some(result); |
174 | } | ||
175 | } | 173 | } |
176 | None | ||
177 | } | 174 | } |
175 | None | ||
176 | } | ||
178 | 177 | ||
179 | fn iterate_trait_method_candidates<T>( | 178 | fn iterate_trait_method_candidates<T>( |
180 | &self, | 179 | ty: &Canonical<Ty>, |
181 | db: &impl HirDatabase, | 180 | db: &impl HirDatabase, |
182 | resolver: &Resolver, | 181 | resolver: &Resolver, |
183 | name: Option<&Name>, | 182 | name: Option<&Name>, |
184 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 183 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
185 | ) -> Option<T> { | 184 | ) -> Option<T> { |
186 | let krate = resolver.krate()?; | 185 | let krate = resolver.krate()?; |
187 | 'traits: for t in resolver.traits_in_scope() { | 186 | 'traits: for t in resolver.traits_in_scope() { |
188 | let data = t.trait_data(db); | 187 | let data = t.trait_data(db); |
189 | // we'll be lazy about checking whether the type implements the | 188 | // we'll be lazy about checking whether the type implements the |
190 | // trait, but if we find out it doesn't, we'll skip the rest of the | 189 | // trait, but if we find out it doesn't, we'll skip the rest of the |
191 | // iteration | 190 | // iteration |
192 | let mut known_implemented = false; | 191 | let mut known_implemented = false; |
193 | for item in data.items() { | 192 | for item in data.items() { |
194 | match item { | 193 | match item { |
195 | &TraitItem::Function(m) => { | 194 | &TraitItem::Function(m) => { |
196 | let sig = m.signature(db); | 195 | let sig = m.signature(db); |
197 | if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { | 196 | if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { |
198 | if !known_implemented { | 197 | if !known_implemented { |
199 | // TODO the self type may contain type | 198 | let trait_ref = canonical_trait_ref(db, t, ty.clone()); |
200 | // variables, so we need to do proper | 199 | // FIXME cache this implements check (without solution) in a query? |
201 | // canonicalization here | 200 | if super::traits::implements(db, krate, trait_ref).is_none() { |
202 | let trait_ref = TraitRef { | 201 | continue 'traits; |
203 | trait_: t, | ||
204 | substs: fresh_substs_for_trait(db, t, self.clone()), | ||
205 | }; | ||
206 | let canonical = Canonical { | ||
207 | num_vars: trait_ref.substs.len(), | ||
208 | value: trait_ref, | ||
209 | }; | ||
210 | // FIXME cache this implements check (without solution) in a query? | ||
211 | if super::traits::implements(db, krate, canonical).is_none() { | ||
212 | continue 'traits; | ||
213 | } | ||
214 | } | ||
215 | known_implemented = true; | ||
216 | if let Some(result) = callback(self, m) { | ||
217 | return Some(result); | ||
218 | } | 202 | } |
219 | } | 203 | } |
204 | known_implemented = true; | ||
205 | // TODO the self type is now canonicalized... | ||
206 | if let Some(result) = callback(&ty.value, m) { | ||
207 | return Some(result); | ||
208 | } | ||
220 | } | 209 | } |
221 | _ => {} | ||
222 | } | 210 | } |
211 | _ => {} | ||
223 | } | 212 | } |
224 | } | 213 | } |
225 | None | ||
226 | } | 214 | } |
215 | None | ||
216 | } | ||
227 | 217 | ||
228 | fn iterate_inherent_methods<T>( | 218 | fn iterate_inherent_methods<T>( |
229 | &self, | 219 | ty: &Canonical<Ty>, |
230 | db: &impl HirDatabase, | 220 | db: &impl HirDatabase, |
231 | name: Option<&Name>, | 221 | name: Option<&Name>, |
232 | krate: Crate, | 222 | krate: Crate, |
233 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 223 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
234 | ) -> Option<T> { | 224 | ) -> Option<T> { |
235 | let krate = match def_crate(db, krate, self) { | 225 | let krate = match def_crate(db, krate, &ty.value) { |
236 | Some(krate) => krate, | 226 | Some(krate) => krate, |
237 | None => return None, | 227 | None => return None, |
238 | }; | 228 | }; |
239 | let impls = db.impls_in_crate(krate); | 229 | let impls = db.impls_in_crate(krate); |
240 | 230 | ||
241 | for impl_block in impls.lookup_impl_blocks(self) { | 231 | for impl_block in impls.lookup_impl_blocks(&ty.value) { |
242 | for item in impl_block.items(db) { | 232 | for item in impl_block.items(db) { |
243 | match item { | 233 | match item { |
244 | ImplItem::Method(f) => { | 234 | ImplItem::Method(f) => { |
245 | let sig = f.signature(db); | 235 | let sig = f.signature(db); |
246 | if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { | 236 | if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { |
247 | if let Some(result) = callback(self, f) { | 237 | if let Some(result) = callback(&ty.value, f) { |
248 | return Some(result); | 238 | return Some(result); |
249 | } | ||
250 | } | 239 | } |
251 | } | 240 | } |
252 | _ => {} | ||
253 | } | 241 | } |
242 | _ => {} | ||
254 | } | 243 | } |
255 | } | 244 | } |
256 | None | ||
257 | } | 245 | } |
246 | None | ||
247 | } | ||
258 | 248 | ||
249 | impl Ty { | ||
259 | // This would be nicer if it just returned an iterator, but that runs into | 250 | // This would be nicer if it just returned an iterator, but that runs into |
260 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. | 251 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. |
261 | pub fn iterate_impl_items<T>( | 252 | pub fn iterate_impl_items<T>( |
@@ -280,17 +271,25 @@ impl Ty { | |||
280 | 271 | ||
281 | /// This creates Substs for a trait with the given Self type and type variables | 272 | /// This creates Substs for a trait with the given Self type and type variables |
282 | /// for all other parameters, to query Chalk with it. | 273 | /// for all other parameters, to query Chalk with it. |
283 | fn fresh_substs_for_trait(db: &impl HirDatabase, tr: Trait, self_ty: Ty) -> Substs { | 274 | fn canonical_trait_ref( |
275 | db: &impl HirDatabase, | ||
276 | trait_: Trait, | ||
277 | self_ty: Canonical<Ty>, | ||
278 | ) -> Canonical<TraitRef> { | ||
284 | let mut substs = Vec::new(); | 279 | let mut substs = Vec::new(); |
285 | let generics = tr.generic_params(db); | 280 | let generics = trait_.generic_params(db); |
286 | substs.push(self_ty); | 281 | let num_vars = self_ty.num_vars; |
282 | substs.push(self_ty.value); | ||
287 | substs.extend( | 283 | substs.extend( |
288 | generics | 284 | generics |
289 | .params_including_parent() | 285 | .params_including_parent() |
290 | .into_iter() | 286 | .into_iter() |
291 | .skip(1) | 287 | .skip(1) |
292 | .enumerate() | 288 | .enumerate() |
293 | .map(|(i, _p)| Ty::Bound(i as u32)), | 289 | .map(|(i, _p)| Ty::Bound((i + num_vars) as u32)), |
294 | ); | 290 | ); |
295 | substs.into() | 291 | Canonical { |
292 | num_vars: substs.len() - 1 + self_ty.num_vars, | ||
293 | value: TraitRef { trait_, substs: substs.into() }, | ||
294 | } | ||
296 | } | 295 | } |