diff options
Diffstat (limited to 'crates/hir_ty')
-rw-r--r-- | crates/hir_ty/src/display.rs | 100 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/display_source_code.rs | 15 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/traits.rs | 8 |
3 files changed, 94 insertions, 29 deletions
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index e9e949c47..d2f1b4014 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -1,14 +1,15 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::fmt; | 3 | use std::{borrow::Cow, fmt}; |
4 | 4 | ||
5 | use crate::{ | 5 | use crate::{ |
6 | db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate, | 6 | db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate, |
7 | Lifetime, Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, | 7 | Lifetime, Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, |
8 | }; | 8 | }; |
9 | use arrayvec::ArrayVec; | ||
9 | use hir_def::{ | 10 | use hir_def::{ |
10 | find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId, | 11 | db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, |
11 | Lookup, ModuleId, | 12 | AssocContainerId, HasModule, Lookup, ModuleId, TraitId, |
12 | }; | 13 | }; |
13 | use hir_expand::name::Name; | 14 | use hir_expand::name::Name; |
14 | 15 | ||
@@ -257,25 +258,45 @@ impl HirDisplay for ApplicationTy { | |||
257 | t.hir_fmt(f)?; | 258 | t.hir_fmt(f)?; |
258 | write!(f, "; _]")?; | 259 | write!(f, "; _]")?; |
259 | } | 260 | } |
260 | TypeCtor::RawPtr(m) => { | 261 | TypeCtor::RawPtr(m) | TypeCtor::Ref(m) => { |
261 | let t = self.parameters.as_single(); | 262 | let t = self.parameters.as_single(); |
263 | let ty_display = | ||
264 | t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target); | ||
262 | 265 | ||
263 | write!(f, "*{}", m.as_keyword_for_ptr())?; | 266 | if matches!(self.ctor, TypeCtor::RawPtr(_)) { |
264 | if matches!(t, Ty::Dyn(predicates) if predicates.len() > 1) { | 267 | write!(f, "*{}", m.as_keyword_for_ptr())?; |
265 | write!(f, "(")?; | ||
266 | t.hir_fmt(f)?; | ||
267 | write!(f, ")")?; | ||
268 | } else { | 268 | } else { |
269 | t.hir_fmt(f)?; | 269 | write!(f, "&{}", m.as_keyword_for_ref())?; |
270 | } | ||
271 | |||
272 | let datas; | ||
273 | let predicates = match t { | ||
274 | Ty::Dyn(predicates) if predicates.len() > 1 => { | ||
275 | Cow::Borrowed(predicates.as_ref()) | ||
276 | } | ||
277 | &Ty::Opaque(OpaqueTy { | ||
278 | opaque_ty_id: OpaqueTyId::ReturnTypeImplTrait(func, idx), | ||
279 | ref parameters, | ||
280 | }) => { | ||
281 | datas = | ||
282 | f.db.return_type_impl_traits(func).expect("impl trait id without data"); | ||
283 | let data = (*datas) | ||
284 | .as_ref() | ||
285 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | ||
286 | let bounds = data.subst(parameters); | ||
287 | Cow::Owned(bounds.value) | ||
288 | } | ||
289 | _ => Cow::Borrowed(&[][..]), | ||
290 | }; | ||
291 | |||
292 | if let [GenericPredicate::Implemented(trait_ref), _] = predicates.as_ref() { | ||
293 | let trait_ = trait_ref.trait_; | ||
294 | if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) { | ||
295 | return write!(f, "{}", ty_display); | ||
296 | } | ||
270 | } | 297 | } |
271 | } | ||
272 | TypeCtor::Ref(m) => { | ||
273 | let t = self.parameters.as_single(); | ||
274 | let ty_display = | ||
275 | t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target); | ||
276 | 298 | ||
277 | write!(f, "&{}", m.as_keyword_for_ref())?; | 299 | if predicates.len() > 1 { |
278 | if matches!(t, Ty::Dyn(predicates) if predicates.len() > 1) { | ||
279 | write!(f, "(")?; | 300 | write!(f, "(")?; |
280 | write!(f, "{}", ty_display)?; | 301 | write!(f, "{}", ty_display)?; |
281 | write!(f, ")")?; | 302 | write!(f, ")")?; |
@@ -595,6 +616,17 @@ impl HirDisplay for FnSig { | |||
595 | } | 616 | } |
596 | } | 617 | } |
597 | 618 | ||
619 | fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator<Item = TraitId> { | ||
620 | let krate = trait_.lookup(db).container.module(db).krate; | ||
621 | let fn_traits = [ | ||
622 | db.lang_item(krate, "fn".into()), | ||
623 | db.lang_item(krate, "fn_mut".into()), | ||
624 | db.lang_item(krate, "fn_once".into()), | ||
625 | ]; | ||
626 | // FIXME: Replace ArrayVec when into_iter is a thing on arrays | ||
627 | ArrayVec::from(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait()) | ||
628 | } | ||
629 | |||
598 | pub fn write_bounds_like_dyn_trait( | 630 | pub fn write_bounds_like_dyn_trait( |
599 | predicates: &[GenericPredicate], | 631 | predicates: &[GenericPredicate], |
600 | f: &mut HirFormatter, | 632 | f: &mut HirFormatter, |
@@ -607,10 +639,15 @@ pub fn write_bounds_like_dyn_trait( | |||
607 | // predicate for that trait). | 639 | // predicate for that trait). |
608 | let mut first = true; | 640 | let mut first = true; |
609 | let mut angle_open = false; | 641 | let mut angle_open = false; |
642 | let mut is_fn_trait = false; | ||
610 | for p in predicates.iter() { | 643 | for p in predicates.iter() { |
611 | match p { | 644 | match p { |
612 | GenericPredicate::Implemented(trait_ref) => { | 645 | GenericPredicate::Implemented(trait_ref) => { |
613 | if angle_open { | 646 | let trait_ = trait_ref.trait_; |
647 | if !is_fn_trait { | ||
648 | is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_); | ||
649 | } | ||
650 | if !is_fn_trait && angle_open { | ||
614 | write!(f, ">")?; | 651 | write!(f, ">")?; |
615 | angle_open = false; | 652 | angle_open = false; |
616 | } | 653 | } |
@@ -620,14 +657,27 @@ pub fn write_bounds_like_dyn_trait( | |||
620 | // We assume that the self type is $0 (i.e. the | 657 | // We assume that the self type is $0 (i.e. the |
621 | // existential) here, which is the only thing that's | 658 | // existential) here, which is the only thing that's |
622 | // possible in actual Rust, and hence don't print it | 659 | // possible in actual Rust, and hence don't print it |
623 | write!(f, "{}", f.db.trait_data(trait_ref.trait_).name)?; | 660 | write!(f, "{}", f.db.trait_data(trait_).name)?; |
624 | if trait_ref.substs.len() > 1 { | 661 | if let [_, params @ ..] = &*trait_ref.substs.0 { |
625 | write!(f, "<")?; | 662 | if is_fn_trait { |
626 | f.write_joined(&trait_ref.substs[1..], ", ")?; | 663 | if let Some(args) = params.first().and_then(|it| it.as_tuple()) { |
627 | // there might be assoc type bindings, so we leave the angle brackets open | 664 | write!(f, "(")?; |
628 | angle_open = true; | 665 | f.write_joined(&*args.0, ", ")?; |
666 | write!(f, ")")?; | ||
667 | } | ||
668 | } else if !params.is_empty() { | ||
669 | write!(f, "<")?; | ||
670 | f.write_joined(params, ", ")?; | ||
671 | // there might be assoc type bindings, so we leave the angle brackets open | ||
672 | angle_open = true; | ||
673 | } | ||
629 | } | 674 | } |
630 | } | 675 | } |
676 | GenericPredicate::Projection(projection_pred) if is_fn_trait => { | ||
677 | is_fn_trait = false; | ||
678 | write!(f, " -> ")?; | ||
679 | projection_pred.ty.hir_fmt(f)?; | ||
680 | } | ||
631 | GenericPredicate::Projection(projection_pred) => { | 681 | GenericPredicate::Projection(projection_pred) => { |
632 | // in types in actual Rust, these will always come | 682 | // in types in actual Rust, these will always come |
633 | // after the corresponding Implemented predicate | 683 | // after the corresponding Implemented predicate |
diff --git a/crates/hir_ty/src/tests/display_source_code.rs b/crates/hir_ty/src/tests/display_source_code.rs index b502135d8..3d29021aa 100644 --- a/crates/hir_ty/src/tests/display_source_code.rs +++ b/crates/hir_ty/src/tests/display_source_code.rs | |||
@@ -39,3 +39,18 @@ fn main() { | |||
39 | "#, | 39 | "#, |
40 | ); | 40 | ); |
41 | } | 41 | } |
42 | |||
43 | #[test] | ||
44 | fn render_raw_ptr_impl_ty() { | ||
45 | check_types_source_code( | ||
46 | r#" | ||
47 | trait Sized {} | ||
48 | trait Unpin {} | ||
49 | fn foo() -> *const (impl Unpin + Sized) { loop {} } | ||
50 | fn main() { | ||
51 | let foo = foo(); | ||
52 | foo; | ||
53 | } //^ *const (impl Unpin + Sized) | ||
54 | "#, | ||
55 | ); | ||
56 | } | ||
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs index 41d097519..e5a3f95a6 100644 --- a/crates/hir_ty/src/tests/traits.rs +++ b/crates/hir_ty/src/tests/traits.rs | |||
@@ -3038,16 +3038,16 @@ fn infer_box_fn_arg() { | |||
3038 | 406..417 '&self.inner': &*mut T | 3038 | 406..417 '&self.inner': &*mut T |
3039 | 407..411 'self': &Box<T> | 3039 | 407..411 'self': &Box<T> |
3040 | 407..417 'self.inner': *mut T | 3040 | 407..417 'self.inner': *mut T |
3041 | 478..575 '{ ...(&s) }': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)> | 3041 | 478..575 '{ ...(&s) }': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)> |
3042 | 488..489 's': Option<i32> | 3042 | 488..489 's': Option<i32> |
3043 | 492..504 'Option::None': Option<i32> | 3043 | 492..504 'Option::None': Option<i32> |
3044 | 514..515 'f': Box<dyn FnOnce<(&Option<i32>,)>> | 3044 | 514..515 'f': Box<dyn FnOnce(&Option<i32>)> |
3045 | 549..562 'box (|ps| {})': Box<|{unknown}| -> ()> | 3045 | 549..562 'box (|ps| {})': Box<|{unknown}| -> ()> |
3046 | 554..561 '|ps| {}': |{unknown}| -> () | 3046 | 554..561 '|ps| {}': |{unknown}| -> () |
3047 | 555..557 'ps': {unknown} | 3047 | 555..557 'ps': {unknown} |
3048 | 559..561 '{}': () | 3048 | 559..561 '{}': () |
3049 | 568..569 'f': Box<dyn FnOnce<(&Option<i32>,)>> | 3049 | 568..569 'f': Box<dyn FnOnce(&Option<i32>)> |
3050 | 568..573 'f(&s)': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)> | 3050 | 568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)> |
3051 | 570..572 '&s': &Option<i32> | 3051 | 570..572 '&s': &Option<i32> |
3052 | 571..572 's': Option<i32> | 3052 | 571..572 's': Option<i32> |
3053 | "#]], | 3053 | "#]], |