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 /crates/ra_hir/src | |
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.
Diffstat (limited to 'crates/ra_hir/src')
-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 |