aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r--crates/ra_hir/src/ty/infer/path.rs135
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs90
-rw-r--r--crates/ra_hir/src/ty/tests.rs4
3 files changed, 96 insertions, 133 deletions
diff --git a/crates/ra_hir/src/ty/infer/path.rs b/crates/ra_hir/src/ty/infer/path.rs
index c58564b22..1946bf608 100644
--- a/crates/ra_hir/src/ty/infer/path.rs
+++ b/crates/ra_hir/src/ty/infer/path.rs
@@ -6,11 +6,9 @@ use super::{ExprOrPatId, InferenceContext, TraitRef};
6use crate::{ 6use crate::{
7 db::HirDatabase, 7 db::HirDatabase,
8 resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, 8 resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs},
9 ty::{lower, traits::TraitEnvironment, Canonical}, 9 ty::{method_resolution, Substs, Ty, TypableDef, TypeWalk},
10 ty::{Substs, Ty, TypableDef, TypeWalk}, 10 AssocItem, Container, HasGenericParams, Name, Namespace, Path,
11 AssocItem, HasGenericParams, Name, Namespace, Path, Trait,
12}; 11};
13use std::sync::Arc;
14 12
15impl<'a, D: HirDatabase> InferenceContext<'a, D> { 13impl<'a, D: HirDatabase> InferenceContext<'a, D> {
16 pub(super) fn infer_path( 14 pub(super) fn infer_path(
@@ -184,91 +182,34 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
184 return None; 182 return None;
185 } 183 }
186 184
187 self.find_inherent_assoc_candidate(ty.clone(), name, id)
188 .or_else(|| self.find_trait_assoc_candidate(ty.clone(), name, id))
189 }
190
191 fn find_inherent_assoc_candidate(
192 &mut self,
193 ty: Ty,
194 name: &Name,
195 id: ExprOrPatId,
196 ) -> Option<(ValueNs, Option<Substs>)> {
197 let krate = self.resolver.krate()?;
198
199 // Find impl
200 let item = ty.clone().iterate_impl_items(self.db, krate, |item| match item {
201 AssocItem::Function(func) => {
202 if *name == func.name(self.db) {
203 Some(AssocItem::Function(func))
204 } else {
205 None
206 }
207 }
208
209 AssocItem::Const(konst) => {
210 if konst.name(self.db).map_or(false, |n| n == *name) {
211 Some(AssocItem::Const(konst))
212 } else {
213 None
214 }
215 }
216 AssocItem::TypeAlias(_) => None,
217 })?;
218 let def = match item {
219 AssocItem::Function(f) => ValueNs::Function(f),
220 AssocItem::Const(c) => ValueNs::Const(c),
221 AssocItem::TypeAlias(_) => unreachable!(),
222 };
223 let substs = self.find_self_types(&def, ty);
224
225 self.write_assoc_resolution(id, item);
226 Some((def, substs))
227 }
228
229 fn find_trait_assoc_candidate(
230 &mut self,
231 ty: Ty,
232 name: &Name,
233 id: ExprOrPatId,
234 ) -> Option<(ValueNs, Option<Substs>)> {
235 let krate = self.resolver.krate()?;
236
237 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); 185 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone());
238 186
239 let env = lower::trait_env(self.db, &self.resolver); 187 method_resolution::iterate_method_candidates(
240 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope 188 &canonical_ty.value,
241 let traits_from_env = env 189 self.db,
242 .trait_predicates_for_self_ty(&ty) 190 &self.resolver.clone(),
243 .map(|tr| tr.trait_) 191 Some(name),
244 .flat_map(|t| t.all_super_traits(self.db)); 192 method_resolution::LookupMode::Path,
245 let traits = traits_from_env.chain(self.resolver.traits_in_scope(self.db)); 193 move |_ty, item| {
246 194 let def = match item {
247 'traits: for t in traits { 195 AssocItem::Function(f) => ValueNs::Function(f),
248 let data = t.trait_data(self.db); 196 AssocItem::Const(c) => ValueNs::Const(c),
249 let mut known_implemented = false; 197 AssocItem::TypeAlias(_) => unreachable!(),
250 for item in data.items() { 198 };
251 if let AssocItem::Function(f) = *item { 199 match item.container(self.db) {
252 if f.name(self.db) == *name { 200 Container::ImplBlock(_) => {
253 if !known_implemented { 201 let substs = self.find_self_types(&def, ty.clone());
254 let goal = generic_implements_goal( 202
255 self.db, 203 self.write_assoc_resolution(id, item);
256 env.clone(), 204 Some((def, substs))
257 t, 205 }
258 canonical_ty.value.clone(), 206 Container::Trait(t) => {
259 );
260 if self.db.trait_solve(krate, goal).is_none() {
261 continue 'traits;
262 }
263 }
264 known_implemented = true;
265
266 // we're picking this method 207 // we're picking this method
267 let trait_substs = Substs::build_for_def(self.db, t) 208 let trait_substs = Substs::build_for_def(self.db, t)
268 .push(ty.clone()) 209 .push(ty.clone())
269 .fill(std::iter::repeat_with(|| self.new_type_var())) 210 .fill(std::iter::repeat_with(|| self.new_type_var()))
270 .build(); 211 .build();
271 let substs = Substs::build_for_def(self.db, f) 212 let substs = Substs::build_for_def(self.db, item)
272 .use_parent_substs(&trait_substs) 213 .use_parent_substs(&trait_substs)
273 .fill_with_params() 214 .fill_with_params()
274 .build(); 215 .build();
@@ -277,14 +218,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
277 substs: trait_substs, 218 substs: trait_substs,
278 })); 219 }));
279 220
280 self.write_assoc_resolution(id, *item); 221 self.write_assoc_resolution(id, item);
281 return Some((ValueNs::Function(f), Some(substs))); 222 Some((def, Some(substs)))
282 } 223 }
283 } 224 }
284 } 225 },
285 } 226 )
286
287 None
288 } 227 }
289 228
290 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { 229 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
@@ -317,23 +256,3 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
317 } 256 }
318 } 257 }
319} 258}
320
321// TODO remove duplication
322/// This creates Substs for a trait with the given Self type and type variables
323/// for all other parameters, to query Chalk with it.
324fn generic_implements_goal(
325 db: &impl HirDatabase,
326 env: Arc<TraitEnvironment>,
327 trait_: Trait,
328 self_ty: Canonical<Ty>,
329) -> Canonical<super::InEnvironment<super::Obligation>> {
330 let num_vars = self_ty.num_vars;
331 let substs = super::Substs::build_for_def(db, trait_)
332 .push(self_ty.value)
333 .fill_with_bound_vars(num_vars as u32)
334 .build();
335 let num_vars = substs.len() - 1 + self_ty.num_vars;
336 let trait_ref = TraitRef { trait_, substs };
337 let obligation = super::Obligation::Trait(trait_ref);
338 Canonical { num_vars, value: super::InEnvironment::new(env, obligation) }
339}
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index eb69344f6..ee0c7b00f 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -166,7 +166,19 @@ pub(crate) fn lookup_method(
166 name: &Name, 166 name: &Name,
167 resolver: &Resolver, 167 resolver: &Resolver,
168) -> Option<(Ty, Function)> { 168) -> Option<(Ty, Function)> {
169 iterate_method_candidates(ty, db, resolver, Some(name), |ty, f| Some((ty.clone(), f))) 169 iterate_method_candidates(ty, db, resolver, Some(name), LookupMode::MethodCall, |ty, f| {
170 if let AssocItem::Function(f) = f {
171 Some((ty.clone(), f))
172 } else {
173 None
174 }
175 })
176}
177
178#[derive(Copy, Clone, Debug, PartialEq, Eq)]
179pub(crate) enum LookupMode {
180 MethodCall,
181 Path,
170} 182}
171 183
172// This would be nicer if it just returned an iterator, but that runs into 184// This would be nicer if it just returned an iterator, but that runs into
@@ -176,7 +188,8 @@ pub(crate) fn iterate_method_candidates<T>(
176 db: &impl HirDatabase, 188 db: &impl HirDatabase,
177 resolver: &Resolver, 189 resolver: &Resolver,
178 name: Option<&Name>, 190 name: Option<&Name>,
179 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 191 mode: LookupMode,
192 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
180) -> Option<T> { 193) -> Option<T> {
181 // For method calls, rust first does any number of autoderef, and then one 194 // For method calls, rust first does any number of autoderef, and then one
182 // autoref (i.e. when the method takes &self or &mut self). We just ignore 195 // autoref (i.e. when the method takes &self or &mut self). We just ignore
@@ -188,13 +201,15 @@ pub(crate) fn iterate_method_candidates<T>(
188 // rustc does an autoderef and then autoref again). 201 // rustc does an autoderef and then autoref again).
189 202
190 let krate = resolver.krate()?; 203 let krate = resolver.krate()?;
204 // TODO no autoderef in LookupMode::Path
191 for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) { 205 for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) {
192 if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback) 206 if let Some(result) =
207 iterate_inherent_methods(&derefed_ty, db, name, mode, krate, &mut callback)
193 { 208 {
194 return Some(result); 209 return Some(result);
195 } 210 }
196 if let Some(result) = 211 if let Some(result) =
197 iterate_trait_method_candidates(&derefed_ty, db, resolver, name, &mut callback) 212 iterate_trait_method_candidates(&derefed_ty, db, resolver, name, mode, &mut callback)
198 { 213 {
199 return Some(result); 214 return Some(result);
200 } 215 }
@@ -207,7 +222,8 @@ fn iterate_trait_method_candidates<T>(
207 db: &impl HirDatabase, 222 db: &impl HirDatabase,
208 resolver: &Resolver, 223 resolver: &Resolver,
209 name: Option<&Name>, 224 name: Option<&Name>,
210 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 225 mode: LookupMode,
226 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
211) -> Option<T> { 227) -> Option<T> {
212 let krate = resolver.krate()?; 228 let krate = resolver.krate()?;
213 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) 229 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
@@ -231,21 +247,35 @@ fn iterate_trait_method_candidates<T>(
231 // trait, but if we find out it doesn't, we'll skip the rest of the 247 // trait, but if we find out it doesn't, we'll skip the rest of the
232 // iteration 248 // iteration
233 let mut known_implemented = inherently_implemented; 249 let mut known_implemented = inherently_implemented;
234 for item in data.items() { 250 for &item in data.items() {
235 if let AssocItem::Function(m) = *item { 251 // TODO unify with the impl case
236 let data = m.data(db); 252 match item {
237 if name.map_or(true, |name| data.name() == name) && data.has_self_param() { 253 AssocItem::Function(m) => {
238 if !known_implemented { 254 let data = m.data(db);
239 let goal = generic_implements_goal(db, env.clone(), t, ty.clone()); 255 if !name.map_or(true, |name| data.name() == name)
240 if db.trait_solve(krate, goal).is_none() { 256 || (!data.has_self_param() && mode != LookupMode::Path)
241 continue 'traits; 257 {
242 } 258 continue;
243 } 259 }
244 known_implemented = true; 260 }
245 if let Some(result) = callback(&ty.value, m) { 261 AssocItem::Const(c) => {
246 return Some(result); 262 if !name.map_or(true, |name| Some(name) == c.name(db).as_ref())
263 || (mode != LookupMode::Path)
264 {
265 continue;
247 } 266 }
248 } 267 }
268 _ => {}
269 };
270 if !known_implemented {
271 let goal = generic_implements_goal(db, env.clone(), t, ty.clone());
272 if db.trait_solve(krate, goal).is_none() {
273 continue 'traits;
274 }
275 }
276 known_implemented = true;
277 if let Some(result) = callback(&ty.value, item) {
278 return Some(result);
249 } 279 }
250 } 280 }
251 } 281 }
@@ -256,21 +286,35 @@ fn iterate_inherent_methods<T>(
256 ty: &Canonical<Ty>, 286 ty: &Canonical<Ty>,
257 db: &impl HirDatabase, 287 db: &impl HirDatabase,
258 name: Option<&Name>, 288 name: Option<&Name>,
289 mode: LookupMode,
259 krate: Crate, 290 krate: Crate,
260 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 291 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
261) -> Option<T> { 292) -> Option<T> {
262 for krate in def_crates(db, krate, &ty.value)? { 293 for krate in def_crates(db, krate, &ty.value)? {
263 let impls = db.impls_in_crate(krate); 294 let impls = db.impls_in_crate(krate);
264 295
265 for impl_block in impls.lookup_impl_blocks(&ty.value) { 296 for impl_block in impls.lookup_impl_blocks(&ty.value) {
266 for item in impl_block.items(db) { 297 for item in impl_block.items(db) {
267 if let AssocItem::Function(f) = item { 298 match item {
268 let data = f.data(db); 299 AssocItem::Function(f) => {
269 if name.map_or(true, |name| data.name() == name) && data.has_self_param() { 300 let data = f.data(db);
270 if let Some(result) = callback(&ty.value, f) { 301 if !name.map_or(true, |name| data.name() == name)
271 return Some(result); 302 || (!data.has_self_param() && mode != LookupMode::Path)
303 {
304 continue;
272 } 305 }
273 } 306 }
307 AssocItem::Const(c) => {
308 if !name.map_or(true, |name| Some(name) == c.name(db).as_ref())
309 || (mode != LookupMode::Path)
310 {
311 continue;
312 }
313 }
314 _ => {}
315 }
316 if let Some(result) = callback(&ty.value, item) {
317 return Some(result);
274 } 318 }
275 } 319 }
276 } 320 }
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index e071e4d4e..bfef48b16 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1841,8 +1841,8 @@ fn test() {
1841 [243; 254) 'Struct::FOO': u32 1841 [243; 254) 'Struct::FOO': u32
1842 [264; 265) 'y': u32 1842 [264; 265) 'y': u32
1843 [268; 277) 'Enum::BAR': u32 1843 [268; 277) 'Enum::BAR': u32
1844 [287; 288) 'z': {unknown} 1844 [287; 288) 'z': u32
1845 [291; 304) 'TraitTest::ID': {unknown} 1845 [291; 304) 'TraitTest::ID': u32
1846 "### 1846 "###
1847 ); 1847 );
1848} 1848}