diff options
author | Lukas Wirth <[email protected]> | 2021-04-07 10:31:50 +0100 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2021-04-07 10:31:50 +0100 |
commit | 41563fd6128e94e1fe1ae4006e4e183dff1a645c (patch) | |
tree | 6de6740ca7f028b1e58ce107f414d7a4b67eb5ac | |
parent | e6a1c9ca60c19bf3b02b302e21d9f9fd9bd8a466 (diff) |
Infer variants through type aliased enums
-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 c63878e7a..796f77ab0 100644 --- a/crates/hir_ty/src/infer.rs +++ b/crates/hir_ty/src/infer.rs | |||
@@ -484,36 +484,13 @@ impl<'a> InferenceContext<'a> { | |||
484 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); | 484 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); |
485 | let substs = generics.type_params_subst(self.db); | 485 | let substs = generics.type_params_subst(self.db); |
486 | let ty = self.db.impl_self_ty(impl_id).substitute(&Interner, &substs); | 486 | let ty = self.db.impl_self_ty(impl_id).substitute(&Interner, &substs); |
487 | match unresolved { | 487 | self.resolve_variant_on_alias(ty, unresolved, path) |
488 | None => { | ||
489 | let variant = ty_variant(&ty); | ||
490 | (ty, variant) | ||
491 | } | ||
492 | Some(1) => { | ||
493 | let segment = path.mod_path().segments().last().unwrap(); | ||
494 | // this could be an enum variant or associated type | ||
495 | if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { | ||
496 | let enum_data = self.db.enum_data(enum_id); | ||
497 | if let Some(local_id) = enum_data.variant(segment) { | ||
498 | let variant = EnumVariantId { parent: enum_id, local_id }; | ||
499 | return (ty, Some(variant.into())); | ||
500 | } | ||
501 | } | ||
502 | // FIXME potentially resolve assoc type | ||
503 | (self.err_ty(), None) | ||
504 | } | ||
505 | Some(_) => { | ||
506 | // FIXME diagnostic | ||
507 | (self.err_ty(), None) | ||
508 | } | ||
509 | } | ||
510 | } | 488 | } |
511 | TypeNs::TypeAliasId(it) => { | 489 | TypeNs::TypeAliasId(it) => { |
512 | let ty = TyBuilder::def_ty(self.db, it.into()) | 490 | let ty = TyBuilder::def_ty(self.db, it.into()) |
513 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) | 491 | .fill(std::iter::repeat_with(|| self.table.new_type_var())) |
514 | .build(); | 492 | .build(); |
515 | let variant = ty_variant(&ty); | 493 | self.resolve_variant_on_alias(ty, unresolved, path) |
516 | forbid_unresolved_segments((ty, variant), unresolved) | ||
517 | } | 494 | } |
518 | TypeNs::AdtSelfType(_) => { | 495 | TypeNs::AdtSelfType(_) => { |
519 | // FIXME this could happen in array size expressions, once we're checking them | 496 | // FIXME this could happen in array size expressions, once we're checking them |
@@ -540,16 +517,43 @@ impl<'a> InferenceContext<'a> { | |||
540 | (TyKind::Error.intern(&Interner), None) | 517 | (TyKind::Error.intern(&Interner), None) |
541 | } | 518 | } |
542 | } | 519 | } |
520 | } | ||
543 | 521 | ||
544 | fn ty_variant(ty: &Ty) -> Option<VariantId> { | 522 | fn resolve_variant_on_alias( |
545 | ty.as_adt().and_then(|(adt_id, _)| match adt_id { | 523 | &mut self, |
546 | AdtId::StructId(s) => Some(VariantId::StructId(s)), | 524 | ty: Ty, |
547 | AdtId::UnionId(u) => Some(VariantId::UnionId(u)), | 525 | unresolved: Option<usize>, |
548 | AdtId::EnumId(_) => { | 526 | path: &Path, |
549 | // FIXME Error E0071, expected struct, variant or union type, found enum `Foo` | 527 | ) -> (Ty, Option<VariantId>) { |
550 | None | 528 | match unresolved { |
529 | None => { | ||
530 | let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id { | ||
531 | AdtId::StructId(s) => Some(VariantId::StructId(s)), | ||
532 | AdtId::UnionId(u) => Some(VariantId::UnionId(u)), | ||
533 | AdtId::EnumId(_) => { | ||
534 | // FIXME Error E0071, expected struct, variant or union type, found enum `Foo` | ||
535 | None | ||
536 | } | ||
537 | }); | ||
538 | (ty, variant) | ||
539 | } | ||
540 | Some(1) => { | ||
541 | let segment = path.mod_path().segments().last().unwrap(); | ||
542 | // this could be an enum variant or associated type | ||
543 | if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() { | ||
544 | let enum_data = self.db.enum_data(enum_id); | ||
545 | if let Some(local_id) = enum_data.variant(segment) { | ||
546 | let variant = EnumVariantId { parent: enum_id, local_id }; | ||
547 | return (ty, Some(variant.into())); | ||
548 | } | ||
551 | } | 549 | } |
552 | }) | 550 | // FIXME potentially resolve assoc type |
551 | (self.err_ty(), None) | ||
552 | } | ||
553 | Some(_) => { | ||
554 | // FIXME diagnostic | ||
555 | (self.err_ty(), None) | ||
556 | } | ||
553 | } | 557 | } |
554 | } | 558 | } |
555 | 559 | ||
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 | } | ||