diff options
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/infer/pat.rs | 42 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 130 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 16 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/patterns.rs | 82 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/regression.rs | 2 |
5 files changed, 196 insertions, 76 deletions
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs index 4006f595d..4dd4f9802 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; | |||
4 | use std::sync::Arc; | 4 | use std::sync::Arc; |
5 | 5 | ||
6 | use hir_def::{ | 6 | use 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 { |
@@ -195,7 +184,7 @@ impl<'a> InferenceContext<'a> { | |||
195 | self.write_pat_ty(pat, bound_ty); | 184 | self.write_pat_ty(pat, bound_ty); |
196 | return inner_ty; | 185 | return inner_ty; |
197 | } | 186 | } |
198 | Pat::Slice { prefix, slice: _slice, suffix } => { | 187 | Pat::Slice { prefix, slice, suffix } => { |
199 | let (container_ty, elem_ty) = match &expected { | 188 | let (container_ty, elem_ty) = match &expected { |
200 | ty_app!(TypeCtor::Array, st) => (TypeCtor::Array, st.as_single().clone()), | 189 | ty_app!(TypeCtor::Array, st) => (TypeCtor::Array, st.as_single().clone()), |
201 | ty_app!(TypeCtor::Slice, st) => (TypeCtor::Slice, st.as_single().clone()), | 190 | ty_app!(TypeCtor::Slice, st) => (TypeCtor::Slice, st.as_single().clone()), |
@@ -206,7 +195,12 @@ impl<'a> InferenceContext<'a> { | |||
206 | self.infer_pat(*pat_id, &elem_ty, default_bm); | 195 | self.infer_pat(*pat_id, &elem_ty, default_bm); |
207 | } | 196 | } |
208 | 197 | ||
209 | Ty::apply_one(container_ty, elem_ty) | 198 | let pat_ty = Ty::apply_one(container_ty, elem_ty); |
199 | if let Some(slice_pat_id) = slice { | ||
200 | self.infer_pat(*slice_pat_id, &pat_ty, default_bm); | ||
201 | } | ||
202 | |||
203 | pat_ty | ||
210 | } | 204 | } |
211 | Pat::Wild => expected.clone(), | 205 | Pat::Wild => expected.clone(), |
212 | Pat::Range { start, end } => { | 206 | Pat::Range { start, end } => { |
@@ -227,3 +221,21 @@ impl<'a> InferenceContext<'a> { | |||
227 | ty | 221 | ty |
228 | } | 222 | } |
229 | } | 223 | } |
224 | |||
225 | fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { | ||
226 | match &body[pat] { | ||
227 | Pat::Tuple { .. } | ||
228 | | Pat::TupleStruct { .. } | ||
229 | | Pat::Record { .. } | ||
230 | | Pat::Range { .. } | ||
231 | | Pat::Slice { .. } => true, | ||
232 | Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)), | ||
233 | // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. | ||
234 | Pat::Path(..) => true, | ||
235 | Pat::Lit(expr) => match body[*expr] { | ||
236 | Expr::Literal(Literal::String(..)) => false, | ||
237 | _ => true, | ||
238 | }, | ||
239 | Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false, | ||
240 | } | ||
241 | } | ||
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index ed638c195..c19519cf1 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -271,6 +271,34 @@ 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 | assert!(slot.is_none()); | ||
285 | slot = callback(ty, item); | ||
286 | slot.is_some() | ||
287 | }, | ||
288 | ); | ||
289 | slot | ||
290 | } | ||
291 | |||
292 | fn iterate_method_candidates_impl( | ||
293 | ty: &Canonical<Ty>, | ||
294 | db: &dyn HirDatabase, | ||
295 | env: Arc<TraitEnvironment>, | ||
296 | krate: CrateId, | ||
297 | traits_in_scope: &FxHashSet<TraitId>, | ||
298 | name: Option<&Name>, | ||
299 | mode: LookupMode, | ||
300 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, | ||
301 | ) -> bool { | ||
274 | match mode { | 302 | match mode { |
275 | LookupMode::MethodCall => { | 303 | LookupMode::MethodCall => { |
276 | // For method calls, rust first does any number of autoderef, and then one | 304 | // For method calls, rust first does any number of autoderef, and then one |
@@ -298,19 +326,19 @@ pub fn iterate_method_candidates<T>( | |||
298 | 326 | ||
299 | let deref_chain = autoderef_method_receiver(db, krate, ty); | 327 | let deref_chain = autoderef_method_receiver(db, krate, ty); |
300 | for i in 0..deref_chain.len() { | 328 | for i in 0..deref_chain.len() { |
301 | if let Some(result) = iterate_method_candidates_with_autoref( | 329 | if iterate_method_candidates_with_autoref( |
302 | &deref_chain[i..], | 330 | &deref_chain[i..], |
303 | db, | 331 | db, |
304 | env.clone(), | 332 | env.clone(), |
305 | krate, | 333 | krate, |
306 | traits_in_scope, | 334 | traits_in_scope, |
307 | name, | 335 | name, |
308 | &mut callback, | 336 | callback, |
309 | ) { | 337 | ) { |
310 | return Some(result); | 338 | return true; |
311 | } | 339 | } |
312 | } | 340 | } |
313 | None | 341 | false |
314 | } | 342 | } |
315 | LookupMode::Path => { | 343 | LookupMode::Path => { |
316 | // No autoderef for path lookups | 344 | // No autoderef for path lookups |
@@ -321,22 +349,22 @@ pub fn iterate_method_candidates<T>( | |||
321 | krate, | 349 | krate, |
322 | traits_in_scope, | 350 | traits_in_scope, |
323 | name, | 351 | name, |
324 | &mut callback, | 352 | callback, |
325 | ) | 353 | ) |
326 | } | 354 | } |
327 | } | 355 | } |
328 | } | 356 | } |
329 | 357 | ||
330 | fn iterate_method_candidates_with_autoref<T>( | 358 | fn iterate_method_candidates_with_autoref( |
331 | deref_chain: &[Canonical<Ty>], | 359 | deref_chain: &[Canonical<Ty>], |
332 | db: &dyn HirDatabase, | 360 | db: &dyn HirDatabase, |
333 | env: Arc<TraitEnvironment>, | 361 | env: Arc<TraitEnvironment>, |
334 | krate: CrateId, | 362 | krate: CrateId, |
335 | traits_in_scope: &FxHashSet<TraitId>, | 363 | traits_in_scope: &FxHashSet<TraitId>, |
336 | name: Option<&Name>, | 364 | name: Option<&Name>, |
337 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 365 | mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, |
338 | ) -> Option<T> { | 366 | ) -> bool { |
339 | if let Some(result) = iterate_method_candidates_by_receiver( | 367 | if iterate_method_candidates_by_receiver( |
340 | &deref_chain[0], | 368 | &deref_chain[0], |
341 | &deref_chain[1..], | 369 | &deref_chain[1..], |
342 | db, | 370 | db, |
@@ -346,13 +374,13 @@ fn iterate_method_candidates_with_autoref<T>( | |||
346 | name, | 374 | name, |
347 | &mut callback, | 375 | &mut callback, |
348 | ) { | 376 | ) { |
349 | return Some(result); | 377 | return true; |
350 | } | 378 | } |
351 | let refed = Canonical { | 379 | let refed = Canonical { |
352 | num_vars: deref_chain[0].num_vars, | 380 | num_vars: deref_chain[0].num_vars, |
353 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), | 381 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()), |
354 | }; | 382 | }; |
355 | if let Some(result) = iterate_method_candidates_by_receiver( | 383 | if iterate_method_candidates_by_receiver( |
356 | &refed, | 384 | &refed, |
357 | deref_chain, | 385 | deref_chain, |
358 | db, | 386 | db, |
@@ -362,13 +390,13 @@ fn iterate_method_candidates_with_autoref<T>( | |||
362 | name, | 390 | name, |
363 | &mut callback, | 391 | &mut callback, |
364 | ) { | 392 | ) { |
365 | return Some(result); | 393 | return true; |
366 | } | 394 | } |
367 | let ref_muted = Canonical { | 395 | let ref_muted = Canonical { |
368 | num_vars: deref_chain[0].num_vars, | 396 | num_vars: deref_chain[0].num_vars, |
369 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), | 397 | value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()), |
370 | }; | 398 | }; |
371 | if let Some(result) = iterate_method_candidates_by_receiver( | 399 | if iterate_method_candidates_by_receiver( |
372 | &ref_muted, | 400 | &ref_muted, |
373 | deref_chain, | 401 | deref_chain, |
374 | db, | 402 | db, |
@@ -378,12 +406,12 @@ fn iterate_method_candidates_with_autoref<T>( | |||
378 | name, | 406 | name, |
379 | &mut callback, | 407 | &mut callback, |
380 | ) { | 408 | ) { |
381 | return Some(result); | 409 | return true; |
382 | } | 410 | } |
383 | None | 411 | false |
384 | } | 412 | } |
385 | 413 | ||
386 | fn iterate_method_candidates_by_receiver<T>( | 414 | fn iterate_method_candidates_by_receiver( |
387 | receiver_ty: &Canonical<Ty>, | 415 | receiver_ty: &Canonical<Ty>, |
388 | rest_of_deref_chain: &[Canonical<Ty>], | 416 | rest_of_deref_chain: &[Canonical<Ty>], |
389 | db: &dyn HirDatabase, | 417 | db: &dyn HirDatabase, |
@@ -391,20 +419,18 @@ fn iterate_method_candidates_by_receiver<T>( | |||
391 | krate: CrateId, | 419 | krate: CrateId, |
392 | traits_in_scope: &FxHashSet<TraitId>, | 420 | traits_in_scope: &FxHashSet<TraitId>, |
393 | name: Option<&Name>, | 421 | name: Option<&Name>, |
394 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 422 | mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, |
395 | ) -> Option<T> { | 423 | ) -> bool { |
396 | // We're looking for methods with *receiver* type receiver_ty. These could | 424 | // 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 | 425 | // be found in any of the derefs of receiver_ty, so we have to go through |
398 | // that. | 426 | // that. |
399 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { | 427 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { |
400 | if let Some(result) = | 428 | 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) | 429 | return true; |
402 | { | ||
403 | return Some(result); | ||
404 | } | 430 | } |
405 | } | 431 | } |
406 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { | 432 | for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) { |
407 | if let Some(result) = iterate_trait_method_candidates( | 433 | if iterate_trait_method_candidates( |
408 | self_ty, | 434 | self_ty, |
409 | db, | 435 | db, |
410 | env.clone(), | 436 | env.clone(), |
@@ -414,40 +440,28 @@ fn iterate_method_candidates_by_receiver<T>( | |||
414 | Some(receiver_ty), | 440 | Some(receiver_ty), |
415 | &mut callback, | 441 | &mut callback, |
416 | ) { | 442 | ) { |
417 | return Some(result); | 443 | return true; |
418 | } | 444 | } |
419 | } | 445 | } |
420 | None | 446 | false |
421 | } | 447 | } |
422 | 448 | ||
423 | fn iterate_method_candidates_for_self_ty<T>( | 449 | fn iterate_method_candidates_for_self_ty( |
424 | self_ty: &Canonical<Ty>, | 450 | self_ty: &Canonical<Ty>, |
425 | db: &dyn HirDatabase, | 451 | db: &dyn HirDatabase, |
426 | env: Arc<TraitEnvironment>, | 452 | env: Arc<TraitEnvironment>, |
427 | krate: CrateId, | 453 | krate: CrateId, |
428 | traits_in_scope: &FxHashSet<TraitId>, | 454 | traits_in_scope: &FxHashSet<TraitId>, |
429 | name: Option<&Name>, | 455 | name: Option<&Name>, |
430 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 456 | mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, |
431 | ) -> Option<T> { | 457 | ) -> bool { |
432 | if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) { | 458 | if iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) { |
433 | return Some(result); | 459 | 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 | } | 460 | } |
447 | None | 461 | iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback) |
448 | } | 462 | } |
449 | 463 | ||
450 | fn iterate_trait_method_candidates<T>( | 464 | fn iterate_trait_method_candidates( |
451 | self_ty: &Canonical<Ty>, | 465 | self_ty: &Canonical<Ty>, |
452 | db: &dyn HirDatabase, | 466 | db: &dyn HirDatabase, |
453 | env: Arc<TraitEnvironment>, | 467 | env: Arc<TraitEnvironment>, |
@@ -455,8 +469,8 @@ fn iterate_trait_method_candidates<T>( | |||
455 | traits_in_scope: &FxHashSet<TraitId>, | 469 | traits_in_scope: &FxHashSet<TraitId>, |
456 | name: Option<&Name>, | 470 | name: Option<&Name>, |
457 | receiver_ty: Option<&Canonical<Ty>>, | 471 | receiver_ty: Option<&Canonical<Ty>>, |
458 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 472 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, |
459 | ) -> Option<T> { | 473 | ) -> bool { |
460 | // if ty is `dyn Trait`, the trait doesn't need to be in scope | 474 | // if ty is `dyn Trait`, the trait doesn't need to be in scope |
461 | let inherent_trait = | 475 | let inherent_trait = |
462 | self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); | 476 | self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); |
@@ -489,23 +503,27 @@ fn iterate_trait_method_candidates<T>( | |||
489 | } | 503 | } |
490 | } | 504 | } |
491 | known_implemented = true; | 505 | known_implemented = true; |
492 | if let Some(result) = callback(&self_ty.value, *item) { | 506 | if callback(&self_ty.value, *item) { |
493 | return Some(result); | 507 | return true; |
494 | } | 508 | } |
495 | } | 509 | } |
496 | } | 510 | } |
497 | None | 511 | false |
498 | } | 512 | } |
499 | 513 | ||
500 | fn iterate_inherent_methods<T>( | 514 | fn iterate_inherent_methods( |
501 | self_ty: &Canonical<Ty>, | 515 | self_ty: &Canonical<Ty>, |
502 | db: &dyn HirDatabase, | 516 | db: &dyn HirDatabase, |
503 | name: Option<&Name>, | 517 | name: Option<&Name>, |
504 | receiver_ty: Option<&Canonical<Ty>>, | 518 | receiver_ty: Option<&Canonical<Ty>>, |
505 | krate: CrateId, | 519 | krate: CrateId, |
506 | mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, | 520 | callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, |
507 | ) -> Option<T> { | 521 | ) -> bool { |
508 | for krate in self_ty.value.def_crates(db, krate)? { | 522 | let def_crates = match self_ty.value.def_crates(db, krate) { |
523 | Some(k) => k, | ||
524 | None => return false, | ||
525 | }; | ||
526 | for krate in def_crates { | ||
509 | let impls = db.impls_in_crate(krate); | 527 | let impls = db.impls_in_crate(krate); |
510 | 528 | ||
511 | for impl_def in impls.lookup_impl_defs(&self_ty.value) { | 529 | for impl_def in impls.lookup_impl_defs(&self_ty.value) { |
@@ -521,13 +539,13 @@ fn iterate_inherent_methods<T>( | |||
521 | test_utils::mark::hit!(impl_self_type_match_without_receiver); | 539 | test_utils::mark::hit!(impl_self_type_match_without_receiver); |
522 | continue; | 540 | continue; |
523 | } | 541 | } |
524 | if let Some(result) = callback(&self_ty.value, item) { | 542 | if callback(&self_ty.value, item) { |
525 | return Some(result); | 543 | return true; |
526 | } | 544 | } |
527 | } | 545 | } |
528 | } | 546 | } |
529 | } | 547 | } |
530 | None | 548 | false |
531 | } | 549 | } |
532 | 550 | ||
533 | /// Returns the self type for the index trait call. | 551 | /// 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 | ||
70 | fn type_at(content: &str) -> String { | 70 | fn 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..f937426bd 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] |
274 | fn infer_pattern_match_string_literal() { | ||
275 | assert_snapshot!( | ||
276 | infer_with_mismatches(r#" | ||
277 | fn 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] | ||
301 | fn infer_pattern_match_or() { | ||
302 | assert_snapshot!( | ||
303 | infer_with_mismatches(r#" | ||
304 | fn 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] | ||
274 | fn infer_pattern_match_arr() { | 331 | fn infer_pattern_match_arr() { |
275 | assert_snapshot!( | 332 | assert_snapshot!( |
276 | infer(r#" | 333 | infer(r#" |
@@ -570,3 +627,28 @@ fn test() { | |||
570 | "### | 627 | "### |
571 | ); | 628 | ); |
572 | } | 629 | } |
630 | |||
631 | #[test] | ||
632 | fn slice_tail_pattern() { | ||
633 | assert_snapshot!( | ||
634 | infer(r#" | ||
635 | fn foo(params: &[i32]) { | ||
636 | match params { | ||
637 | [head, tail @ ..] => { | ||
638 | } | ||
639 | } | ||
640 | } | ||
641 | "#), | ||
642 | @r###" | ||
643 | 7..13 'params': &[i32] | ||
644 | 23..92 '{ ... } }': () | ||
645 | 29..90 'match ... }': () | ||
646 | 35..41 'params': &[i32] | ||
647 | 52..69 '[head,... @ ..]': [i32] | ||
648 | 53..57 'head': &i32 | ||
649 | 59..68 'tail @ ..': &[i32] | ||
650 | 66..68 '..': [i32] | ||
651 | 73..84 '{ }': () | ||
652 | "### | ||
653 | ); | ||
654 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs index eedaa27ba..aa37326df 100644 --- a/crates/ra_hir_ty/src/tests/regression.rs +++ b/crates/ra_hir_ty/src/tests/regression.rs | |||
@@ -500,6 +500,8 @@ fn foo(params: &[usize]) { | |||
500 | 31..78 'match ... }': () | 500 | 31..78 'match ... }': () |
501 | 37..43 'params': &[usize] | 501 | 37..43 'params': &[usize] |
502 | 54..66 '[ps @ .., _]': [usize] | 502 | 54..66 '[ps @ .., _]': [usize] |
503 | 55..62 'ps @ ..': &[usize] | ||
504 | 60..62 '..': [usize] | ||
503 | 64..65 '_': usize | 505 | 64..65 '_': usize |
504 | 70..72 '{}': () | 506 | 70..72 '{}': () |
505 | "### | 507 | "### |