mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
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`.
This commit is contained in:
parent
3a9a0bc968
commit
6cfdfdecba
3 changed files with 113 additions and 0 deletions
|
@ -838,6 +838,10 @@ impl TypeAlias {
|
|||
self.id.module(db)
|
||||
}
|
||||
|
||||
pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
|
||||
self.module(db).krate(db)
|
||||
}
|
||||
|
||||
/// The containing impl block, if this is a method.
|
||||
pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> {
|
||||
let module_impls = db.impls_in_module(self.module(db));
|
||||
|
|
|
@ -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)<T>`.
|
||||
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 `<P0 as Trait<P1..Pn>>::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<T>(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,15 +612,61 @@ 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<impl HirDatabase>) -> 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<impl HirDatabase>) -> 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(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Ty {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> 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}}")?,
|
||||
|
|
|
@ -50,6 +50,19 @@ impl ToChalk for Ty {
|
|||
let parameters = apply_ty.parameters.to_chalk(db);
|
||||
chalk_ir::ApplicationTy { name, parameters }.cast()
|
||||
}
|
||||
Ty::Projection(proj_ty) => {
|
||||
let associated_ty_id = proj_ty.associated_ty.to_chalk(db);
|
||||
let parameters = proj_ty.parameters.to_chalk(db);
|
||||
chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast()
|
||||
}
|
||||
Ty::UnselectedProjection(proj_ty) => {
|
||||
let type_name = lalrpop_intern::intern(&proj_ty.type_name.to_string());
|
||||
let parameters = proj_ty.parameters.to_chalk(db);
|
||||
chalk_ir::Ty::UnselectedProjection(chalk_ir::UnselectedProjectionTy {
|
||||
type_name,
|
||||
parameters,
|
||||
})
|
||||
}
|
||||
Ty::Param { idx, .. } => {
|
||||
PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty()
|
||||
}
|
||||
|
@ -529,6 +542,16 @@ pub(crate) fn struct_datum_query(
|
|||
adt.krate(db) != Some(krate),
|
||||
)
|
||||
}
|
||||
TypeCtor::AssociatedType(type_alias) => {
|
||||
let generic_params = type_alias.generic_params(db);
|
||||
let bound_vars = Substs::bound_vars(&generic_params);
|
||||
let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
|
||||
(
|
||||
generic_params.count_params_including_parent(),
|
||||
where_clauses,
|
||||
type_alias.krate(db) != Some(krate),
|
||||
)
|
||||
}
|
||||
};
|
||||
let flags = chalk_rust_ir::StructFlags {
|
||||
upstream,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue