diff options
author | Florian Diebold <[email protected]> | 2019-08-23 16:19:37 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-09-03 13:00:35 +0100 |
commit | 741e350d4b7c3561f242207541ac9d7cab6ce45f (patch) | |
tree | 8ab45d1f2491395eba0e6f938eddc65f15d2667d /crates/ra_hir/src/ty | |
parent | 966ab9abd2253e68d2e410a58dc1328805ee7f61 (diff) |
Add support for associated type bindings (`where Trait<Type = X>`)
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 85 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 62 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 27 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 7 |
4 files changed, 135 insertions, 46 deletions
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 47d161277..0011c06b4 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -8,7 +8,9 @@ | |||
8 | use std::iter; | 8 | use std::iter; |
9 | use std::sync::Arc; | 9 | use std::sync::Arc; |
10 | 10 | ||
11 | use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor}; | 11 | use super::{ |
12 | FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | ||
13 | }; | ||
12 | use crate::{ | 14 | use crate::{ |
13 | adt::VariantDef, | 15 | adt::VariantDef, |
14 | generics::HasGenericParams, | 16 | generics::HasGenericParams, |
@@ -62,7 +64,9 @@ impl Ty { | |||
62 | let self_ty = Ty::Bound(0); | 64 | let self_ty = Ty::Bound(0); |
63 | let predicates = bounds | 65 | let predicates = bounds |
64 | .iter() | 66 | .iter() |
65 | .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) | 67 | .flat_map(|b| { |
68 | GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()) | ||
69 | }) | ||
66 | .collect::<Vec<_>>(); | 70 | .collect::<Vec<_>>(); |
67 | Ty::Dyn(predicates.into()) | 71 | Ty::Dyn(predicates.into()) |
68 | } | 72 | } |
@@ -70,7 +74,9 @@ impl Ty { | |||
70 | let self_ty = Ty::Bound(0); | 74 | let self_ty = Ty::Bound(0); |
71 | let predicates = bounds | 75 | let predicates = bounds |
72 | .iter() | 76 | .iter() |
73 | .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) | 77 | .flat_map(|b| { |
78 | GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()) | ||
79 | }) | ||
74 | .collect::<Vec<_>>(); | 80 | .collect::<Vec<_>>(); |
75 | Ty::Opaque(predicates.into()) | 81 | Ty::Opaque(predicates.into()) |
76 | } | 82 | } |
@@ -326,15 +332,6 @@ impl TraitRef { | |||
326 | TraitRef { trait_, substs } | 332 | TraitRef { trait_, substs } |
327 | } | 333 | } |
328 | 334 | ||
329 | pub(crate) fn from_where_predicate( | ||
330 | db: &impl HirDatabase, | ||
331 | resolver: &Resolver, | ||
332 | pred: &WherePredicate, | ||
333 | ) -> Option<TraitRef> { | ||
334 | let self_ty = Ty::from_hir(db, resolver, &pred.type_ref); | ||
335 | TraitRef::from_type_bound(db, resolver, &pred.bound, self_ty) | ||
336 | } | ||
337 | |||
338 | pub(crate) fn from_type_bound( | 335 | pub(crate) fn from_type_bound( |
339 | db: &impl HirDatabase, | 336 | db: &impl HirDatabase, |
340 | resolver: &Resolver, | 337 | resolver: &Resolver, |
@@ -349,26 +346,58 @@ impl TraitRef { | |||
349 | } | 346 | } |
350 | 347 | ||
351 | impl GenericPredicate { | 348 | impl GenericPredicate { |
352 | pub(crate) fn from_where_predicate( | 349 | pub(crate) fn from_where_predicate<'a>( |
353 | db: &impl HirDatabase, | 350 | db: &'a impl HirDatabase, |
354 | resolver: &Resolver, | 351 | resolver: &'a Resolver, |
355 | where_predicate: &WherePredicate, | 352 | where_predicate: &'a WherePredicate, |
356 | ) -> GenericPredicate { | 353 | ) -> impl Iterator<Item = GenericPredicate> + 'a { |
357 | TraitRef::from_where_predicate(db, &resolver, where_predicate) | 354 | let self_ty = Ty::from_hir(db, resolver, &where_predicate.type_ref); |
358 | .map_or(GenericPredicate::Error, GenericPredicate::Implemented) | 355 | GenericPredicate::from_type_bound(db, resolver, &where_predicate.bound, self_ty) |
359 | } | 356 | } |
360 | 357 | ||
361 | pub(crate) fn from_type_bound( | 358 | pub(crate) fn from_type_bound<'a>( |
362 | db: &impl HirDatabase, | 359 | db: &'a impl HirDatabase, |
363 | resolver: &Resolver, | 360 | resolver: &'a Resolver, |
364 | bound: &TypeBound, | 361 | bound: &'a TypeBound, |
365 | self_ty: Ty, | 362 | self_ty: Ty, |
366 | ) -> GenericPredicate { | 363 | ) -> impl Iterator<Item = GenericPredicate> + 'a { |
367 | TraitRef::from_type_bound(db, &resolver, bound, self_ty) | 364 | let trait_ref = TraitRef::from_type_bound(db, &resolver, bound, self_ty); |
368 | .map_or(GenericPredicate::Error, GenericPredicate::Implemented) | 365 | iter::once(trait_ref.clone().map_or(GenericPredicate::Error, GenericPredicate::Implemented)) |
366 | .chain( | ||
367 | trait_ref.into_iter().flat_map(move |tr| { | ||
368 | assoc_type_bindings_from_type_bound(db, resolver, bound, tr) | ||
369 | }), | ||
370 | ) | ||
369 | } | 371 | } |
370 | } | 372 | } |
371 | 373 | ||
374 | fn assoc_type_bindings_from_type_bound<'a>( | ||
375 | db: &'a impl HirDatabase, | ||
376 | resolver: &'a Resolver, | ||
377 | bound: &'a TypeBound, | ||
378 | trait_ref: TraitRef, | ||
379 | ) -> impl Iterator<Item = GenericPredicate> + 'a { | ||
380 | let last_segment = match bound { | ||
381 | TypeBound::Path(path) => path.segments.last(), | ||
382 | TypeBound::Error => None, | ||
383 | }; | ||
384 | last_segment | ||
385 | .into_iter() | ||
386 | .flat_map(|segment| segment.args_and_bindings.iter()) | ||
387 | .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) | ||
388 | .map(move |(name, type_ref)| { | ||
389 | let associated_ty = match trait_ref.trait_.associated_type_by_name(db, name.clone()) { | ||
390 | None => return GenericPredicate::Error, | ||
391 | Some(t) => t, | ||
392 | }; | ||
393 | let projection_ty = | ||
394 | ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; | ||
395 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
396 | let projection_predicate = ProjectionPredicate { projection_ty, ty }; | ||
397 | GenericPredicate::Projection(projection_predicate) | ||
398 | }) | ||
399 | } | ||
400 | |||
372 | /// Build the declared type of an item. This depends on the namespace; e.g. for | 401 | /// Build the declared type of an item. This depends on the namespace; e.g. for |
373 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and | 402 | /// `struct Foo(usize)`, we have two types: The type of the struct itself, and |
374 | /// the constructor function `(usize) -> Foo` which lives in the values | 403 | /// the constructor function `(usize) -> Foo` which lives in the values |
@@ -425,7 +454,7 @@ pub(crate) fn trait_env( | |||
425 | ) -> Arc<super::TraitEnvironment> { | 454 | ) -> Arc<super::TraitEnvironment> { |
426 | let predicates = resolver | 455 | let predicates = resolver |
427 | .where_predicates_in_scope() | 456 | .where_predicates_in_scope() |
428 | .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) | 457 | .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) |
429 | .collect::<Vec<_>>(); | 458 | .collect::<Vec<_>>(); |
430 | 459 | ||
431 | Arc::new(super::TraitEnvironment { predicates }) | 460 | Arc::new(super::TraitEnvironment { predicates }) |
@@ -439,7 +468,7 @@ pub(crate) fn generic_predicates_query( | |||
439 | let resolver = def.resolver(db); | 468 | let resolver = def.resolver(db); |
440 | let predicates = resolver | 469 | let predicates = resolver |
441 | .where_predicates_in_scope() | 470 | .where_predicates_in_scope() |
442 | .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) | 471 | .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) |
443 | .collect::<Vec<_>>(); | 472 | .collect::<Vec<_>>(); |
444 | predicates.into() | 473 | predicates.into() |
445 | } | 474 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 42bcae157..3e743ef58 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3586,37 +3586,63 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { | |||
3586 | [166; 169) '{t}': T | 3586 | [166; 169) '{t}': T |
3587 | [167; 168) 't': T | 3587 | [167; 168) 't': T |
3588 | [257; 258) 'x': T | 3588 | [257; 258) 'x': T |
3589 | [263; 264) 'y': impl Trait | 3589 | [263; 264) 'y': impl Trait + |
3590 | [290; 398) '{ ...r>); }': () | 3590 | [290; 398) '{ ...r>); }': () |
3591 | [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type | 3591 | [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type |
3592 | [296; 302) 'get(x)': {unknown} | 3592 | [296; 302) 'get(x)': {unknown} |
3593 | [300; 301) 'x': T | 3593 | [300; 301) 'x': T |
3594 | [308; 312) 'get2': fn get2<{unknown}, T>(T) -> U | 3594 | [308; 312) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U |
3595 | [308; 315) 'get2(x)': {unknown} | 3595 | [308; 315) 'get2(x)': {unknown} |
3596 | [313; 314) 'x': T | 3596 | [313; 314) 'x': T |
3597 | [321; 324) 'get': fn get<impl Trait>(T) -> <T as Trait>::Type | 3597 | [321; 324) 'get': fn get<impl Trait + >(T) -> <T as Trait>::Type |
3598 | [321; 327) 'get(y)': {unknown} | 3598 | [321; 327) 'get(y)': {unknown} |
3599 | [325; 326) 'y': impl Trait | 3599 | [325; 326) 'y': impl Trait + |
3600 | [333; 337) 'get2': fn get2<{unknown}, impl Trait>(T) -> U | 3600 | [333; 337) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U |
3601 | [333; 340) 'get2(y)': {unknown} | 3601 | [333; 340) 'get2(y)': {unknown} |
3602 | [338; 339) 'y': impl Trait | 3602 | [338; 339) 'y': impl Trait + |
3603 | [346; 349) 'get': fn get<S<{unknown}>>(T) -> <T as Trait>::Type | 3603 | [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type |
3604 | [346; 357) 'get(set(S))': {unknown} | 3604 | [346; 357) 'get(set(S))': u64 |
3605 | [350; 353) 'set': fn set<S<{unknown}>>(T) -> T | 3605 | [350; 353) 'set': fn set<S<u64>>(T) -> T |
3606 | [350; 356) 'set(S)': S<{unknown}> | 3606 | [350; 356) 'set(S)': S<u64> |
3607 | [354; 355) 'S': S<{unknown}> | 3607 | [354; 355) 'S': S<u64> |
3608 | [363; 367) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U | 3608 | [363; 367) 'get2': fn get2<u64, S<u64>>(T) -> U |
3609 | [363; 375) 'get2(set(S))': {unknown} | 3609 | [363; 375) 'get2(set(S))': u64 |
3610 | [368; 371) 'set': fn set<S<{unknown}>>(T) -> T | 3610 | [368; 371) 'set': fn set<S<u64>>(T) -> T |
3611 | [368; 374) 'set(S)': S<{unknown}> | 3611 | [368; 374) 'set(S)': S<u64> |
3612 | [372; 373) 'S': S<{unknown}> | 3612 | [372; 373) 'S': S<u64> |
3613 | [381; 385) 'get2': fn get2<{unknown}, S<str>>(T) -> U | 3613 | [381; 385) 'get2': fn get2<str, S<str>>(T) -> U |
3614 | [381; 395) 'get2(S::<str>)': {unknown} | 3614 | [381; 395) 'get2(S::<str>)': str |
3615 | [386; 394) 'S::<str>': S<str> | 3615 | [386; 394) 'S::<str>': S<str> |
3616 | "### | 3616 | "### |
3617 | ); | 3617 | ); |
3618 | } | 3618 | } |
3619 | 3619 | ||
3620 | #[test] | ||
3621 | fn projection_eq_within_chalk() { | ||
3622 | // std::env::set_var("CHALK_DEBUG", "1"); | ||
3623 | assert_snapshot!( | ||
3624 | infer(r#" | ||
3625 | trait Trait1 { | ||
3626 | type Type; | ||
3627 | } | ||
3628 | trait Trait2<T> { | ||
3629 | fn foo(self) -> T; | ||
3630 | } | ||
3631 | impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {} | ||
3632 | |||
3633 | fn test<T: Trait1<Type = u32>>(x: T) { | ||
3634 | x.foo(); | ||
3635 | } | ||
3636 | "#), | ||
3637 | @r###" | ||
3638 | [62; 66) 'self': Self | ||
3639 | [164; 165) 'x': T | ||
3640 | [170; 186) '{ ...o(); }': () | ||
3641 | [176; 177) 'x': T | ||
3642 | [176; 183) 'x.foo()': {unknown} | ||
3643 | "### | ||
3644 | ); | ||
3645 | } | ||
3620 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 3646 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
3621 | let file = db.parse(pos.file_id).ok().unwrap(); | 3647 | let file = db.parse(pos.file_id).ok().unwrap(); |
3622 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 3648 | 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 b634f0b79..25316bc02 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -124,6 +124,9 @@ impl Obligation { | |||
124 | pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> { | 124 | pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> { |
125 | match predicate { | 125 | match predicate { |
126 | GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)), | 126 | GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)), |
127 | GenericPredicate::Projection(projection_pred) => { | ||
128 | Some(Obligation::Projection(projection_pred)) | ||
129 | } | ||
127 | GenericPredicate::Error => None, | 130 | GenericPredicate::Error => None, |
128 | } | 131 | } |
129 | } | 132 | } |
@@ -135,6 +138,30 @@ pub struct ProjectionPredicate { | |||
135 | pub ty: Ty, | 138 | pub ty: Ty, |
136 | } | 139 | } |
137 | 140 | ||
141 | impl ProjectionPredicate { | ||
142 | pub fn subst(mut self, substs: &super::Substs) -> ProjectionPredicate { | ||
143 | self.walk_mut(&mut |ty| match ty { | ||
144 | Ty::Param { idx, .. } => { | ||
145 | if let Some(t) = substs.get(*idx as usize).cloned() { | ||
146 | *ty = t; | ||
147 | } | ||
148 | } | ||
149 | _ => {} | ||
150 | }); | ||
151 | self | ||
152 | } | ||
153 | |||
154 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
155 | self.projection_ty.walk(f); | ||
156 | self.ty.walk(f); | ||
157 | } | ||
158 | |||
159 | pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | ||
160 | self.projection_ty.walk_mut(f); | ||
161 | self.ty.walk_mut(f); | ||
162 | } | ||
163 | } | ||
164 | |||
138 | /// Solve a trait goal using Chalk. | 165 | /// Solve a trait goal using Chalk. |
139 | pub(crate) fn trait_solve_query( | 166 | pub(crate) fn trait_solve_query( |
140 | db: &impl HirDatabase, | 167 | db: &impl HirDatabase, |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 2ebc06135..3ab5b7cca 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -211,6 +211,13 @@ impl ToChalk for GenericPredicate { | |||
211 | GenericPredicate::Implemented(trait_ref) => { | 211 | GenericPredicate::Implemented(trait_ref) => { |
212 | make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) | 212 | make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) |
213 | } | 213 | } |
214 | GenericPredicate::Projection(projection_pred) => make_binders( | ||
215 | chalk_ir::WhereClause::ProjectionEq(chalk_ir::ProjectionEq { | ||
216 | projection: projection_pred.projection_ty.to_chalk(db), | ||
217 | ty: projection_pred.ty.to_chalk(db), | ||
218 | }), | ||
219 | 0, | ||
220 | ), | ||
214 | GenericPredicate::Error => { | 221 | GenericPredicate::Error => { |
215 | let impossible_trait_ref = chalk_ir::TraitRef { | 222 | let impossible_trait_ref = chalk_ir::TraitRef { |
216 | trait_id: UNKNOWN_TRAIT, | 223 | trait_id: UNKNOWN_TRAIT, |