diff options
Diffstat (limited to 'crates/hir_ty')
-rw-r--r-- | crates/hir_ty/src/infer.rs | 70 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/simple.rs | 33 |
2 files changed, 70 insertions, 33 deletions
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs index 7c6c3600b..6af0c59b8 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -487,36 +487,13 @@ impl<'a> InferenceContext<'a> { | |||
487 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); | 487 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); |
488 | let substs = generics.type_params_subst(self.db); | 488 | let substs = generics.type_params_subst(self.db); |
489 | let ty = self.db.impl_self_ty(impl_id).substitute(&Interner, &substs); | 489 | let ty = self.db.impl_self_ty(impl_id).substitute(&Interner, &substs); |
490 | match unresolved { | 490 | self.resolve_variant_on_alias(ty, unresolved, path) |
491 | None => { | ||
492 | let variant = ty_variant(&ty); | ||
493 | (ty, variant) | ||
494 | } | ||
495 | Some(1) => { | ||
496 | let segment = path.mod_path().segments().last().unwrap(); | ||
497 | // this could be an enum variant or associated type | ||
498 | if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { | ||
499 | let enum_data = self.db.enum_data(enum_id); | ||
500 | if let Some(local_id) = enum_data.variant(segment) { | ||
501 | let variant = EnumVariantId { parent: enum_id, local_id }; | ||
502 | return (ty, Some(variant.into())); | ||
503 | } | ||
504 | } | ||
505 | // FIXME potentially resolve assoc type | ||
506 | (self.err_ty(), None) | ||
507 | } | ||
508 | Some(_) => { | ||
509 | // FIXME diagnostic | ||
510 | (self.err_ty(), None) | ||
511 | } | ||
512 | } | ||
513 | } | 491 | } |
514 | TypeNs::TypeAliasId(it) => { | 492 | TypeNs::TypeAliasId(it) => { |
515 | let ty = TyBuilder::def_ty(self.db, it.into()) | 493 | let ty = TyBuilder::def_ty(self.db, it.into()) |
516 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) | 494 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) |
517 | .build(); | 495 | .build(); |
518 | let variant = ty_variant(&ty); | 496 | self.resolve_variant_on_alias(ty, unresolved, path) |
519 | forbid_unresolved_segments((ty, variant), unresolved) | ||
520 | } | 497 | } |
521 | TypeNs::AdtSelfType(_) => { | 498 | TypeNs::AdtSelfType(_) => { |
522 | // FIXME this could happen in array size expressions, once we're checking them | 499 | // FIXME this could happen in array size expressions, once we're checking them |
@@ -543,16 +520,43 @@ impl<'a> InferenceContext<'a> { | |||
543 | (TyKind::Error.intern(&Interner), None) | 520 | (TyKind::Error.intern(&Interner), None) |
544 | } | 521 | } |
545 | } | 522 | } |
523 | } | ||
546 | 524 | ||
547 | fn ty_variant(ty: &Ty) -> Option<VariantId> { | 525 | fn resolve_variant_on_alias( |
548 | ty.as_adt().and_then(|(adt_id, _)| match adt_id { | 526 | &mut self, |
549 | AdtId::StructId(s) => Some(VariantId::StructId(s)), | 527 | ty: Ty, |
550 | AdtId::UnionId(u) => Some(VariantId::UnionId(u)), | 528 | unresolved: Option<usize>, |
551 | AdtId::EnumId(_) => { | 529 | path: &Path, |
552 | // FIXME Error E0071, expected struct, variant or union type, found enum `Foo` | 530 | ) -> (Ty, Option<VariantId>) { |
553 | None | 531 | match unresolved { |
532 | None => { | ||
533 | let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id { | ||
534 | AdtId::StructId(s) => Some(VariantId::StructId(s)), | ||
535 | AdtId::UnionId(u) => Some(VariantId::UnionId(u)), | ||
536 | AdtId::EnumId(_) => { | ||
537 | // FIXME Error E0071, expected struct, variant or union type, found enum `Foo` | ||
538 | None | ||
539 | } | ||
540 | }); | ||
541 | (ty, variant) | ||
542 | } | ||
543 | Some(1) => { | ||
544 | let segment = path.mod_path().segments().last().unwrap(); | ||
545 | // this could be an enum variant or associated type | ||
546 | if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { | ||
547 | let enum_data = self.db.enum_data(enum_id); | ||
548 | if let Some(local_id) = enum_data.variant(segment) { | ||
549 | let variant = EnumVariantId { parent: enum_id, local_id }; | ||
550 | return (ty, Some(variant.into())); | ||
551 | } | ||
554 | } | 552 | } |
555 | }) | 553 | // FIXME potentially resolve assoc type |
554 | (self.err_ty(), None) | ||
555 | } | ||
556 | Some(_) => { | ||
557 | // FIXME diagnostic | ||
558 | (self.err_ty(), None) | ||
559 | } | ||
556 | } | 560 | } |
557 | } | 561 | } |
558 | 562 | ||
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index 361cd6302..84c5c05fd 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs | |||
@@ -2564,3 +2564,36 @@ fn f() { | |||
2564 | "#, | 2564 | "#, |
2565 | ) | 2565 | ) |
2566 | } | 2566 | } |
2567 | |||
2568 | #[test] | ||
2569 | fn infer_type_alias_variant() { | ||
2570 | check_infer( | ||
2571 | r#" | ||
2572 | type Qux = Foo; | ||
2573 | enum Foo { | ||
2574 | Bar(i32), | ||
2575 | Baz { baz: f32 } | ||
2576 | } | ||
2577 | |||
2578 | fn f() { | ||
2579 | match Foo::Bar(3) { | ||
2580 | Qux::Bar(bar) => (), | ||
2581 | Qux::Baz { baz } => (), | ||
2582 | } | ||
2583 | } | ||
2584 | "#, | ||
2585 | expect![[r#" | ||
2586 | 72..166 '{ ... } }': () | ||
2587 | 78..164 'match ... }': () | ||
2588 | 84..92 'Foo::Bar': Bar(i32) -> Foo | ||
2589 | 84..95 'Foo::Bar(3)': Foo | ||
2590 | 93..94 '3': i32 | ||
2591 | 106..119 'Qux::Bar(bar)': Foo | ||
2592 | 115..118 'bar': i32 | ||
2593 | 123..125 '()': () | ||
2594 | 135..151 'Qux::B... baz }': Foo | ||
2595 | 146..149 'baz': f32 | ||
2596 | 155..157 '()': () | ||
2597 | "#]], | ||
2598 | ) | ||
2599 | } | ||