diff options
author | Florian Diebold <[email protected]> | 2019-08-05 20:13:34 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-08-12 20:43:00 +0100 |
commit | 6cfdfdecbaed38534397f16e1ea1cda38b0b9395 (patch) | |
tree | 44366b5104b57969a3e337acbeb30209ad709087 /crates/ra_hir/src/ty.rs | |
parent | 3a9a0bc968d9bb97c80f18b4323b3ad75cc8bbad (diff) |
Add representations of associated types
This adds three different representations, copied from the Chalk model:
- `Ty::Projection` is an associated type projection written somewhere in the
code, like `<Foo as Trait>::Bar`.
- `Ty::UnselectedProjection` is similar, but we don't know the trait
yet (`Foo::Bar`).
- The above representations are normalized to their actual types during type
inference. When that isn't possible, for example for `T::Item` inside an `fn
foo<T: Iterator>`, the type is normalized to an application type with
`TypeCtor::AssociatedType`.
Diffstat (limited to 'crates/ra_hir/src/ty.rs')
-rw-r--r-- | crates/ra_hir/src/ty.rs | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 82589e504..f9cf3ec72 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -94,6 +94,12 @@ pub enum TypeCtor { | |||
94 | 94 | ||
95 | /// A tuple type. For example, `(i32, bool)`. | 95 | /// A tuple type. For example, `(i32, bool)`. |
96 | Tuple { cardinality: u16 }, | 96 | Tuple { cardinality: u16 }, |
97 | |||
98 | /// Represents an associated item like `Iterator::Item`. This is used | ||
99 | /// when we have tried to normalize a projection like `T::Item` but | ||
100 | /// couldn't find a better representation. In that case, we generate | ||
101 | /// an **application type** like `(Iterator::Item)<T>`. | ||
102 | AssociatedType(TypeAlias), | ||
97 | } | 103 | } |
98 | 104 | ||
99 | /// A nominal type with (maybe 0) type parameters. This might be a primitive | 105 | /// A nominal type with (maybe 0) type parameters. This might be a primitive |
@@ -114,6 +120,12 @@ pub struct ProjectionTy { | |||
114 | pub parameters: Substs, | 120 | pub parameters: Substs, |
115 | } | 121 | } |
116 | 122 | ||
123 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
124 | pub struct UnselectedProjectionTy { | ||
125 | pub type_name: Name, | ||
126 | pub parameters: Substs, | ||
127 | } | ||
128 | |||
117 | /// A type. | 129 | /// A type. |
118 | /// | 130 | /// |
119 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents | 131 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents |
@@ -127,6 +139,18 @@ pub enum Ty { | |||
127 | /// several other things. | 139 | /// several other things. |
128 | Apply(ApplicationTy), | 140 | Apply(ApplicationTy), |
129 | 141 | ||
142 | /// A "projection" type corresponds to an (unnormalized) | ||
143 | /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the | ||
144 | /// trait and all its parameters are fully known. | ||
145 | Projection(ProjectionTy), | ||
146 | |||
147 | /// This is a variant of a projection in which the trait is | ||
148 | /// **not** known. It corresponds to a case where people write | ||
149 | /// `T::Item` without specifying the trait. We would then try to | ||
150 | /// figure out the trait by looking at all the traits that are in | ||
151 | /// scope. | ||
152 | UnselectedProjection(UnselectedProjectionTy), | ||
153 | |||
130 | /// A type parameter; for example, `T` in `fn f<T>(x: T) {} | 154 | /// A type parameter; for example, `T` in `fn f<T>(x: T) {} |
131 | Param { | 155 | Param { |
132 | /// The index of the parameter (starting with parameters from the | 156 | /// The index of the parameter (starting with parameters from the |
@@ -352,6 +376,16 @@ impl Ty { | |||
352 | t.walk(f); | 376 | t.walk(f); |
353 | } | 377 | } |
354 | } | 378 | } |
379 | Ty::Projection(p_ty) => { | ||
380 | for t in p_ty.parameters.iter() { | ||
381 | t.walk(f); | ||
382 | } | ||
383 | } | ||
384 | Ty::UnselectedProjection(p_ty) => { | ||
385 | for t in p_ty.parameters.iter() { | ||
386 | t.walk(f); | ||
387 | } | ||
388 | } | ||
355 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | 389 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} |
356 | } | 390 | } |
357 | f(self); | 391 | f(self); |
@@ -362,6 +396,12 @@ impl Ty { | |||
362 | Ty::Apply(a_ty) => { | 396 | Ty::Apply(a_ty) => { |
363 | a_ty.parameters.walk_mut(f); | 397 | a_ty.parameters.walk_mut(f); |
364 | } | 398 | } |
399 | Ty::Projection(p_ty) => { | ||
400 | p_ty.parameters.walk_mut(f); | ||
401 | } | ||
402 | Ty::UnselectedProjection(p_ty) => { | ||
403 | p_ty.parameters.walk_mut(f); | ||
404 | } | ||
365 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | 405 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} |
366 | } | 406 | } |
367 | f(self); | 407 | f(self); |
@@ -572,7 +612,51 @@ impl HirDisplay for ApplicationTy { | |||
572 | write!(f, ">")?; | 612 | write!(f, ">")?; |
573 | } | 613 | } |
574 | } | 614 | } |
615 | TypeCtor::AssociatedType(type_alias) => { | ||
616 | let trait_name = type_alias | ||
617 | .parent_trait(f.db) | ||
618 | .and_then(|t| t.name(f.db)) | ||
619 | .unwrap_or_else(Name::missing); | ||
620 | let name = type_alias.name(f.db); | ||
621 | write!(f, "{}::{}", trait_name, name)?; | ||
622 | if self.parameters.len() > 0 { | ||
623 | write!(f, "<")?; | ||
624 | f.write_joined(&*self.parameters.0, ", ")?; | ||
625 | write!(f, ">")?; | ||
626 | } | ||
627 | } | ||
628 | } | ||
629 | Ok(()) | ||
630 | } | ||
631 | } | ||
632 | |||
633 | impl HirDisplay for ProjectionTy { | ||
634 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
635 | let trait_name = self | ||
636 | .associated_ty | ||
637 | .parent_trait(f.db) | ||
638 | .and_then(|t| t.name(f.db)) | ||
639 | .unwrap_or_else(Name::missing); | ||
640 | write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?; | ||
641 | if self.parameters.len() > 1 { | ||
642 | write!(f, "<")?; | ||
643 | f.write_joined(&self.parameters[1..], ", ")?; | ||
644 | write!(f, ">")?; | ||
645 | } | ||
646 | write!(f, ">::{}", self.associated_ty.name(f.db))?; | ||
647 | Ok(()) | ||
648 | } | ||
649 | } | ||
650 | |||
651 | impl HirDisplay for UnselectedProjectionTy { | ||
652 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
653 | write!(f, "{}", self.parameters[0].display(f.db))?; | ||
654 | if self.parameters.len() > 1 { | ||
655 | write!(f, "<")?; | ||
656 | f.write_joined(&self.parameters[1..], ", ")?; | ||
657 | write!(f, ">")?; | ||
575 | } | 658 | } |
659 | write!(f, "::{}", self.type_name)?; | ||
576 | Ok(()) | 660 | Ok(()) |
577 | } | 661 | } |
578 | } | 662 | } |
@@ -581,6 +665,8 @@ impl HirDisplay for Ty { | |||
581 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | 665 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { |
582 | match self { | 666 | match self { |
583 | Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, | 667 | Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, |
668 | Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, | ||
669 | Ty::UnselectedProjection(p_ty) => p_ty.hir_fmt(f)?, | ||
584 | Ty::Param { name, .. } => write!(f, "{}", name)?, | 670 | Ty::Param { name, .. } => write!(f, "{}", name)?, |
585 | Ty::Bound(idx) => write!(f, "?{}", idx)?, | 671 | Ty::Bound(idx) => write!(f, "?{}", idx)?, |
586 | Ty::Unknown => write!(f, "{{unknown}}")?, | 672 | Ty::Unknown => write!(f, "{{unknown}}")?, |