diff options
author | Florian Diebold <[email protected]> | 2019-08-25 12:57:03 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-09-03 13:00:35 +0100 |
commit | c4fcfa2b0d516b9790fa8abdf96bb2308657d60a (patch) | |
tree | 94ae979da298244b9a057b6eacf58875101535b0 | |
parent | 741e350d4b7c3561f242207541ac9d7cab6ce45f (diff) |
Properly format `impl Trait<Type = Foo>` types
It's a bit complicated because we basically have to 'undo' the desugaring, and
the result is very dependent on the specifics of the desugaring and will
probably produce weird results otherwise.
-rw-r--r-- | crates/ra_hir/src/ty.rs | 112 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 8 |
2 files changed, 97 insertions, 23 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 035491bff..c0c609d78 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -121,6 +121,16 @@ pub struct ProjectionTy { | |||
121 | } | 121 | } |
122 | 122 | ||
123 | impl ProjectionTy { | 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 | |||
124 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { | 134 | pub fn walk(&self, f: &mut impl FnMut(&Ty)) { |
125 | self.parameters.walk(f); | 135 | self.parameters.walk(f); |
126 | } | 136 | } |
@@ -341,6 +351,21 @@ impl GenericPredicate { | |||
341 | } | 351 | } |
342 | } | 352 | } |
343 | 353 | ||
354 | pub fn is_implemented(&self) -> bool { | ||
355 | match self { | ||
356 | GenericPredicate::Implemented(_) => true, | ||
357 | _ => false, | ||
358 | } | ||
359 | } | ||
360 | |||
361 | pub fn trait_ref(&self, db: &impl HirDatabase) -> Option<TraitRef> { | ||
362 | match self { | ||
363 | GenericPredicate::Implemented(tr) => Some(tr.clone()), | ||
364 | GenericPredicate::Projection(proj) => Some(proj.projection_ty.trait_ref(db)), | ||
365 | GenericPredicate::Error => None, | ||
366 | } | ||
367 | } | ||
368 | |||
344 | pub fn subst(self, substs: &Substs) -> GenericPredicate { | 369 | pub fn subst(self, substs: &Substs) -> GenericPredicate { |
345 | match self { | 370 | match self { |
346 | GenericPredicate::Implemented(trait_ref) => { | 371 | GenericPredicate::Implemented(trait_ref) => { |
@@ -769,23 +794,66 @@ impl HirDisplay for Ty { | |||
769 | Ty::Opaque(_) => write!(f, "impl ")?, | 794 | Ty::Opaque(_) => write!(f, "impl ")?, |
770 | _ => unreachable!(), | 795 | _ => unreachable!(), |
771 | }; | 796 | }; |
772 | // looping by hand here just to format the bounds in a slightly nicer way | 797 | // Note: This code is written to produce nice results (i.e. |
798 | // corresponding to surface Rust) for types that can occur in | ||
799 | // actual Rust. It will have weird results if the predicates | ||
800 | // aren't as expected (i.e. self types = $0, projection | ||
801 | // predicates for a certain trait come after the Implemented | ||
802 | // predicate for that trait). | ||
773 | let mut first = true; | 803 | let mut first = true; |
804 | let mut angle_open = false; | ||
774 | for p in predicates.iter() { | 805 | for p in predicates.iter() { |
775 | if !first { | ||
776 | write!(f, " + ")?; | ||
777 | } | ||
778 | first = false; | ||
779 | match p { | 806 | match p { |
780 | // don't show the $0 self type | ||
781 | GenericPredicate::Implemented(trait_ref) => { | 807 | GenericPredicate::Implemented(trait_ref) => { |
782 | trait_ref.hir_fmt_ext(f, false)? | 808 | if angle_open { |
809 | write!(f, ">")?; | ||
810 | } | ||
811 | if !first { | ||
812 | write!(f, " + ")?; | ||
813 | } | ||
814 | // We assume that the self type is $0 (i.e. the | ||
815 | // existential) here, which is the only thing that's | ||
816 | // possible in actual Rust, and hence don't print it | ||
817 | write!( | ||
818 | f, | ||
819 | "{}", | ||
820 | trait_ref.trait_.name(f.db).unwrap_or_else(Name::missing) | ||
821 | )?; | ||
822 | if trait_ref.substs.len() > 1 { | ||
823 | write!(f, "<")?; | ||
824 | f.write_joined(&trait_ref.substs[1..], ", ")?; | ||
825 | // there might be assoc type bindings, so we leave the angle brackets open | ||
826 | angle_open = true; | ||
827 | } | ||
783 | } | 828 | } |
784 | GenericPredicate::Projection(_projection_pred) => { | 829 | GenericPredicate::Projection(projection_pred) => { |
785 | // TODO show something | 830 | // in types in actual Rust, these will always come |
831 | // after the corresponding Implemented predicate | ||
832 | if angle_open { | ||
833 | write!(f, ", ")?; | ||
834 | } else { | ||
835 | write!(f, "<")?; | ||
836 | angle_open = true; | ||
837 | } | ||
838 | let name = projection_pred.projection_ty.associated_ty.name(f.db); | ||
839 | write!(f, "{} = ", name)?; | ||
840 | projection_pred.ty.hir_fmt(f)?; | ||
841 | } | ||
842 | GenericPredicate::Error => { | ||
843 | if angle_open { | ||
844 | // impl Trait<X, {error}> | ||
845 | write!(f, ", ")?; | ||
846 | } else if !first { | ||
847 | // impl Trait + {error} | ||
848 | write!(f, " + ")?; | ||
849 | } | ||
850 | p.hir_fmt(f)?; | ||
786 | } | 851 | } |
787 | GenericPredicate::Error => p.hir_fmt(f)?, | ||
788 | } | 852 | } |
853 | first = false; | ||
854 | } | ||
855 | if angle_open { | ||
856 | write!(f, ">")?; | ||
789 | } | 857 | } |
790 | } | 858 | } |
791 | Ty::Unknown => write!(f, "{{unknown}}")?, | 859 | Ty::Unknown => write!(f, "{{unknown}}")?, |
@@ -796,13 +864,12 @@ impl HirDisplay for Ty { | |||
796 | } | 864 | } |
797 | 865 | ||
798 | impl TraitRef { | 866 | impl TraitRef { |
799 | fn hir_fmt_ext( | 867 | fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result { |
800 | &self, | 868 | self.substs[0].hir_fmt(f)?; |
801 | f: &mut HirFormatter<impl HirDatabase>, | 869 | if use_as { |
802 | with_self_ty: bool, | 870 | write!(f, " as ")?; |
803 | ) -> fmt::Result { | 871 | } else { |
804 | if with_self_ty { | 872 | write!(f, ": ")?; |
805 | write!(f, "{}: ", self.substs[0].display(f.db),)?; | ||
806 | } | 873 | } |
807 | write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?; | 874 | write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?; |
808 | if self.substs.len() > 1 { | 875 | if self.substs.len() > 1 { |
@@ -816,7 +883,7 @@ impl TraitRef { | |||
816 | 883 | ||
817 | impl HirDisplay for TraitRef { | 884 | impl HirDisplay for TraitRef { |
818 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | 885 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { |
819 | self.hir_fmt_ext(f, true) | 886 | self.hir_fmt_ext(f, false) |
820 | } | 887 | } |
821 | } | 888 | } |
822 | 889 | ||
@@ -831,7 +898,14 @@ impl HirDisplay for GenericPredicate { | |||
831 | match self { | 898 | match self { |
832 | GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, | 899 | GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, |
833 | GenericPredicate::Projection(projection_pred) => { | 900 | GenericPredicate::Projection(projection_pred) => { |
834 | // TODO print something | 901 | write!(f, "<")?; |
902 | projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; | ||
903 | write!( | ||
904 | f, | ||
905 | ">::{} = {}", | ||
906 | projection_pred.projection_ty.associated_ty.name(f.db), | ||
907 | projection_pred.ty.display(f.db) | ||
908 | )?; | ||
835 | } | 909 | } |
836 | GenericPredicate::Error => write!(f, "{{error}}")?, | 910 | GenericPredicate::Error => write!(f, "{{error}}")?, |
837 | } | 911 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 3e743ef58..d92d4659b 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -3586,7 +3586,7 @@ 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<Type = i64> |
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} |
@@ -3594,12 +3594,12 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { | |||
3594 | [308; 312) 'get2': fn get2<{unknown}, S<{unknown}>>(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<Type = i64>>(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<Type = i64> |
3600 | [333; 337) 'get2': fn get2<{unknown}, S<{unknown}>>(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<Type = i64> |
3603 | [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type | 3603 | [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type |
3604 | [346; 357) 'get(set(S))': u64 | 3604 | [346; 357) 'get(set(S))': u64 |
3605 | [350; 353) 'set': fn set<S<u64>>(T) -> T | 3605 | [350; 353) 'set': fn set<S<u64>>(T) -> T |