aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs33
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs129
-rw-r--r--crates/ra_hir_ty/src/tests.rs16
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs57
4 files changed, 161 insertions, 74 deletions
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index 4006f595d..23de2bd6b 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -4,7 +4,7 @@ use std::iter::repeat;
4use std::sync::Arc; 4use std::sync::Arc;
5 5
6use hir_def::{ 6use hir_def::{
7 expr::{BindingAnnotation, Pat, PatId, RecordFieldPat}, 7 expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat},
8 path::Path, 8 path::Path,
9 type_ref::Mutability, 9 type_ref::Mutability,
10 FieldId, 10 FieldId,
@@ -90,18 +90,7 @@ impl<'a> InferenceContext<'a> {
90 ) -> Ty { 90 ) -> Ty {
91 let body = Arc::clone(&self.body); // avoid borrow checker problem 91 let body = Arc::clone(&self.body); // avoid borrow checker problem
92 92
93 let is_non_ref_pat = match &body[pat] { 93 if is_non_ref_pat(&body, pat) {
94 Pat::Tuple { .. }
95 | Pat::Or(..)
96 | Pat::TupleStruct { .. }
97 | Pat::Record { .. }
98 | Pat::Range { .. }
99 | Pat::Slice { .. } => true,
100 // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented.
101 Pat::Path(..) | Pat::Lit(..) => true,
102 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false,
103 };
104 if is_non_ref_pat {
105 while let Some((inner, mutability)) = expected.as_reference() { 94 while let Some((inner, mutability)) = expected.as_reference() {
106 expected = inner; 95 expected = inner;
107 default_bm = match default_bm { 96 default_bm = match default_bm {
@@ -227,3 +216,21 @@ impl<'a> InferenceContext<'a> {
227 ty 216 ty
228 } 217 }
229} 218}
219
220fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
221 match &body[pat] {
222 Pat::Tuple { .. }
223 | Pat::TupleStruct { .. }
224 | Pat::Record { .. }
225 | Pat::Range { .. }
226 | Pat::Slice { .. } => true,
227 Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)),
228 // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented.
229 Pat::Path(..) => true,
230 Pat::Lit(expr) => match body[*expr] {
231 Expr::Literal(Literal::String(..)) => false,
232 _ => true,
233 },
234 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false,
235 }
236}
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index ed638c195..8b59a8bd6 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -271,6 +271,33 @@ pub fn iterate_method_candidates<T>(
271 mode: LookupMode, 271 mode: LookupMode,
272 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 272 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
273) -> Option<T> { 273) -> Option<T> {
274 let mut slot = None;
275 iterate_method_candidates_impl(
276 ty,
277 db,
278 env,
279 krate,
280 traits_in_scope,
281 name,
282 mode,
283 &mut |ty, item| {
284 slot = callback(ty, item);
285 slot.is_some()
286 },
287 );
288 slot
289}
290
291pub fn iterate_method_candidates_impl(
292 ty: &Canonical<Ty>,
293 db: &dyn HirDatabase,
294 env: Arc<TraitEnvironment>,
295 krate: CrateId,
296 traits_in_scope: &FxHashSet<TraitId>,
297 name: Option<&Name>,
298 mode: LookupMode,
299 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
300) -> bool {
274 match mode { 301 match mode {
275 LookupMode::MethodCall => { 302 LookupMode::MethodCall => {
276 // For method calls, rust first does any number of autoderef, and then one 303 // For method calls, rust first does any number of autoderef, and then one
@@ -298,19 +325,19 @@ pub fn iterate_method_candidates<T>(
298 325
299 let deref_chain = autoderef_method_receiver(db, krate, ty); 326 let deref_chain = autoderef_method_receiver(db, krate, ty);
300 for i in 0..deref_chain.len() { 327 for i in 0..deref_chain.len() {
301 if let Some(result) = iterate_method_candidates_with_autoref( 328 if iterate_method_candidates_with_autoref(
302 &deref_chain[i..], 329 &deref_chain[i..],
303 db, 330 db,
304 env.clone(), 331 env.clone(),
305 krate, 332 krate,
306 traits_in_scope, 333 traits_in_scope,
307 name, 334 name,
308 &mut callback, 335 callback,
309 ) { 336 ) {
310 return Some(result); 337 return true;
311 } 338 }
312 } 339 }
313 None 340 false
314 } 341 }
315 LookupMode::Path => { 342 LookupMode::Path => {
316 // No autoderef for path lookups 343 // No autoderef for path lookups
@@ -321,22 +348,22 @@ pub fn iterate_method_candidates<T>(
321 krate, 348 krate,
322 traits_in_scope, 349 traits_in_scope,
323 name, 350 name,
324 &mut callback, 351 callback,
325 ) 352 )
326 } 353 }
327 } 354 }
328} 355}
329 356
330fn iterate_method_candidates_with_autoref<T>( 357fn iterate_method_candidates_with_autoref(
331 deref_chain: &[Canonical<Ty>], 358 deref_chain: &[Canonical<Ty>],
332 db: &dyn HirDatabase, 359 db: &dyn HirDatabase,
333 env: Arc<TraitEnvironment>, 360 env: Arc<TraitEnvironment>,
334 krate: CrateId, 361 krate: CrateId,
335 traits_in_scope: &FxHashSet<TraitId>, 362 traits_in_scope: &FxHashSet<TraitId>,
336 name: Option<&Name>, 363 name: Option<&Name>,
337 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 364 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
338) -> Option<T> { 365) -> bool {
339 if let Some(result) = iterate_method_candidates_by_receiver( 366 if iterate_method_candidates_by_receiver(
340 &deref_chain[0], 367 &deref_chain[0],
341 &deref_chain[1..], 368 &deref_chain[1..],
342 db, 369 db,
@@ -346,13 +373,13 @@ fn iterate_method_candidates_with_autoref<T>(
346 name, 373 name,
347 &mut callback, 374 &mut callback,
348 ) { 375 ) {
349 return Some(result); 376 return true;
350 } 377 }
351 let refed = Canonical { 378 let refed = Canonical {
352 num_vars: deref_chain[0].num_vars, 379 num_vars: deref_chain[0].num_vars,
353 value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), 380 value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()),
354 }; 381 };
355 if let Some(result) = iterate_method_candidates_by_receiver( 382 if iterate_method_candidates_by_receiver(
356 &refed, 383 &refed,
357 deref_chain, 384 deref_chain,
358 db, 385 db,
@@ -362,13 +389,13 @@ fn iterate_method_candidates_with_autoref<T>(
362 name, 389 name,
363 &mut callback, 390 &mut callback,
364 ) { 391 ) {
365 return Some(result); 392 return true;
366 } 393 }
367 let ref_muted = Canonical { 394 let ref_muted = Canonical {
368 num_vars: deref_chain[0].num_vars, 395 num_vars: deref_chain[0].num_vars,
369 value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), 396 value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()),
370 }; 397 };
371 if let Some(result) = iterate_method_candidates_by_receiver( 398 if iterate_method_candidates_by_receiver(
372 &ref_muted, 399 &ref_muted,
373 deref_chain, 400 deref_chain,
374 db, 401 db,
@@ -378,12 +405,12 @@ fn iterate_method_candidates_with_autoref<T>(
378 name, 405 name,
379 &mut callback, 406 &mut callback,
380 ) { 407 ) {
381 return Some(result); 408 return true;
382 } 409 }
383 None 410 false
384} 411}
385 412
386fn iterate_method_candidates_by_receiver<T>( 413fn iterate_method_candidates_by_receiver(
387 receiver_ty: &Canonical<Ty>, 414 receiver_ty: &Canonical<Ty>,
388 rest_of_deref_chain: &[Canonical<Ty>], 415 rest_of_deref_chain: &[Canonical<Ty>],
389 db: &dyn HirDatabase, 416 db: &dyn HirDatabase,
@@ -391,20 +418,18 @@ fn iterate_method_candidates_by_receiver<T>(
391 krate: CrateId, 418 krate: CrateId,
392 traits_in_scope: &FxHashSet<TraitId>, 419 traits_in_scope: &FxHashSet<TraitId>,
393 name: Option<&Name>, 420 name: Option<&Name>,
394 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 421 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
395) -> Option<T> { 422) -> bool {
396 // We're looking for methods with *receiver* type receiver_ty. These could 423 // We're looking for methods with *receiver* type receiver_ty. These could
397 // be found in any of the derefs of receiver_ty, so we have to go through 424 // be found in any of the derefs of receiver_ty, so we have to go through
398 // that. 425 // that.
399 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { 426 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
400 if let Some(result) = 427 if iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback) {
401 iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback) 428 return true;
402 {
403 return Some(result);
404 } 429 }
405 } 430 }
406 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { 431 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
407 if let Some(result) = iterate_trait_method_candidates( 432 if iterate_trait_method_candidates(
408 self_ty, 433 self_ty,
409 db, 434 db,
410 env.clone(), 435 env.clone(),
@@ -414,40 +439,28 @@ fn iterate_method_candidates_by_receiver<T>(
414 Some(receiver_ty), 439 Some(receiver_ty),
415 &mut callback, 440 &mut callback,
416 ) { 441 ) {
417 return Some(result); 442 return true;
418 } 443 }
419 } 444 }
420 None 445 false
421} 446}
422 447
423fn iterate_method_candidates_for_self_ty<T>( 448fn iterate_method_candidates_for_self_ty(
424 self_ty: &Canonical<Ty>, 449 self_ty: &Canonical<Ty>,
425 db: &dyn HirDatabase, 450 db: &dyn HirDatabase,
426 env: Arc<TraitEnvironment>, 451 env: Arc<TraitEnvironment>,
427 krate: CrateId, 452 krate: CrateId,
428 traits_in_scope: &FxHashSet<TraitId>, 453 traits_in_scope: &FxHashSet<TraitId>,
429 name: Option<&Name>, 454 name: Option<&Name>,
430 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 455 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
431) -> Option<T> { 456) -> bool {
432 if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) { 457 if iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) {
433 return Some(result); 458 return true;
434 }
435 if let Some(result) = iterate_trait_method_candidates(
436 self_ty,
437 db,
438 env,
439 krate,
440 traits_in_scope,
441 name,
442 None,
443 &mut callback,
444 ) {
445 return Some(result);
446 } 459 }
447 None 460 iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback)
448} 461}
449 462
450fn iterate_trait_method_candidates<T>( 463fn iterate_trait_method_candidates(
451 self_ty: &Canonical<Ty>, 464 self_ty: &Canonical<Ty>,
452 db: &dyn HirDatabase, 465 db: &dyn HirDatabase,
453 env: Arc<TraitEnvironment>, 466 env: Arc<TraitEnvironment>,
@@ -455,8 +468,8 @@ fn iterate_trait_method_candidates<T>(
455 traits_in_scope: &FxHashSet<TraitId>, 468 traits_in_scope: &FxHashSet<TraitId>,
456 name: Option<&Name>, 469 name: Option<&Name>,
457 receiver_ty: Option<&Canonical<Ty>>, 470 receiver_ty: Option<&Canonical<Ty>>,
458 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 471 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
459) -> Option<T> { 472) -> bool {
460 // if ty is `dyn Trait`, the trait doesn't need to be in scope 473 // if ty is `dyn Trait`, the trait doesn't need to be in scope
461 let inherent_trait = 474 let inherent_trait =
462 self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); 475 self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
@@ -489,23 +502,27 @@ fn iterate_trait_method_candidates<T>(
489 } 502 }
490 } 503 }
491 known_implemented = true; 504 known_implemented = true;
492 if let Some(result) = callback(&self_ty.value, *item) { 505 if callback(&self_ty.value, *item) {
493 return Some(result); 506 return true;
494 } 507 }
495 } 508 }
496 } 509 }
497 None 510 false
498} 511}
499 512
500fn iterate_inherent_methods<T>( 513fn iterate_inherent_methods(
501 self_ty: &Canonical<Ty>, 514 self_ty: &Canonical<Ty>,
502 db: &dyn HirDatabase, 515 db: &dyn HirDatabase,
503 name: Option<&Name>, 516 name: Option<&Name>,
504 receiver_ty: Option<&Canonical<Ty>>, 517 receiver_ty: Option<&Canonical<Ty>>,
505 krate: CrateId, 518 krate: CrateId,
506 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 519 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
507) -> Option<T> { 520) -> bool {
508 for krate in self_ty.value.def_crates(db, krate)? { 521 let def_crates = match self_ty.value.def_crates(db, krate) {
522 Some(k) => k,
523 None => return false,
524 };
525 for krate in def_crates {
509 let impls = db.impls_in_crate(krate); 526 let impls = db.impls_in_crate(krate);
510 527
511 for impl_def in impls.lookup_impl_defs(&self_ty.value) { 528 for impl_def in impls.lookup_impl_defs(&self_ty.value) {
@@ -521,13 +538,13 @@ fn iterate_inherent_methods<T>(
521 test_utils::mark::hit!(impl_self_type_match_without_receiver); 538 test_utils::mark::hit!(impl_self_type_match_without_receiver);
522 continue; 539 continue;
523 } 540 }
524 if let Some(result) = callback(&self_ty.value, item) { 541 if callback(&self_ty.value, item) {
525 return Some(result); 542 return true;
526 } 543 }
527 } 544 }
528 } 545 }
529 } 546 }
530 None 547 false
531} 548}
532 549
533/// Returns the self type for the index trait call. 550/// Returns the self type for the index trait call.
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 1fe05c70c..85ff26a36 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -67,8 +67,8 @@ fn type_at_pos_displayed(
67 panic!("Can't find expression") 67 panic!("Can't find expression")
68} 68}
69 69
70fn type_at(content: &str) -> String { 70fn type_at(ra_fixture: &str) -> String {
71 let (db, file_pos) = TestDB::with_position(content); 71 let (db, file_pos) = TestDB::with_position(ra_fixture);
72 type_at_pos(&db, file_pos) 72 type_at_pos(&db, file_pos)
73} 73}
74 74
@@ -164,13 +164,19 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
164 visit_module(&db, &crate_def_map, module.local_id, &mut |it| defs.push(it)); 164 visit_module(&db, &crate_def_map, module.local_id, &mut |it| defs.push(it));
165 defs.sort_by_key(|def| match def { 165 defs.sort_by_key(|def| match def {
166 DefWithBodyId::FunctionId(it) => { 166 DefWithBodyId::FunctionId(it) => {
167 it.lookup(&db).ast_id.to_node(&db).syntax().text_range().start() 167 let loc = it.lookup(&db);
168 let tree = db.item_tree(loc.id.file_id);
169 tree.source(&db, loc.id).syntax().text_range().start()
168 } 170 }
169 DefWithBodyId::ConstId(it) => { 171 DefWithBodyId::ConstId(it) => {
170 it.lookup(&db).ast_id.to_node(&db).syntax().text_range().start() 172 let loc = it.lookup(&db);
173 let tree = db.item_tree(loc.id.file_id);
174 tree.source(&db, loc.id).syntax().text_range().start()
171 } 175 }
172 DefWithBodyId::StaticId(it) => { 176 DefWithBodyId::StaticId(it) => {
173 it.lookup(&db).ast_id.to_node(&db).syntax().text_range().start() 177 let loc = it.lookup(&db);
178 let tree = db.item_tree(loc.id.file_id);
179 tree.source(&db, loc.id).syntax().text_range().start()
174 } 180 }
175 }); 181 });
176 for def in defs { 182 for def in defs {
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
index 8fa296137..e5ef241ca 100644
--- a/crates/ra_hir_ty/src/tests/patterns.rs
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -271,6 +271,63 @@ fn test() {
271} 271}
272 272
273#[test] 273#[test]
274fn infer_pattern_match_string_literal() {
275 assert_snapshot!(
276 infer_with_mismatches(r#"
277fn test() {
278 let s: &str = "hello";
279 match s {
280 "hello" => {}
281 _ => {}
282 }
283}
284"#, true),
285 @r###"
286 10..98 '{ ... } }': ()
287 20..21 's': &str
288 30..37 '"hello"': &str
289 43..96 'match ... }': ()
290 49..50 's': &str
291 61..68 '"hello"': &str
292 61..68 '"hello"': &str
293 72..74 '{}': ()
294 83..84 '_': &str
295 88..90 '{}': ()
296 "###
297 );
298}
299
300#[test]
301fn infer_pattern_match_or() {
302 assert_snapshot!(
303 infer_with_mismatches(r#"
304fn test() {
305 let s: &str = "hello";
306 match s {
307 "hello" | "world" => {}
308 _ => {}
309 }
310}
311"#, true),
312 @r###"
313 10..108 '{ ... } }': ()
314 20..21 's': &str
315 30..37 '"hello"': &str
316 43..106 'match ... }': ()
317 49..50 's': &str
318 61..68 '"hello"': &str
319 61..68 '"hello"': &str
320 61..78 '"hello...world"': &str
321 71..78 '"world"': &str
322 71..78 '"world"': &str
323 82..84 '{}': ()
324 93..94 '_': &str
325 98..100 '{}': ()
326 "###
327 );
328}
329
330#[test]
274fn infer_pattern_match_arr() { 331fn infer_pattern_match_arr() {
275 assert_snapshot!( 332 assert_snapshot!(
276 infer(r#" 333 infer(r#"