aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-08-23 16:19:37 +0100
committerFlorian Diebold <[email protected]>2019-09-03 13:00:35 +0100
commit741e350d4b7c3561f242207541ac9d7cab6ce45f (patch)
tree8ab45d1f2491395eba0e6f938eddc65f15d2667d /crates/ra_hir/src/ty
parent966ab9abd2253e68d2e410a58dc1328805ee7f61 (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.rs85
-rw-r--r--crates/ra_hir/src/ty/tests.rs62
-rw-r--r--crates/ra_hir/src/ty/traits.rs27
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs7
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 @@
8use std::iter; 8use std::iter;
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor}; 11use super::{
12 FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
13};
12use crate::{ 14use 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
351impl GenericPredicate { 348impl 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
374fn 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]
3621fn projection_eq_within_chalk() {
3622 // std::env::set_var("CHALK_DEBUG", "1");
3623 assert_snapshot!(
3624 infer(r#"
3625trait Trait1 {
3626 type Type;
3627}
3628trait Trait2<T> {
3629 fn foo(self) -> T;
3630}
3631impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {}
3632
3633fn 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}
3620fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 3646fn 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
141impl 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.
139pub(crate) fn trait_solve_query( 166pub(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,