From 5af9691dc9132db61b50c4e90cdeda6fea0c5dd9 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 11 Aug 2019 15:54:31 +0200 Subject: Handle placeholder assoc types when Chalk produces them --- crates/ra_hir/src/ty/tests.rs | 49 ++++++++++++++++++++++++++++++++++++ crates/ra_hir/src/ty/traits/chalk.rs | 21 +++++++++++++--- 2 files changed, 67 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir/src/ty') diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index e6a09cc67..28727bb18 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3181,6 +3181,55 @@ fn test(t: T) { (*t)<|>; } assert_eq!(t, "i128"); } +#[test] +fn associated_type_placeholder() { + let t = type_at( + r#" +//- /main.rs +pub trait ApplyL { + type Out; +} + +pub struct RefMutL; + +impl ApplyL for RefMutL { + type Out = ::Out; +} + +fn test() { + let y: as ApplyL>::Out = no_matter; + y<|>; +} +"#, + ); + // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types]. + // FIXME: fix type parameter names going missing when going through Chalk + assert_eq!(t, "ApplyL::Out<[missing name]>"); +} + +#[test] +fn associated_type_placeholder_2() { + let t = type_at( + r#" +//- /main.rs +pub trait ApplyL { + type Out; +} +fn foo(t: T) -> ::Out; + +fn test(t: T) { + let y = foo(t); + y<|>; +} +"#, + ); + // FIXME here Chalk doesn't normalize the type to a placeholder. I think we + // need to add a rule like Normalize(::Out -> ApplyL::Out) + // to the trait env ourselves here; probably Chalk can't do this by itself. + // assert_eq!(t, "ApplyL::Out<[missing name]>"); + assert_eq!(t, "{unknown}"); +} + fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { let file = db.parse(pos.file_id).ok().unwrap(); let expr = algo::find_node_at_offset::(file.syntax(), pos.offset).unwrap(); diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index e669f835b..6df7094c5 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -45,8 +45,17 @@ impl ToChalk for Ty { fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { match self { Ty::Apply(apply_ty) => { - let struct_id = apply_ty.ctor.to_chalk(db); - let name = TypeName::TypeKindId(struct_id.into()); + let name = match apply_ty.ctor { + TypeCtor::AssociatedType(type_alias) => { + let type_id = type_alias.to_chalk(db); + TypeName::AssociatedType(type_id) + } + _ => { + // other TypeCtors get interned and turned into a chalk StructId + let struct_id = apply_ty.ctor.to_chalk(db); + TypeName::TypeKindId(struct_id.into()) + } + }; let parameters = apply_ty.parameters.to_chalk(db); chalk_ir::ApplicationTy { name, parameters }.cast() } @@ -79,15 +88,21 @@ impl ToChalk for Ty { fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { match chalk { chalk_ir::Ty::Apply(apply_ty) => { + // FIXME this is kind of hacky due to the fact that + // TypeName::Placeholder is a Ty::Param on our side match apply_ty.name { TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => { let ctor = from_chalk(db, struct_id); let parameters = from_chalk(db, apply_ty.parameters); Ty::Apply(ApplicationTy { ctor, parameters }) } + TypeName::AssociatedType(type_id) => { + let ctor = TypeCtor::AssociatedType(from_chalk(db, type_id)); + let parameters = from_chalk(db, apply_ty.parameters); + Ty::Apply(ApplicationTy { ctor, parameters }) + } // FIXME handle TypeKindId::Trait/Type here TypeName::TypeKindId(_) => unimplemented!(), - TypeName::AssociatedType(_) => unimplemented!(), TypeName::Placeholder(idx) => { assert_eq!(idx.ui, UniverseIndex::ROOT); Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() } -- cgit v1.2.3