diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-09-03 13:17:58 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-09-03 13:17:58 +0100 |
commit | bac73ade7f73d9b7bafaf369a0b206a4ffea73dd (patch) | |
tree | ddd1737a8e3f46fb8757bad1d8024469d3bf0a89 /crates | |
parent | 1c0672b7f802c7e7814ba9a1b3b21ecf866343d6 (diff) | |
parent | b8c1e402fa3a40c7e979750d60d7b003f9cb7b0d (diff) |
Merge #1757
1757: Assoc type bindings r=flodiebold a=flodiebold
This adds support for type bindings (bounds like `where T: Iterator<Item = u32>`).
It doesn't yet work in as many situations as I'd like because of some [Chalk problems](https://github.com/rust-lang/chalk/issues/234). But it works in some situations, and will at least not bitrot this way ;)
(part of the problem is that we use `Normalize` to normalize associated types, but produce `ProjectionEq` goals from where clauses, so Chalk can't normalize using the environment; this would be fixed by using `ProjectionEq` for normalization, which I think is the 'proper' way, but then we'd run into those ambiguity problems everywhere...)
Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_cli/src/analysis_stats.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 348 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer/unify.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 86 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 91 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 8 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/presentation.rs | 2 |
12 files changed, 427 insertions, 158 deletions
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs index 5c0a9dd98..1fad5b233 100644 --- a/crates/ra_cli/src/analysis_stats.rs +++ b/crates/ra_cli/src/analysis_stats.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; | 1 | use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; |
2 | 2 | ||
3 | use ra_db::SourceDatabase; | 3 | use ra_db::SourceDatabase; |
4 | use ra_hir::{Crate, HasBodySource, HasSource, HirDisplay, ImplItem, ModuleDef, Ty}; | 4 | use ra_hir::{Crate, HasBodySource, HasSource, HirDisplay, ImplItem, ModuleDef, Ty, TypeWalk}; |
5 | use ra_syntax::AstNode; | 5 | use ra_syntax::AstNode; |
6 | 6 | ||
7 | use crate::Result; | 7 | use crate::Result; |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 752653ad7..c3e589921 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -69,7 +69,9 @@ pub use self::{ | |||
69 | resolve::Resolution, | 69 | resolve::Resolution, |
70 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, | 70 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, |
71 | source_id::{AstIdMap, ErasedFileAstId}, | 71 | source_id::{AstIdMap, ErasedFileAstId}, |
72 | ty::{display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor}, | 72 | ty::{ |
73 | display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, | ||
74 | }, | ||
73 | type_ref::Mutability, | 75 | type_ref::Mutability, |
74 | }; | 76 | }; |
75 | 77 | ||
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 5ee71e421..24316fc91 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -31,7 +31,8 @@ pub struct GenericArgs { | |||
31 | /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type | 31 | /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type |
32 | /// is left out. | 32 | /// is left out. |
33 | pub has_self_type: bool, | 33 | pub has_self_type: bool, |
34 | // someday also bindings | 34 | /// Associated type bindings like in `Iterator<Item = T>`. |
35 | pub bindings: Vec<(Name, TypeRef)>, | ||
35 | } | 36 | } |
36 | 37 | ||
37 | /// A single generic argument. | 38 | /// A single generic argument. |
@@ -170,16 +171,24 @@ impl GenericArgs { | |||
170 | let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); | 171 | let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); |
171 | args.push(GenericArg::Type(type_ref)); | 172 | args.push(GenericArg::Type(type_ref)); |
172 | } | 173 | } |
173 | // lifetimes and assoc type args ignored for now | 174 | // lifetimes ignored for now |
174 | if !args.is_empty() { | 175 | let mut bindings = Vec::new(); |
175 | Some(GenericArgs { args, has_self_type: false }) | 176 | for assoc_type_arg in node.assoc_type_args() { |
176 | } else { | 177 | if let Some(name_ref) = assoc_type_arg.name_ref() { |
178 | let name = name_ref.as_name(); | ||
179 | let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref()); | ||
180 | bindings.push((name, type_ref)); | ||
181 | } | ||
182 | } | ||
183 | if args.is_empty() && bindings.is_empty() { | ||
177 | None | 184 | None |
185 | } else { | ||
186 | Some(GenericArgs { args, has_self_type: false, bindings }) | ||
178 | } | 187 | } |
179 | } | 188 | } |
180 | 189 | ||
181 | pub(crate) fn empty() -> GenericArgs { | 190 | pub(crate) fn empty() -> GenericArgs { |
182 | GenericArgs { args: Vec::new(), has_self_type: false } | 191 | GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() } |
183 | } | 192 | } |
184 | } | 193 | } |
185 | 194 | ||
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index b54c80318..a3df08827 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -120,12 +120,44 @@ pub struct ProjectionTy { | |||
120 | pub parameters: Substs, | 120 | pub parameters: Substs, |
121 | } | 121 | } |
122 | 122 | ||
123 | impl ProjectionTy { | ||
124 | pub fn trait_ref(&self, db: &impl HirDatabase) -> TraitRef { | ||
125 | TraitRef { | ||
126 | trait_: self | ||
127 | .associated_ty | ||
128 | .parent_trait(db) | ||
129 | .expect("projection ty without parent trait"), | ||
130 | substs: self.parameters.clone(), | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | impl TypeWalk for ProjectionTy { | ||
136 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
137 | self.parameters.walk(f); | ||
138 | } | ||
139 | |||
140 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | ||
141 | self.parameters.walk_mut(f); | ||
142 | } | ||
143 | } | ||
144 | |||
123 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 145 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
124 | pub struct UnselectedProjectionTy { | 146 | pub struct UnselectedProjectionTy { |
125 | pub type_name: Name, | 147 | pub type_name: Name, |
126 | pub parameters: Substs, | 148 | pub parameters: Substs, |
127 | } | 149 | } |
128 | 150 | ||
151 | impl TypeWalk for UnselectedProjectionTy { | ||
152 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
153 | self.parameters.walk(f); | ||
154 | } | ||
155 | |||
156 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | ||
157 | self.parameters.walk_mut(f); | ||
158 | } | ||
159 | } | ||
160 | |||
129 | /// A type. | 161 | /// A type. |
130 | /// | 162 | /// |
131 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents | 163 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents |
@@ -282,20 +314,14 @@ impl TraitRef { | |||
282 | pub fn self_ty(&self) -> &Ty { | 314 | pub fn self_ty(&self) -> &Ty { |
283 | &self.substs[0] | 315 | &self.substs[0] |
284 | } | 316 | } |
317 | } | ||
285 | 318 | ||
286 | pub fn subst(mut self, substs: &Substs) -> TraitRef { | 319 | impl TypeWalk for TraitRef { |
287 | self.substs.walk_mut(&mut |ty_mut| { | 320 | fn walk(&self, f: &mut impl FnMut(&Ty)) { |
288 | let ty = mem::replace(ty_mut, Ty::Unknown); | ||
289 | *ty_mut = ty.subst(substs); | ||
290 | }); | ||
291 | self | ||
292 | } | ||
293 | |||
294 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
295 | self.substs.walk(f); | 321 | self.substs.walk(f); |
296 | } | 322 | } |
297 | 323 | ||
298 | pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | 324 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { |
299 | self.substs.walk_mut(f); | 325 | self.substs.walk_mut(f); |
300 | } | 326 | } |
301 | } | 327 | } |
@@ -306,6 +332,8 @@ impl TraitRef { | |||
306 | pub enum GenericPredicate { | 332 | pub enum GenericPredicate { |
307 | /// The given trait needs to be implemented for its type parameters. | 333 | /// The given trait needs to be implemented for its type parameters. |
308 | Implemented(TraitRef), | 334 | Implemented(TraitRef), |
335 | /// An associated type bindings like in `Iterator<Item = T>`. | ||
336 | Projection(ProjectionPredicate), | ||
309 | /// We couldn't resolve the trait reference. (If some type parameters can't | 337 | /// We couldn't resolve the trait reference. (If some type parameters can't |
310 | /// be resolved, they will just be Unknown). | 338 | /// be resolved, they will just be Unknown). |
311 | Error, | 339 | Error, |
@@ -319,25 +347,35 @@ impl GenericPredicate { | |||
319 | } | 347 | } |
320 | } | 348 | } |
321 | 349 | ||
322 | pub fn subst(self, substs: &Substs) -> GenericPredicate { | 350 | pub fn is_implemented(&self) -> bool { |
323 | match self { | 351 | match self { |
324 | GenericPredicate::Implemented(trait_ref) => { | 352 | GenericPredicate::Implemented(_) => true, |
325 | GenericPredicate::Implemented(trait_ref.subst(substs)) | 353 | _ => false, |
326 | } | ||
327 | GenericPredicate::Error => self, | ||
328 | } | 354 | } |
329 | } | 355 | } |
330 | 356 | ||
331 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { | 357 | pub fn trait_ref(&self, db: &impl HirDatabase) -> Option<TraitRef> { |
358 | match self { | ||
359 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | ||
360 | GenericPredicate::Projection(proj) => Some(proj.projection_ty.trait_ref(db)), | ||
361 | GenericPredicate::Error => None, | ||
362 | } | ||
363 | } | ||
364 | } | ||
365 | |||
366 | impl TypeWalk for GenericPredicate { | ||
367 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
332 | match self { | 368 | match self { |
333 | GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f), | 369 | GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f), |
370 | GenericPredicate::Projection(projection_pred) => projection_pred.walk(f), | ||
334 | GenericPredicate::Error => {} | 371 | GenericPredicate::Error => {} |
335 | } | 372 | } |
336 | } | 373 | } |
337 | 374 | ||
338 | pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | 375 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { |
339 | match self { | 376 | match self { |
340 | GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f), | 377 | GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f), |
378 | GenericPredicate::Projection(projection_pred) => projection_pred.walk_mut(f), | ||
341 | GenericPredicate::Error => {} | 379 | GenericPredicate::Error => {} |
342 | } | 380 | } |
343 | } | 381 | } |
@@ -378,16 +416,16 @@ impl FnSig { | |||
378 | pub fn ret(&self) -> &Ty { | 416 | pub fn ret(&self) -> &Ty { |
379 | &self.params_and_return[self.params_and_return.len() - 1] | 417 | &self.params_and_return[self.params_and_return.len() - 1] |
380 | } | 418 | } |
419 | } | ||
381 | 420 | ||
382 | /// Applies the given substitutions to all types in this signature and | 421 | impl TypeWalk for FnSig { |
383 | /// returns the result. | 422 | fn walk(&self, f: &mut impl FnMut(&Ty)) { |
384 | pub fn subst(&self, substs: &Substs) -> FnSig { | 423 | for t in self.params_and_return.iter() { |
385 | let result: Vec<_> = | 424 | t.walk(f); |
386 | self.params_and_return.iter().map(|ty| ty.clone().subst(substs)).collect(); | 425 | } |
387 | FnSig { params_and_return: result.into() } | ||
388 | } | 426 | } |
389 | 427 | ||
390 | pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | 428 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { |
391 | // Without an Arc::make_mut_slice, we can't avoid the clone here: | 429 | // Without an Arc::make_mut_slice, we can't avoid the clone here: |
392 | let mut v: Vec<_> = self.params_and_return.iter().cloned().collect(); | 430 | let mut v: Vec<_> = self.params_and_return.iter().cloned().collect(); |
393 | for t in &mut v { | 431 | for t in &mut v { |
@@ -411,64 +449,6 @@ impl Ty { | |||
411 | Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty()) | 449 | Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty()) |
412 | } | 450 | } |
413 | 451 | ||
414 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
415 | match self { | ||
416 | Ty::Apply(a_ty) => { | ||
417 | for t in a_ty.parameters.iter() { | ||
418 | t.walk(f); | ||
419 | } | ||
420 | } | ||
421 | Ty::Projection(p_ty) => { | ||
422 | for t in p_ty.parameters.iter() { | ||
423 | t.walk(f); | ||
424 | } | ||
425 | } | ||
426 | Ty::UnselectedProjection(p_ty) => { | ||
427 | for t in p_ty.parameters.iter() { | ||
428 | t.walk(f); | ||
429 | } | ||
430 | } | ||
431 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | ||
432 | for p in predicates.iter() { | ||
433 | p.walk(f); | ||
434 | } | ||
435 | } | ||
436 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | ||
437 | } | ||
438 | f(self); | ||
439 | } | ||
440 | |||
441 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | ||
442 | match self { | ||
443 | Ty::Apply(a_ty) => { | ||
444 | a_ty.parameters.walk_mut(f); | ||
445 | } | ||
446 | Ty::Projection(p_ty) => { | ||
447 | p_ty.parameters.walk_mut(f); | ||
448 | } | ||
449 | Ty::UnselectedProjection(p_ty) => { | ||
450 | p_ty.parameters.walk_mut(f); | ||
451 | } | ||
452 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | ||
453 | let mut v: Vec<_> = predicates.iter().cloned().collect(); | ||
454 | for p in &mut v { | ||
455 | p.walk_mut(f); | ||
456 | } | ||
457 | *predicates = v.into(); | ||
458 | } | ||
459 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | ||
460 | } | ||
461 | f(self); | ||
462 | } | ||
463 | |||
464 | fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty { | ||
465 | self.walk_mut(&mut |ty_mut| { | ||
466 | let ty = mem::replace(ty_mut, Ty::Unknown); | ||
467 | *ty_mut = f(ty); | ||
468 | }); | ||
469 | self | ||
470 | } | ||
471 | |||
472 | pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { | 452 | pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { |
473 | match self { | 453 | match self { |
474 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { | 454 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { |
@@ -544,10 +524,53 @@ impl Ty { | |||
544 | } | 524 | } |
545 | } | 525 | } |
546 | 526 | ||
527 | /// Returns the type parameters of this type if it has some (i.e. is an ADT | ||
528 | /// or function); so if `self` is `Option<u32>`, this returns the `u32`. | ||
529 | pub fn substs(&self) -> Option<Substs> { | ||
530 | match self { | ||
531 | Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()), | ||
532 | _ => None, | ||
533 | } | ||
534 | } | ||
535 | |||
536 | /// If this is an `impl Trait` or `dyn Trait`, returns that trait. | ||
537 | pub fn inherent_trait(&self) -> Option<Trait> { | ||
538 | match self { | ||
539 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | ||
540 | predicates.iter().find_map(|pred| match pred { | ||
541 | GenericPredicate::Implemented(tr) => Some(tr.trait_), | ||
542 | _ => None, | ||
543 | }) | ||
544 | } | ||
545 | _ => None, | ||
546 | } | ||
547 | } | ||
548 | } | ||
549 | |||
550 | /// This allows walking structures that contain types to do something with those | ||
551 | /// types, similar to Chalk's `Fold` trait. | ||
552 | pub trait TypeWalk { | ||
553 | fn walk(&self, f: &mut impl FnMut(&Ty)); | ||
554 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)); | ||
555 | |||
556 | fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self | ||
557 | where | ||
558 | Self: Sized, | ||
559 | { | ||
560 | self.walk_mut(&mut |ty_mut| { | ||
561 | let ty = mem::replace(ty_mut, Ty::Unknown); | ||
562 | *ty_mut = f(ty); | ||
563 | }); | ||
564 | self | ||
565 | } | ||
566 | |||
547 | /// Replaces type parameters in this type using the given `Substs`. (So e.g. | 567 | /// Replaces type parameters in this type using the given `Substs`. (So e.g. |
548 | /// if `self` is `&[T]`, where type parameter T has index 0, and the | 568 | /// if `self` is `&[T]`, where type parameter T has index 0, and the |
549 | /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.) | 569 | /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.) |
550 | pub fn subst(self, substs: &Substs) -> Ty { | 570 | fn subst(self, substs: &Substs) -> Self |
571 | where | ||
572 | Self: Sized, | ||
573 | { | ||
551 | self.fold(&mut |ty| match ty { | 574 | self.fold(&mut |ty| match ty { |
552 | Ty::Param { idx, name } => { | 575 | Ty::Param { idx, name } => { |
553 | substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name }) | 576 | substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name }) |
@@ -557,24 +580,21 @@ impl Ty { | |||
557 | } | 580 | } |
558 | 581 | ||
559 | /// Substitutes `Ty::Bound` vars (as opposed to type parameters). | 582 | /// Substitutes `Ty::Bound` vars (as opposed to type parameters). |
560 | pub fn subst_bound_vars(self, substs: &Substs) -> Ty { | 583 | fn subst_bound_vars(self, substs: &Substs) -> Self |
584 | where | ||
585 | Self: Sized, | ||
586 | { | ||
561 | self.fold(&mut |ty| match ty { | 587 | self.fold(&mut |ty| match ty { |
562 | Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)), | 588 | Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)), |
563 | ty => ty, | 589 | ty => ty, |
564 | }) | 590 | }) |
565 | } | 591 | } |
566 | 592 | ||
567 | /// Returns the type parameters of this type if it has some (i.e. is an ADT | ||
568 | /// or function); so if `self` is `Option<u32>`, this returns the `u32`. | ||
569 | pub fn substs(&self) -> Option<Substs> { | ||
570 | match self { | ||
571 | Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()), | ||
572 | _ => None, | ||
573 | } | ||
574 | } | ||
575 | |||
576 | /// Shifts up `Ty::Bound` vars by `n`. | 593 | /// Shifts up `Ty::Bound` vars by `n`. |
577 | pub fn shift_bound_vars(self, n: i32) -> Ty { | 594 | fn shift_bound_vars(self, n: i32) -> Self |
595 | where | ||
596 | Self: Sized, | ||
597 | { | ||
578 | self.fold(&mut |ty| match ty { | 598 | self.fold(&mut |ty| match ty { |
579 | Ty::Bound(idx) => { | 599 | Ty::Bound(idx) => { |
580 | assert!(idx as i32 >= -n); | 600 | assert!(idx as i32 >= -n); |
@@ -583,18 +603,57 @@ impl Ty { | |||
583 | ty => ty, | 603 | ty => ty, |
584 | }) | 604 | }) |
585 | } | 605 | } |
606 | } | ||
586 | 607 | ||
587 | /// If this is an `impl Trait` or `dyn Trait`, returns that trait. | 608 | impl TypeWalk for Ty { |
588 | pub fn inherent_trait(&self) -> Option<Trait> { | 609 | fn walk(&self, f: &mut impl FnMut(&Ty)) { |
610 | match self { | ||
611 | Ty::Apply(a_ty) => { | ||
612 | for t in a_ty.parameters.iter() { | ||
613 | t.walk(f); | ||
614 | } | ||
615 | } | ||
616 | Ty::Projection(p_ty) => { | ||
617 | for t in p_ty.parameters.iter() { | ||
618 | t.walk(f); | ||
619 | } | ||
620 | } | ||
621 | Ty::UnselectedProjection(p_ty) => { | ||
622 | for t in p_ty.parameters.iter() { | ||
623 | t.walk(f); | ||
624 | } | ||
625 | } | ||
626 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | ||
627 | for p in predicates.iter() { | ||
628 | p.walk(f); | ||
629 | } | ||
630 | } | ||
631 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | ||
632 | } | ||
633 | f(self); | ||
634 | } | ||
635 | |||
636 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | ||
589 | match self { | 637 | match self { |
638 | Ty::Apply(a_ty) => { | ||
639 | a_ty.parameters.walk_mut(f); | ||
640 | } | ||
641 | Ty::Projection(p_ty) => { | ||
642 | p_ty.parameters.walk_mut(f); | ||
643 | } | ||
644 | Ty::UnselectedProjection(p_ty) => { | ||
645 | p_ty.parameters.walk_mut(f); | ||
646 | } | ||
590 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { | 647 | Ty::Dyn(predicates) | Ty::Opaque(predicates) => { |
591 | predicates.iter().find_map(|pred| match pred { | 648 | let mut v: Vec<_> = predicates.iter().cloned().collect(); |
592 | GenericPredicate::Implemented(tr) => Some(tr.trait_), | 649 | for p in &mut v { |
593 | _ => None, | 650 | p.walk_mut(f); |
594 | }) | 651 | } |
652 | *predicates = v.into(); | ||
595 | } | 653 | } |
596 | _ => None, | 654 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} |
597 | } | 655 | } |
656 | f(self); | ||
598 | } | 657 | } |
599 | } | 658 | } |
600 | 659 | ||
@@ -742,20 +801,66 @@ impl HirDisplay for Ty { | |||
742 | Ty::Opaque(_) => write!(f, "impl ")?, | 801 | Ty::Opaque(_) => write!(f, "impl ")?, |
743 | _ => unreachable!(), | 802 | _ => unreachable!(), |
744 | }; | 803 | }; |
745 | // looping by hand here just to format the bounds in a slightly nicer way | 804 | // Note: This code is written to produce nice results (i.e. |
805 | // corresponding to surface Rust) for types that can occur in | ||
806 | // actual Rust. It will have weird results if the predicates | ||
807 | // aren't as expected (i.e. self types = $0, projection | ||
808 | // predicates for a certain trait come after the Implemented | ||
809 | // predicate for that trait). | ||
746 | let mut first = true; | 810 | let mut first = true; |
811 | let mut angle_open = false; | ||
747 | for p in predicates.iter() { | 812 | for p in predicates.iter() { |
748 | if !first { | ||
749 | write!(f, " + ")?; | ||
750 | } | ||
751 | first = false; | ||
752 | match p { | 813 | match p { |
753 | // don't show the $0 self type | ||
754 | GenericPredicate::Implemented(trait_ref) => { | 814 | GenericPredicate::Implemented(trait_ref) => { |
755 | trait_ref.hir_fmt_ext(f, false)? | 815 | if angle_open { |
816 | write!(f, ">")?; | ||
817 | } | ||
818 | if !first { | ||
819 | write!(f, " + ")?; | ||
820 | } | ||
821 | // We assume that the self type is $0 (i.e. the | ||
822 | // existential) here, which is the only thing that's | ||
823 | // possible in actual Rust, and hence don't print it | ||
824 | write!( | ||
825 | f, | ||
826 | "{}", | ||
827 | trait_ref.trait_.name(f.db).unwrap_or_else(Name::missing) | ||
828 | )?; | ||
829 | if trait_ref.substs.len() > 1 { | ||
830 | write!(f, "<")?; | ||
831 | f.write_joined(&trait_ref.substs[1..], ", ")?; | ||
832 | // there might be assoc type bindings, so we leave the angle brackets open | ||
833 | angle_open = true; | ||
834 | } | ||
835 | } | ||
836 | GenericPredicate::Projection(projection_pred) => { | ||
837 | // in types in actual Rust, these will always come | ||
838 | // after the corresponding Implemented predicate | ||
839 | if angle_open { | ||
840 | write!(f, ", ")?; | ||
841 | } else { | ||
842 | write!(f, "<")?; | ||
843 | angle_open = true; | ||
844 | } | ||
845 | let name = projection_pred.projection_ty.associated_ty.name(f.db); | ||
846 | write!(f, "{} = ", name)?; | ||
847 | projection_pred.ty.hir_fmt(f)?; | ||
848 | } | ||
849 | GenericPredicate::Error => { | ||
850 | if angle_open { | ||
851 | // impl Trait<X, {error}> | ||
852 | write!(f, ", ")?; | ||
853 | } else if !first { | ||
854 | // impl Trait + {error} | ||
855 | write!(f, " + ")?; | ||
856 | } | ||
857 | p.hir_fmt(f)?; | ||
756 | } | 858 | } |
757 | GenericPredicate::Error => p.hir_fmt(f)?, | ||
758 | } | 859 | } |
860 | first = false; | ||
861 | } | ||
862 | if angle_open { | ||
863 | write!(f, ">")?; | ||
759 | } | 864 | } |
760 | } | 865 | } |
761 | Ty::Unknown => write!(f, "{{unknown}}")?, | 866 | Ty::Unknown => write!(f, "{{unknown}}")?, |
@@ -766,13 +871,12 @@ impl HirDisplay for Ty { | |||
766 | } | 871 | } |
767 | 872 | ||
768 | impl TraitRef { | 873 | impl TraitRef { |
769 | fn hir_fmt_ext( | 874 | fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result { |
770 | &self, | 875 | self.substs[0].hir_fmt(f)?; |
771 | f: &mut HirFormatter<impl HirDatabase>, | 876 | if use_as { |
772 | with_self_ty: bool, | 877 | write!(f, " as ")?; |
773 | ) -> fmt::Result { | 878 | } else { |
774 | if with_self_ty { | 879 | write!(f, ": ")?; |
775 | write!(f, "{}: ", self.substs[0].display(f.db),)?; | ||
776 | } | 880 | } |
777 | write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?; | 881 | write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?; |
778 | if self.substs.len() > 1 { | 882 | if self.substs.len() > 1 { |
@@ -786,7 +890,7 @@ impl TraitRef { | |||
786 | 890 | ||
787 | impl HirDisplay for TraitRef { | 891 | impl HirDisplay for TraitRef { |
788 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | 892 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { |
789 | self.hir_fmt_ext(f, true) | 893 | self.hir_fmt_ext(f, false) |
790 | } | 894 | } |
791 | } | 895 | } |
792 | 896 | ||
@@ -800,6 +904,16 @@ impl HirDisplay for GenericPredicate { | |||
800 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | 904 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { |
801 | match self { | 905 | match self { |
802 | GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, | 906 | GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, |
907 | GenericPredicate::Projection(projection_pred) => { | ||
908 | write!(f, "<")?; | ||
909 | projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; | ||
910 | write!( | ||
911 | f, | ||
912 | ">::{} = {}", | ||
913 | projection_pred.projection_ty.associated_ty.name(f.db), | ||
914 | projection_pred.ty.display(f.db) | ||
915 | )?; | ||
916 | } | ||
803 | GenericPredicate::Error => write!(f, "{{error}}")?, | 917 | GenericPredicate::Error => write!(f, "{{error}}")?, |
804 | } | 918 | } |
805 | Ok(()) | 919 | Ok(()) |
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index 2535d4ae7..08f52a53b 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs | |||
@@ -7,7 +7,7 @@ use std::iter::successors; | |||
7 | 7 | ||
8 | use log::{info, warn}; | 8 | use log::{info, warn}; |
9 | 9 | ||
10 | use super::{traits::Solution, Canonical, Ty}; | 10 | use super::{traits::Solution, Canonical, Ty, TypeWalk}; |
11 | use crate::{HasGenericParams, HirDatabase, Name, Resolver}; | 11 | use crate::{HasGenericParams, HirDatabase, Name, Resolver}; |
12 | 12 | ||
13 | const AUTODEREF_RECURSION_LIMIT: usize = 10; | 13 | const AUTODEREF_RECURSION_LIMIT: usize = 10; |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index b89a40b4b..ec3b7ffef 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -30,7 +30,7 @@ use super::{ | |||
30 | autoderef, lower, method_resolution, op, primitive, | 30 | autoderef, lower, method_resolution, op, primitive, |
31 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, | 31 | traits::{Guidance, Obligation, ProjectionPredicate, Solution}, |
32 | ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, | 32 | ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, |
33 | Ty, TypableDef, TypeCtor, | 33 | Ty, TypableDef, TypeCtor, TypeWalk, |
34 | }; | 34 | }; |
35 | use crate::{ | 35 | use crate::{ |
36 | adt::VariantDef, | 36 | adt::VariantDef, |
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs index e7e8825d1..9a0d2d8f9 100644 --- a/crates/ra_hir/src/ty/infer/unify.rs +++ b/crates/ra_hir/src/ty/infer/unify.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | use super::{InferenceContext, Obligation}; | 3 | use super::{InferenceContext, Obligation}; |
4 | use crate::db::HirDatabase; | 4 | use crate::db::HirDatabase; |
5 | use crate::ty::{ | 5 | use crate::ty::{ |
6 | Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, | 6 | Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, TypeWalk, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { | 9 | impl<'a, D: HirDatabase> InferenceContext<'a, D> { |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 47d161277..f6f0137cf 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -8,7 +8,10 @@ | |||
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 | TypeWalk, | ||
14 | }; | ||
12 | use crate::{ | 15 | use crate::{ |
13 | adt::VariantDef, | 16 | adt::VariantDef, |
14 | generics::HasGenericParams, | 17 | generics::HasGenericParams, |
@@ -62,7 +65,9 @@ impl Ty { | |||
62 | let self_ty = Ty::Bound(0); | 65 | let self_ty = Ty::Bound(0); |
63 | let predicates = bounds | 66 | let predicates = bounds |
64 | .iter() | 67 | .iter() |
65 | .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) | 68 | .flat_map(|b| { |
69 | GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()) | ||
70 | }) | ||
66 | .collect::<Vec<_>>(); | 71 | .collect::<Vec<_>>(); |
67 | Ty::Dyn(predicates.into()) | 72 | Ty::Dyn(predicates.into()) |
68 | } | 73 | } |
@@ -70,7 +75,9 @@ impl Ty { | |||
70 | let self_ty = Ty::Bound(0); | 75 | let self_ty = Ty::Bound(0); |
71 | let predicates = bounds | 76 | let predicates = bounds |
72 | .iter() | 77 | .iter() |
73 | .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) | 78 | .flat_map(|b| { |
79 | GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()) | ||
80 | }) | ||
74 | .collect::<Vec<_>>(); | 81 | .collect::<Vec<_>>(); |
75 | Ty::Opaque(predicates.into()) | 82 | Ty::Opaque(predicates.into()) |
76 | } | 83 | } |
@@ -326,15 +333,6 @@ impl TraitRef { | |||
326 | TraitRef { trait_, substs } | 333 | TraitRef { trait_, substs } |
327 | } | 334 | } |
328 | 335 | ||
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( | 336 | pub(crate) fn from_type_bound( |
339 | db: &impl HirDatabase, | 337 | db: &impl HirDatabase, |
340 | resolver: &Resolver, | 338 | resolver: &Resolver, |
@@ -349,26 +347,58 @@ impl TraitRef { | |||
349 | } | 347 | } |
350 | 348 | ||
351 | impl GenericPredicate { | 349 | impl GenericPredicate { |
352 | pub(crate) fn from_where_predicate( | 350 | pub(crate) fn from_where_predicate<'a>( |
353 | db: &impl HirDatabase, | 351 | db: &'a impl HirDatabase, |
354 | resolver: &Resolver, | 352 | resolver: &'a Resolver, |
355 | where_predicate: &WherePredicate, | 353 | where_predicate: &'a WherePredicate, |
356 | ) -> GenericPredicate { | 354 | ) -> impl Iterator<Item = GenericPredicate> + 'a { |
357 | TraitRef::from_where_predicate(db, &resolver, where_predicate) | 355 | let self_ty = Ty::from_hir(db, resolver, &where_predicate.type_ref); |
358 | .map_or(GenericPredicate::Error, GenericPredicate::Implemented) | 356 | GenericPredicate::from_type_bound(db, resolver, &where_predicate.bound, self_ty) |
359 | } | 357 | } |
360 | 358 | ||
361 | pub(crate) fn from_type_bound( | 359 | pub(crate) fn from_type_bound<'a>( |
362 | db: &impl HirDatabase, | 360 | db: &'a impl HirDatabase, |
363 | resolver: &Resolver, | 361 | resolver: &'a Resolver, |
364 | bound: &TypeBound, | 362 | bound: &'a TypeBound, |
365 | self_ty: Ty, | 363 | self_ty: Ty, |
366 | ) -> GenericPredicate { | 364 | ) -> impl Iterator<Item = GenericPredicate> + 'a { |
367 | TraitRef::from_type_bound(db, &resolver, bound, self_ty) | 365 | let trait_ref = TraitRef::from_type_bound(db, &resolver, bound, self_ty); |
368 | .map_or(GenericPredicate::Error, GenericPredicate::Implemented) | 366 | iter::once(trait_ref.clone().map_or(GenericPredicate::Error, GenericPredicate::Implemented)) |
367 | .chain( | ||
368 | trait_ref.into_iter().flat_map(move |tr| { | ||
369 | assoc_type_bindings_from_type_bound(db, resolver, bound, tr) | ||
370 | }), | ||
371 | ) | ||
369 | } | 372 | } |
370 | } | 373 | } |
371 | 374 | ||
375 | fn assoc_type_bindings_from_type_bound<'a>( | ||
376 | db: &'a impl HirDatabase, | ||
377 | resolver: &'a Resolver, | ||
378 | bound: &'a TypeBound, | ||
379 | trait_ref: TraitRef, | ||
380 | ) -> impl Iterator<Item = GenericPredicate> + 'a { | ||
381 | let last_segment = match bound { | ||
382 | TypeBound::Path(path) => path.segments.last(), | ||
383 | TypeBound::Error => None, | ||
384 | }; | ||
385 | last_segment | ||
386 | .into_iter() | ||
387 | .flat_map(|segment| segment.args_and_bindings.iter()) | ||
388 | .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) | ||
389 | .map(move |(name, type_ref)| { | ||
390 | let associated_ty = match trait_ref.trait_.associated_type_by_name(db, name.clone()) { | ||
391 | None => return GenericPredicate::Error, | ||
392 | Some(t) => t, | ||
393 | }; | ||
394 | let projection_ty = | ||
395 | ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; | ||
396 | let ty = Ty::from_hir(db, resolver, type_ref); | ||
397 | let projection_predicate = ProjectionPredicate { projection_ty, ty }; | ||
398 | GenericPredicate::Projection(projection_predicate) | ||
399 | }) | ||
400 | } | ||
401 | |||
372 | /// Build the declared type of an item. This depends on the namespace; e.g. for | 402 | /// 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 | 403 | /// `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 | 404 | /// the constructor function `(usize) -> Foo` which lives in the values |
@@ -425,7 +455,7 @@ pub(crate) fn trait_env( | |||
425 | ) -> Arc<super::TraitEnvironment> { | 455 | ) -> Arc<super::TraitEnvironment> { |
426 | let predicates = resolver | 456 | let predicates = resolver |
427 | .where_predicates_in_scope() | 457 | .where_predicates_in_scope() |
428 | .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) | 458 | .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) |
429 | .collect::<Vec<_>>(); | 459 | .collect::<Vec<_>>(); |
430 | 460 | ||
431 | Arc::new(super::TraitEnvironment { predicates }) | 461 | Arc::new(super::TraitEnvironment { predicates }) |
@@ -439,7 +469,7 @@ pub(crate) fn generic_predicates_query( | |||
439 | let resolver = def.resolver(db); | 469 | let resolver = def.resolver(db); |
440 | let predicates = resolver | 470 | let predicates = resolver |
441 | .where_predicates_in_scope() | 471 | .where_predicates_in_scope() |
442 | .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) | 472 | .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) |
443 | .collect::<Vec<_>>(); | 473 | .collect::<Vec<_>>(); |
444 | predicates.into() | 474 | predicates.into() |
445 | } | 475 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index cde9801f6..d92d4659b 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3552,6 +3552,97 @@ fn test() { | |||
3552 | ); | 3552 | ); |
3553 | } | 3553 | } |
3554 | 3554 | ||
3555 | #[test] | ||
3556 | fn assoc_type_bindings() { | ||
3557 | assert_snapshot!( | ||
3558 | infer(r#" | ||
3559 | trait Trait { | ||
3560 | type Type; | ||
3561 | } | ||
3562 | |||
3563 | fn get<T: Trait>(t: T) -> <T as Trait>::Type {} | ||
3564 | fn get2<U, T: Trait<Type = U>>(t: T) -> U {} | ||
3565 | fn set<T: Trait<Type = u64>>(t: T) -> T {t} | ||
3566 | |||
3567 | struct S<T>; | ||
3568 | impl<T> Trait for S<T> { type Type = T; } | ||
3569 | |||
3570 | fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { | ||
3571 | get(x); | ||
3572 | get2(x); | ||
3573 | get(y); | ||
3574 | get2(y); | ||
3575 | get(set(S)); | ||
3576 | get2(set(S)); | ||
3577 | get2(S::<str>); | ||
3578 | } | ||
3579 | "#), | ||
3580 | @r###" | ||
3581 | [50; 51) 't': T | ||
3582 | [78; 80) '{}': () | ||
3583 | [112; 113) 't': T | ||
3584 | [123; 125) '{}': () | ||
3585 | [155; 156) 't': T | ||
3586 | [166; 169) '{t}': T | ||
3587 | [167; 168) 't': T | ||
3588 | [257; 258) 'x': T | ||
3589 | [263; 264) 'y': impl Trait<Type = i64> | ||
3590 | [290; 398) '{ ...r>); }': () | ||
3591 | [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type | ||
3592 | [296; 302) 'get(x)': {unknown} | ||
3593 | [300; 301) 'x': T | ||
3594 | [308; 312) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U | ||
3595 | [308; 315) 'get2(x)': {unknown} | ||
3596 | [313; 314) 'x': T | ||
3597 | [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type | ||
3598 | [321; 327) 'get(y)': {unknown} | ||
3599 | [325; 326) 'y': impl Trait<Type = i64> | ||
3600 | [333; 337) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U | ||
3601 | [333; 340) 'get2(y)': {unknown} | ||
3602 | [338; 339) 'y': impl Trait<Type = i64> | ||
3603 | [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type | ||
3604 | [346; 357) 'get(set(S))': u64 | ||
3605 | [350; 353) 'set': fn set<S<u64>>(T) -> T | ||
3606 | [350; 356) 'set(S)': S<u64> | ||
3607 | [354; 355) 'S': S<u64> | ||
3608 | [363; 367) 'get2': fn get2<u64, S<u64>>(T) -> U | ||
3609 | [363; 375) 'get2(set(S))': u64 | ||
3610 | [368; 371) 'set': fn set<S<u64>>(T) -> T | ||
3611 | [368; 374) 'set(S)': S<u64> | ||
3612 | [372; 373) 'S': S<u64> | ||
3613 | [381; 385) 'get2': fn get2<str, S<str>>(T) -> U | ||
3614 | [381; 395) 'get2(S::<str>)': str | ||
3615 | [386; 394) 'S::<str>': S<str> | ||
3616 | "### | ||
3617 | ); | ||
3618 | } | ||
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 | } | ||
3555 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 3646 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
3556 | let file = db.parse(pos.file_id).ok().unwrap(); | 3647 | let file = db.parse(pos.file_id).ok().unwrap(); |
3557 | 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..6e0271a96 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -8,7 +8,7 @@ use ra_db::salsa; | |||
8 | use ra_prof::profile; | 8 | use ra_prof::profile; |
9 | use rustc_hash::FxHashSet; | 9 | use rustc_hash::FxHashSet; |
10 | 10 | ||
11 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty}; | 11 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; |
12 | use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; | 12 | use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; |
13 | 13 | ||
14 | use self::chalk::{from_chalk, ToChalk}; | 14 | use self::chalk::{from_chalk, ToChalk}; |
@@ -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,18 @@ pub struct ProjectionPredicate { | |||
135 | pub ty: Ty, | 138 | pub ty: Ty, |
136 | } | 139 | } |
137 | 140 | ||
141 | impl TypeWalk for ProjectionPredicate { | ||
142 | fn walk(&self, f: &mut impl FnMut(&Ty)) { | ||
143 | self.projection_ty.walk(f); | ||
144 | self.ty.walk(f); | ||
145 | } | ||
146 | |||
147 | fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { | ||
148 | self.projection_ty.walk_mut(f); | ||
149 | self.ty.walk_mut(f); | ||
150 | } | ||
151 | } | ||
152 | |||
138 | /// Solve a trait goal using Chalk. | 153 | /// Solve a trait goal using Chalk. |
139 | pub(crate) fn trait_solve_query( | 154 | pub(crate) fn trait_solve_query( |
140 | db: &impl HirDatabase, | 155 | 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..c201c5e50 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -19,6 +19,7 @@ use crate::{ | |||
19 | ty::display::HirDisplay, | 19 | ty::display::HirDisplay, |
20 | ty::{ | 20 | ty::{ |
21 | ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | 21 | ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, |
22 | TypeWalk, | ||
22 | }, | 23 | }, |
23 | Crate, HasGenericParams, ImplBlock, ImplItem, Trait, TypeAlias, | 24 | Crate, HasGenericParams, ImplBlock, ImplItem, Trait, TypeAlias, |
24 | }; | 25 | }; |
@@ -211,6 +212,13 @@ impl ToChalk for GenericPredicate { | |||
211 | GenericPredicate::Implemented(trait_ref) => { | 212 | GenericPredicate::Implemented(trait_ref) => { |
212 | make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) | 213 | make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) |
213 | } | 214 | } |
215 | GenericPredicate::Projection(projection_pred) => make_binders( | ||
216 | chalk_ir::WhereClause::ProjectionEq(chalk_ir::ProjectionEq { | ||
217 | projection: projection_pred.projection_ty.to_chalk(db), | ||
218 | ty: projection_pred.ty.to_chalk(db), | ||
219 | }), | ||
220 | 0, | ||
221 | ), | ||
214 | GenericPredicate::Error => { | 222 | GenericPredicate::Error => { |
215 | let impossible_trait_ref = chalk_ir::TraitRef { | 223 | let impossible_trait_ref = chalk_ir::TraitRef { |
216 | trait_id: UNKNOWN_TRAIT, | 224 | trait_id: UNKNOWN_TRAIT, |
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index f19eec9b7..db7e8348e 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | //! This modules takes care of rendering various defenitions as completion items. | 1 | //! This modules takes care of rendering various defenitions as completion items. |
2 | use hir::{Docs, HasSource, HirDisplay, PerNs, Resolution, Ty}; | 2 | use hir::{Docs, HasSource, HirDisplay, PerNs, Resolution, Ty, TypeWalk}; |
3 | use join_to_string::join; | 3 | use join_to_string::join; |
4 | use ra_syntax::ast::NameOwner; | 4 | use ra_syntax::ast::NameOwner; |
5 | use test_utils::tested_by; | 5 | use test_utils::tested_by; |