aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-04-07 10:31:50 +0100
committerLukas Wirth <[email protected]>2021-04-07 10:31:50 +0100
commit41563fd6128e94e1fe1ae4006e4e183dff1a645c (patch)
tree6de6740ca7f028b1e58ce107f414d7a4b67eb5ac
parente6a1c9ca60c19bf3b02b302e21d9f9fd9bd8a466 (diff)
Infer variants through type aliased enums
-rw-r--r--crates/hir_ty/src/infer.rs70
-rw-r--r--crates/hir_ty/src/tests/simple.rs33
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]
2569fn infer_type_alias_variant() {
2570 check_infer(
2571 r#"
2572type Qux = Foo;
2573enum Foo {
2574 Bar(i32),
2575 Baz { baz: f32 }
2576}
2577
2578fn 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}