From 6cfdfdecbaed38534397f16e1ea1cda38b0b9395 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Mon, 5 Aug 2019 21:13:34 +0200 Subject: 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 `::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`, the type is normalized to an application type with `TypeCtor::AssociatedType`. --- crates/ra_hir/src/ty.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'crates/ra_hir/src/ty.rs') 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 { /// A tuple type. For example, `(i32, bool)`. Tuple { cardinality: u16 }, + + /// Represents an associated item like `Iterator::Item`. This is used + /// when we have tried to normalize a projection like `T::Item` but + /// couldn't find a better representation. In that case, we generate + /// an **application type** like `(Iterator::Item)`. + AssociatedType(TypeAlias), } /// A nominal type with (maybe 0) type parameters. This might be a primitive @@ -114,6 +120,12 @@ pub struct ProjectionTy { pub parameters: Substs, } +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub struct UnselectedProjectionTy { + pub type_name: Name, + pub parameters: Substs, +} + /// A type. /// /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents @@ -127,6 +139,18 @@ pub enum Ty { /// several other things. Apply(ApplicationTy), + /// A "projection" type corresponds to an (unnormalized) + /// projection like `>::Foo`. Note that the + /// trait and all its parameters are fully known. + Projection(ProjectionTy), + + /// This is a variant of a projection in which the trait is + /// **not** known. It corresponds to a case where people write + /// `T::Item` without specifying the trait. We would then try to + /// figure out the trait by looking at all the traits that are in + /// scope. + UnselectedProjection(UnselectedProjectionTy), + /// A type parameter; for example, `T` in `fn f(x: T) {} Param { /// The index of the parameter (starting with parameters from the @@ -352,6 +376,16 @@ impl Ty { t.walk(f); } } + Ty::Projection(p_ty) => { + for t in p_ty.parameters.iter() { + t.walk(f); + } + } + Ty::UnselectedProjection(p_ty) => { + for t in p_ty.parameters.iter() { + t.walk(f); + } + } Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} } f(self); @@ -362,6 +396,12 @@ impl Ty { Ty::Apply(a_ty) => { a_ty.parameters.walk_mut(f); } + Ty::Projection(p_ty) => { + p_ty.parameters.walk_mut(f); + } + Ty::UnselectedProjection(p_ty) => { + p_ty.parameters.walk_mut(f); + } Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} } f(self); @@ -572,7 +612,51 @@ impl HirDisplay for ApplicationTy { write!(f, ">")?; } } + TypeCtor::AssociatedType(type_alias) => { + let trait_name = type_alias + .parent_trait(f.db) + .and_then(|t| t.name(f.db)) + .unwrap_or_else(Name::missing); + let name = type_alias.name(f.db); + write!(f, "{}::{}", trait_name, name)?; + if self.parameters.len() > 0 { + write!(f, "<")?; + f.write_joined(&*self.parameters.0, ", ")?; + write!(f, ">")?; + } + } + } + Ok(()) + } +} + +impl HirDisplay for ProjectionTy { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + let trait_name = self + .associated_ty + .parent_trait(f.db) + .and_then(|t| t.name(f.db)) + .unwrap_or_else(Name::missing); + write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?; + if self.parameters.len() > 1 { + write!(f, "<")?; + f.write_joined(&self.parameters[1..], ", ")?; + write!(f, ">")?; + } + write!(f, ">::{}", self.associated_ty.name(f.db))?; + Ok(()) + } +} + +impl HirDisplay for UnselectedProjectionTy { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + write!(f, "{}", self.parameters[0].display(f.db))?; + if self.parameters.len() > 1 { + write!(f, "<")?; + f.write_joined(&self.parameters[1..], ", ")?; + write!(f, ">")?; } + write!(f, "::{}", self.type_name)?; Ok(()) } } @@ -581,6 +665,8 @@ impl HirDisplay for Ty { fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { match self { Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, + Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, + Ty::UnselectedProjection(p_ty) => p_ty.hir_fmt(f)?, Ty::Param { name, .. } => write!(f, "{}", name)?, Ty::Bound(idx) => write!(f, "?{}", idx)?, Ty::Unknown => write!(f, "{{unknown}}")?, -- cgit v1.2.3 From 11b9845afd1daa845ac9d541fd22f1fdf53436c8 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 10 Aug 2019 12:13:39 +0200 Subject: Improve debug logging a bit --- crates/ra_hir/src/ty.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'crates/ra_hir/src/ty.rs') diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index f9cf3ec72..642dd02cb 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -692,3 +692,17 @@ impl HirDisplay for TraitRef { Ok(()) } } + +impl HirDisplay for Obligation { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + match self { + Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)), + Obligation::Projection(proj) => write!( + f, + "Normalize({} => {})", + proj.projection_ty.display(f.db), + proj.ty.display(f.db) + ), + } + } +} -- cgit v1.2.3