mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 05:45:12 +00:00
Handle placeholder assoc types when Chalk produces them
This commit is contained in:
parent
9d72b14cfe
commit
5af9691dc9
2 changed files with 67 additions and 3 deletions
|
@ -3181,6 +3181,55 @@ fn test<T: Trait>(t: T) { (*t)<|>; }
|
||||||
assert_eq!(t, "i128");
|
assert_eq!(t, "i128");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn associated_type_placeholder() {
|
||||||
|
let t = type_at(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
pub trait ApplyL {
|
||||||
|
type Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RefMutL<T>;
|
||||||
|
|
||||||
|
impl<T> ApplyL for RefMutL<T> {
|
||||||
|
type Out = <T as ApplyL>::Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test<T: ApplyL>() {
|
||||||
|
let y: <RefMutL<T> as ApplyL>::Out = no_matter;
|
||||||
|
y<|>;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
// inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [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: ApplyL>(t: T) -> <T as ApplyL>::Out;
|
||||||
|
|
||||||
|
fn test<T: ApplyL>(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(<T as ApplyL>::Out -> ApplyL::Out<T>)
|
||||||
|
// 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 {
|
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
||||||
let file = db.parse(pos.file_id).ok().unwrap();
|
let file = db.parse(pos.file_id).ok().unwrap();
|
||||||
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
||||||
|
|
|
@ -45,8 +45,17 @@ impl ToChalk for Ty {
|
||||||
fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty {
|
fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty {
|
||||||
match self {
|
match self {
|
||||||
Ty::Apply(apply_ty) => {
|
Ty::Apply(apply_ty) => {
|
||||||
let struct_id = apply_ty.ctor.to_chalk(db);
|
let name = match apply_ty.ctor {
|
||||||
let name = TypeName::TypeKindId(struct_id.into());
|
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);
|
let parameters = apply_ty.parameters.to_chalk(db);
|
||||||
chalk_ir::ApplicationTy { name, parameters }.cast()
|
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 {
|
fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self {
|
||||||
match chalk {
|
match chalk {
|
||||||
chalk_ir::Ty::Apply(apply_ty) => {
|
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 {
|
match apply_ty.name {
|
||||||
TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => {
|
TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => {
|
||||||
let ctor = from_chalk(db, struct_id);
|
let ctor = from_chalk(db, struct_id);
|
||||||
let parameters = from_chalk(db, apply_ty.parameters);
|
let parameters = from_chalk(db, apply_ty.parameters);
|
||||||
Ty::Apply(ApplicationTy { ctor, 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
|
// FIXME handle TypeKindId::Trait/Type here
|
||||||
TypeName::TypeKindId(_) => unimplemented!(),
|
TypeName::TypeKindId(_) => unimplemented!(),
|
||||||
TypeName::AssociatedType(_) => unimplemented!(),
|
|
||||||
TypeName::Placeholder(idx) => {
|
TypeName::Placeholder(idx) => {
|
||||||
assert_eq!(idx.ui, UniverseIndex::ROOT);
|
assert_eq!(idx.ui, UniverseIndex::ROOT);
|
||||||
Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() }
|
Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue