aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-08-12 20:43:57 +0100
committerbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-08-12 20:43:57 +0100
commit2c65a059840dd2092a00e90337a8221cd832c456 (patch)
treefa1f8c46158271eb859928ed9da3eb389f861c09 /crates/ra_hir/src/ty
parent0cf48e48d75d267bfa38ff1319e7f7c0468fb53f (diff)
parent5af9691dc9132db61b50c4e90cdeda6fea0c5dd9 (diff)
Merge #1677
1677: Associated types r=flodiebold a=flodiebold This implements basic support for (fully qualified) associated type projections: - handle fully qualified paths like `<T as Trait>::AssocType` (basically desugaring to something like `Trait<Self=T>::AssocType`) - lower these to a new `Ty::Projection` enum variant - also introduce `Ty::UnselectedProjection` for cases like `T::AssocType` where the trait from which the type comes isn't specified, but these aren't handled further so far - in inference, normalize these projections using Chalk: basically, when encountering a type e.g. from a type annotation or signature, we replace these `Ty::Projection`s by type variables and add obligations to normalize the associated type Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r--crates/ra_hir/src/ty/infer.rs47
-rw-r--r--crates/ra_hir/src/ty/lower.rs83
-rw-r--r--crates/ra_hir/src/ty/tests.rs101
-rw-r--r--crates/ra_hir/src/ty/traits.rs8
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs51
5 files changed, 253 insertions, 37 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 594c5bc79..675df4a22 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -245,7 +245,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
245 &self.resolver, 245 &self.resolver,
246 type_ref, 246 type_ref,
247 ); 247 );
248 self.insert_type_vars(ty) 248 let ty = self.insert_type_vars(ty);
249 self.normalize_associated_types_in(ty)
249 } 250 }
250 251
251 fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool { 252 fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool {
@@ -411,6 +412,32 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
411 ty 412 ty
412 } 413 }
413 414
415 /// Recurses through the given type, normalizing associated types mentioned
416 /// in it by replacing them by type variables and registering obligations to
417 /// resolve later. This should be done once for every type we get from some
418 /// type annotation (e.g. from a let type annotation, field type or function
419 /// call). `make_ty` handles this already, but e.g. for field types we need
420 /// to do it as well.
421 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
422 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
423 ty.fold(&mut |ty| match ty {
424 Ty::Projection(proj_ty) => self.normalize_projection_ty(proj_ty),
425 Ty::UnselectedProjection(proj_ty) => {
426 // FIXME use Chalk's unselected projection support
427 Ty::UnselectedProjection(proj_ty)
428 }
429 _ => ty,
430 })
431 }
432
433 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
434 let var = self.new_type_var();
435 let predicate = ProjectionPredicate { projection_ty: proj_ty.clone(), ty: var.clone() };
436 let obligation = Obligation::Projection(predicate);
437 self.obligations.push(obligation);
438 var
439 }
440
414 /// Resolves the type completely; type variables without known type are 441 /// Resolves the type completely; type variables without known type are
415 /// replaced by Ty::Unknown. 442 /// replaced by Ty::Unknown.
416 fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { 443 fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
@@ -549,6 +576,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
549 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); 576 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
550 let ty = ty.subst(&substs); 577 let ty = ty.subst(&substs);
551 let ty = self.insert_type_vars(ty); 578 let ty = self.insert_type_vars(ty);
579 let ty = self.normalize_associated_types_in(ty);
552 Some(ty) 580 Some(ty)
553 } 581 }
554 Resolution::LocalBinding(pat) => { 582 Resolution::LocalBinding(pat) => {
@@ -670,6 +698,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
670 .and_then(|d| d.field(self.db, &Name::tuple_field_name(i))) 698 .and_then(|d| d.field(self.db, &Name::tuple_field_name(i)))
671 .map_or(Ty::Unknown, |field| field.ty(self.db)) 699 .map_or(Ty::Unknown, |field| field.ty(self.db))
672 .subst(&substs); 700 .subst(&substs);
701 let expected_ty = self.normalize_associated_types_in(expected_ty);
673 self.infer_pat(subpat, &expected_ty, default_bm); 702 self.infer_pat(subpat, &expected_ty, default_bm);
674 } 703 }
675 704
@@ -697,6 +726,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
697 let matching_field = def.and_then(|it| it.field(self.db, &subpat.name)); 726 let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
698 let expected_ty = 727 let expected_ty =
699 matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs); 728 matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs);
729 let expected_ty = self.normalize_associated_types_in(expected_ty);
700 self.infer_pat(subpat.pat, &expected_ty, default_bm); 730 self.infer_pat(subpat.pat, &expected_ty, default_bm);
701 } 731 }
702 732
@@ -927,9 +957,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
927 self.unify(&expected_receiver_ty, &actual_receiver_ty); 957 self.unify(&expected_receiver_ty, &actual_receiver_ty);
928 958
929 let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); 959 let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
930 for (arg, param) in args.iter().zip(param_iter) { 960 for (arg, param_ty) in args.iter().zip(param_iter) {
931 self.infer_expr(*arg, &Expectation::has_type(param)); 961 let param_ty = self.normalize_associated_types_in(param_ty);
962 self.infer_expr(*arg, &Expectation::has_type(param_ty));
932 } 963 }
964 let ret_ty = self.normalize_associated_types_in(ret_ty);
933 ret_ty 965 ret_ty
934 } 966 }
935 967
@@ -1020,9 +1052,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1020 }; 1052 };
1021 self.register_obligations_for_call(&callee_ty); 1053 self.register_obligations_for_call(&callee_ty);
1022 let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); 1054 let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
1023 for (arg, param) in args.iter().zip(param_iter) { 1055 for (arg, param_ty) in args.iter().zip(param_iter) {
1024 self.infer_expr(*arg, &Expectation::has_type(param)); 1056 let param_ty = self.normalize_associated_types_in(param_ty);
1057 self.infer_expr(*arg, &Expectation::has_type(param_ty));
1025 } 1058 }
1059 let ret_ty = self.normalize_associated_types_in(ret_ty);
1026 ret_ty 1060 ret_ty
1027 } 1061 }
1028 Expr::MethodCall { receiver, args, method_name, generic_args } => self 1062 Expr::MethodCall { receiver, args, method_name, generic_args } => self
@@ -1120,7 +1154,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1120 _ => None, 1154 _ => None,
1121 }) 1155 })
1122 .unwrap_or(Ty::Unknown); 1156 .unwrap_or(Ty::Unknown);
1123 self.insert_type_vars(ty) 1157 let ty = self.insert_type_vars(ty);
1158 self.normalize_associated_types_in(ty)
1124 } 1159 }
1125 Expr::Await { expr } => { 1160 Expr::Await { expr } => {
1126 let inner_ty = self.infer_expr(*expr, &Expectation::none()); 1161 let inner_ty = self.infer_expr(*expr, &Expectation::none());
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 894ba0695..debedcbb8 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -8,7 +8,7 @@
8use std::iter; 8use std::iter;
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use super::{FnSig, GenericPredicate, Substs, TraitRef, Ty, TypeCtor}; 11use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor};
12use crate::{ 12use crate::{
13 adt::VariantDef, 13 adt::VariantDef,
14 generics::HasGenericParams, 14 generics::HasGenericParams,
@@ -64,7 +64,8 @@ impl Ty {
64 64
65 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self { 65 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self {
66 // Resolve the path (in type namespace) 66 // Resolve the path (in type namespace)
67 let resolution = resolver.resolve_path_without_assoc_items(db, path).take_types(); 67 let (resolution, remaining_index) = resolver.resolve_path_segments(db, path).into_inner();
68 let resolution = resolution.take_types();
68 69
69 let def = match resolution { 70 let def = match resolution {
70 Some(Resolution::Def(def)) => def, 71 Some(Resolution::Def(def)) => def,
@@ -73,6 +74,10 @@ impl Ty {
73 panic!("path resolved to local binding in type ns"); 74 panic!("path resolved to local binding in type ns");
74 } 75 }
75 Some(Resolution::GenericParam(idx)) => { 76 Some(Resolution::GenericParam(idx)) => {
77 if remaining_index.is_some() {
78 // e.g. T::Item
79 return Ty::Unknown;
80 }
76 return Ty::Param { 81 return Ty::Param {
77 idx, 82 idx,
78 // FIXME: maybe return name in resolution? 83 // FIXME: maybe return name in resolution?
@@ -83,18 +88,54 @@ impl Ty {
83 }; 88 };
84 } 89 }
85 Some(Resolution::SelfType(impl_block)) => { 90 Some(Resolution::SelfType(impl_block)) => {
91 if remaining_index.is_some() {
92 // e.g. Self::Item
93 return Ty::Unknown;
94 }
86 return impl_block.target_ty(db); 95 return impl_block.target_ty(db);
87 } 96 }
88 None => return Ty::Unknown, 97 None => {
98 // path did not resolve
99 return Ty::Unknown;
100 }
89 }; 101 };
90 102
91 let typable: TypableDef = match def.into() { 103 if let ModuleDef::Trait(trait_) = def {
92 None => return Ty::Unknown, 104 let segment = match remaining_index {
93 Some(it) => it, 105 None => path.segments.last().expect("resolved path has at least one element"),
94 }; 106 Some(i) => &path.segments[i - 1],
95 let ty = db.type_for_def(typable, Namespace::Types); 107 };
96 let substs = Ty::substs_from_path(db, resolver, path, typable); 108 let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None);
97 ty.subst(&substs) 109 if let Some(remaining_index) = remaining_index {
110 if remaining_index == path.segments.len() - 1 {
111 let segment = &path.segments[remaining_index];
112 let associated_ty =
113 match trait_ref.trait_.associated_type_by_name(db, segment.name.clone()) {
114 Some(t) => t,
115 None => {
116 // associated type not found
117 return Ty::Unknown;
118 }
119 };
120 // FIXME handle type parameters on the segment
121 Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs })
122 } else {
123 // FIXME more than one segment remaining, is this possible?
124 Ty::Unknown
125 }
126 } else {
127 // FIXME dyn Trait without the dyn
128 Ty::Unknown
129 }
130 } else {
131 let typable: TypableDef = match def.into() {
132 None => return Ty::Unknown,
133 Some(it) => it,
134 };
135 let ty = db.type_for_def(typable, Namespace::Types);
136 let substs = Ty::substs_from_path(db, resolver, path, typable);
137 ty.subst(&substs)
138 }
98 } 139 }
99 140
100 pub(super) fn substs_from_path_segment( 141 pub(super) fn substs_from_path_segment(
@@ -219,14 +260,25 @@ impl TraitRef {
219 Resolution::Def(ModuleDef::Trait(tr)) => tr, 260 Resolution::Def(ModuleDef::Trait(tr)) => tr,
220 _ => return None, 261 _ => return None,
221 }; 262 };
222 let mut substs = Self::substs_from_path(db, resolver, path, resolved); 263 let segment = path.segments.last().expect("path should have at least one segment");
264 Some(TraitRef::from_resolved_path(db, resolver, resolved, segment, explicit_self_ty))
265 }
266
267 fn from_resolved_path(
268 db: &impl HirDatabase,
269 resolver: &Resolver,
270 resolved: Trait,
271 segment: &PathSegment,
272 explicit_self_ty: Option<Ty>,
273 ) -> Self {
274 let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved);
223 if let Some(self_ty) = explicit_self_ty { 275 if let Some(self_ty) = explicit_self_ty {
224 // FIXME this could be nicer 276 // FIXME this could be nicer
225 let mut substs_vec = substs.0.to_vec(); 277 let mut substs_vec = substs.0.to_vec();
226 substs_vec[0] = self_ty; 278 substs_vec[0] = self_ty;
227 substs.0 = substs_vec.into(); 279 substs.0 = substs_vec.into();
228 } 280 }
229 Some(TraitRef { trait_: resolved, substs }) 281 TraitRef { trait_: resolved, substs }
230 } 282 }
231 283
232 pub(crate) fn from_hir( 284 pub(crate) fn from_hir(
@@ -245,11 +297,12 @@ impl TraitRef {
245 fn substs_from_path( 297 fn substs_from_path(
246 db: &impl HirDatabase, 298 db: &impl HirDatabase,
247 resolver: &Resolver, 299 resolver: &Resolver,
248 path: &Path, 300 segment: &PathSegment,
249 resolved: Trait, 301 resolved: Trait,
250 ) -> Substs { 302 ) -> Substs {
251 let segment = path.segments.last().expect("path should have at least one segment"); 303 let has_self_param =
252 substs_from_path_segment(db, resolver, segment, Some(resolved.into()), true) 304 segment.args_and_bindings.as_ref().map(|a| a.has_self_type).unwrap_or(false);
305 substs_from_path_segment(db, resolver, segment, Some(resolved.into()), !has_self_param)
253 } 306 }
254 307
255 pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { 308 pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef {
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index d5f7a4d25..28727bb18 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2508,15 +2508,55 @@ struct S;
2508impl Iterable for S { type Item = u32; } 2508impl Iterable for S { type Item = u32; }
2509fn test<T: Iterable>() { 2509fn test<T: Iterable>() {
2510 let x: <S as Iterable>::Item = 1; 2510 let x: <S as Iterable>::Item = 1;
2511 let y: T::Item = no_matter; 2511 let y: <T as Iterable>::Item = no_matter;
2512 let z: T::Item = no_matter;
2512} 2513}
2513"#), 2514"#),
2514 @r###" 2515 @r###"
2515[108; 181) '{ ...ter; }': () 2516
2516[118; 119) 'x': i32 2517 ⋮[108; 227) '{ ...ter; }': ()
2517[145; 146) '1': i32 2518 ⋮[118; 119) 'x': u32
2518[156; 157) 'y': {unknown} 2519 ⋮[145; 146) '1': u32
2519[169; 178) 'no_matter': {unknown}"### 2520 ⋮[156; 157) 'y': {unknown}
2521 ⋮[183; 192) 'no_matter': {unknown}
2522 ⋮[202; 203) 'z': {unknown}
2523 ⋮[215; 224) 'no_matter': {unknown}
2524 "###
2525 );
2526}
2527
2528#[test]
2529fn infer_return_associated_type() {
2530 assert_snapshot_matches!(
2531 infer(r#"
2532trait Iterable {
2533 type Item;
2534}
2535struct S;
2536impl Iterable for S { type Item = u32; }
2537fn foo1<T: Iterable>(t: T) -> T::Item {}
2538fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {}
2539fn test() {
2540 let x = foo1(S);
2541 let y = foo2(S);
2542}
2543"#),
2544 @r###"
2545
2546 ⋮[106; 107) 't': T
2547 ⋮[123; 125) '{}': ()
2548 ⋮[147; 148) 't': T
2549 ⋮[178; 180) '{}': ()
2550 ⋮[191; 236) '{ ...(S); }': ()
2551 ⋮[201; 202) 'x': {unknown}
2552 ⋮[205; 209) 'foo1': fn foo1<S>(T) -> {unknown}
2553 ⋮[205; 212) 'foo1(S)': {unknown}
2554 ⋮[210; 211) 'S': S
2555 ⋮[222; 223) 'y': u32
2556 ⋮[226; 230) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item
2557 ⋮[226; 233) 'foo2(S)': u32
2558 ⋮[231; 232) 'S': S
2559 "###
2520 ); 2560 );
2521} 2561}
2522 2562
@@ -3141,6 +3181,55 @@ fn test<T: Trait>(t: T) { (*t)<|>; }
3141 assert_eq!(t, "i128"); 3181 assert_eq!(t, "i128");
3142} 3182}
3143 3183
3184#[test]
3185fn associated_type_placeholder() {
3186 let t = type_at(
3187 r#"
3188//- /main.rs
3189pub trait ApplyL {
3190 type Out;
3191}
3192
3193pub struct RefMutL<T>;
3194
3195impl<T> ApplyL for RefMutL<T> {
3196 type Out = <T as ApplyL>::Out;
3197}
3198
3199fn test<T: ApplyL>() {
3200 let y: <RefMutL<T> as ApplyL>::Out = no_matter;
3201 y<|>;
3202}
3203"#,
3204 );
3205 // 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].
3206 // FIXME: fix type parameter names going missing when going through Chalk
3207 assert_eq!(t, "ApplyL::Out<[missing name]>");
3208}
3209
3210#[test]
3211fn associated_type_placeholder_2() {
3212 let t = type_at(
3213 r#"
3214//- /main.rs
3215pub trait ApplyL {
3216 type Out;
3217}
3218fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out;
3219
3220fn test<T: ApplyL>(t: T) {
3221 let y = foo(t);
3222 y<|>;
3223}
3224"#,
3225 );
3226 // FIXME here Chalk doesn't normalize the type to a placeholder. I think we
3227 // need to add a rule like Normalize(<T as ApplyL>::Out -> ApplyL::Out<T>)
3228 // to the trait env ourselves here; probably Chalk can't do this by itself.
3229 // assert_eq!(t, "ApplyL::Out<[missing name]>");
3230 assert_eq!(t, "{unknown}");
3231}
3232
3144fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 3233fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
3145 let file = db.parse(pos.file_id).ok().unwrap(); 3234 let file = db.parse(pos.file_id).ok().unwrap();
3146 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 3235 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index 0769e6e17..fde5d8a47 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -7,7 +7,7 @@ use parking_lot::Mutex;
7use ra_prof::profile; 7use ra_prof::profile;
8use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
9 9
10use super::{Canonical, GenericPredicate, ProjectionTy, TraitRef, Ty}; 10use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty};
11use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; 11use crate::{db::HirDatabase, Crate, ImplBlock, Trait};
12 12
13use self::chalk::{from_chalk, ToChalk}; 13use self::chalk::{from_chalk, ToChalk};
@@ -61,7 +61,6 @@ fn solve(
61) -> Option<chalk_solve::Solution> { 61) -> Option<chalk_solve::Solution> {
62 let context = ChalkContext { db, krate }; 62 let context = ChalkContext { db, krate };
63 let solver = db.trait_solver(krate); 63 let solver = db.trait_solver(krate);
64 debug!("solve goal: {:?}", goal);
65 let solution = solver.lock().solve(&context, goal); 64 let solution = solver.lock().solve(&context, goal);
66 debug!("solve({:?}) => {:?}", goal, solution); 65 debug!("solve({:?}) => {:?}", goal, solution);
67 solution 66 solution
@@ -120,10 +119,11 @@ pub struct ProjectionPredicate {
120pub(crate) fn trait_solve_query( 119pub(crate) fn trait_solve_query(
121 db: &impl HirDatabase, 120 db: &impl HirDatabase,
122 krate: Crate, 121 krate: Crate,
123 trait_ref: Canonical<InEnvironment<Obligation>>, 122 goal: Canonical<InEnvironment<Obligation>>,
124) -> Option<Solution> { 123) -> Option<Solution> {
125 let _p = profile("trait_solve_query"); 124 let _p = profile("trait_solve_query");
126 let canonical = trait_ref.to_chalk(db).cast(); 125 debug!("trait_solve_query({})", goal.value.value.display(db));
126 let canonical = goal.to_chalk(db).cast();
127 // We currently don't deal with universes (I think / hope they're not yet 127 // We currently don't deal with universes (I think / hope they're not yet
128 // relevant for our use cases?) 128 // relevant for our use cases?)
129 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; 129 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 9e7ae0724..6df7094c5 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -45,11 +45,33 @@ impl ToChalk for Ty {
45 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { 45 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty {
46 match self { 46 match self {
47 Ty::Apply(apply_ty) => { 47 Ty::Apply(apply_ty) => {
48 let struct_id = apply_ty.ctor.to_chalk(db); 48 let name = match apply_ty.ctor {
49 let name = TypeName::TypeKindId(struct_id.into()); 49 TypeCtor::AssociatedType(type_alias) => {
50 let type_id = type_alias.to_chalk(db);
51 TypeName::AssociatedType(type_id)
52 }
53 _ => {
54 // other TypeCtors get interned and turned into a chalk StructId
55 let struct_id = apply_ty.ctor.to_chalk(db);
56 TypeName::TypeKindId(struct_id.into())
57 }
58 };
50 let parameters = apply_ty.parameters.to_chalk(db); 59 let parameters = apply_ty.parameters.to_chalk(db);
51 chalk_ir::ApplicationTy { name, parameters }.cast() 60 chalk_ir::ApplicationTy { name, parameters }.cast()
52 } 61 }
62 Ty::Projection(proj_ty) => {
63 let associated_ty_id = proj_ty.associated_ty.to_chalk(db);
64 let parameters = proj_ty.parameters.to_chalk(db);
65 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast()
66 }
67 Ty::UnselectedProjection(proj_ty) => {
68 let type_name = lalrpop_intern::intern(&proj_ty.type_name.to_string());
69 let parameters = proj_ty.parameters.to_chalk(db);
70 chalk_ir::Ty::UnselectedProjection(chalk_ir::UnselectedProjectionTy {
71 type_name,
72 parameters,
73 })
74 }
53 Ty::Param { idx, .. } => { 75 Ty::Param { idx, .. } => {
54 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty() 76 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty()
55 } 77 }
@@ -66,15 +88,21 @@ impl ToChalk for Ty {
66 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { 88 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self {
67 match chalk { 89 match chalk {
68 chalk_ir::Ty::Apply(apply_ty) => { 90 chalk_ir::Ty::Apply(apply_ty) => {
91 // FIXME this is kind of hacky due to the fact that
92 // TypeName::Placeholder is a Ty::Param on our side
69 match apply_ty.name { 93 match apply_ty.name {
70 TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => { 94 TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => {
71 let ctor = from_chalk(db, struct_id); 95 let ctor = from_chalk(db, struct_id);
72 let parameters = from_chalk(db, apply_ty.parameters); 96 let parameters = from_chalk(db, apply_ty.parameters);
73 Ty::Apply(ApplicationTy { ctor, parameters }) 97 Ty::Apply(ApplicationTy { ctor, parameters })
74 } 98 }
99 TypeName::AssociatedType(type_id) => {
100 let ctor = TypeCtor::AssociatedType(from_chalk(db, type_id));
101 let parameters = from_chalk(db, apply_ty.parameters);
102 Ty::Apply(ApplicationTy { ctor, parameters })
103 }
75 // FIXME handle TypeKindId::Trait/Type here 104 // FIXME handle TypeKindId::Trait/Type here
76 TypeName::TypeKindId(_) => unimplemented!(), 105 TypeName::TypeKindId(_) => unimplemented!(),
77 TypeName::AssociatedType(_) => unimplemented!(),
78 TypeName::Placeholder(idx) => { 106 TypeName::Placeholder(idx) => {
79 assert_eq!(idx.ui, UniverseIndex::ROOT); 107 assert_eq!(idx.ui, UniverseIndex::ROOT);
80 Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() } 108 Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() }
@@ -389,11 +417,12 @@ where
389 &self, 417 &self,
390 projection: &'p chalk_ir::ProjectionTy, 418 projection: &'p chalk_ir::ProjectionTy,
391 ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) { 419 ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) {
392 debug!("split_projection {:?}", projection); 420 let proj_ty: ProjectionTy = from_chalk(self.db, projection.clone());
393 unimplemented!() 421 debug!("split_projection {:?} = {}", projection, proj_ty.display(self.db));
422 // we don't support GATs, so I think this should always be correct currently
423 (self.db.associated_ty_data(projection.associated_ty_id), &projection.parameters, &[])
394 } 424 }
395 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> { 425 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> {
396 debug!("custom_clauses");
397 vec![] 426 vec![]
398 } 427 }
399 fn all_structs(&self) -> Vec<chalk_ir::StructId> { 428 fn all_structs(&self) -> Vec<chalk_ir::StructId> {
@@ -529,6 +558,16 @@ pub(crate) fn struct_datum_query(
529 adt.krate(db) != Some(krate), 558 adt.krate(db) != Some(krate),
530 ) 559 )
531 } 560 }
561 TypeCtor::AssociatedType(type_alias) => {
562 let generic_params = type_alias.generic_params(db);
563 let bound_vars = Substs::bound_vars(&generic_params);
564 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
565 (
566 generic_params.count_params_including_parent(),
567 where_clauses,
568 type_alias.krate(db) != Some(krate),
569 )
570 }
532 }; 571 };
533 let flags = chalk_rust_ir::StructFlags { 572 let flags = chalk_rust_ir::StructFlags {
534 upstream, 573 upstream,