aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2021-01-12 19:19:13 +0000
committerLukas Wirth <[email protected]>2021-01-13 12:29:47 +0000
commit3d6480bc3103f7238b1b0e020518e8aa72af3156 (patch)
tree080939aab1f5304b0ba22615547baa16141e83df /crates
parente9e3ab549d5a73f85e19eed5b915d78870f8892c (diff)
Render Fn* trait objects and impl types as rust does
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_ty/src/display.rs100
-rw-r--r--crates/hir_ty/src/tests/display_source_code.rs15
-rw-r--r--crates/hir_ty/src/tests/traits.rs8
-rw-r--r--crates/ide/src/inlay_hints.rs37
-rw-r--r--crates/ide_db/src/helpers/famous_defs_fixture.rs1
5 files changed, 132 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
3use std::fmt; 3use std::{borrow::Cow, fmt};
4 4
5use crate::{ 5use 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};
9use arrayvec::ArrayVec;
9use hir_def::{ 10use 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};
13use hir_expand::name::Name; 14use 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
619fn 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
598pub fn write_bounds_like_dyn_trait( 630pub 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]
44fn render_raw_ptr_impl_ty() {
45 check_types_source_code(
46 r#"
47trait Sized {}
48trait Unpin {}
49fn foo() -> *const (impl Unpin + Sized) { loop {} }
50fn 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 "#]],
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 3e9a65d9c..a2039fcc7 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1401,4 +1401,41 @@ fn main() {
1401"#, 1401"#,
1402 ) 1402 )
1403 } 1403 }
1404
1405 #[test]
1406 fn fn_hints() {
1407 check(
1408 r#"
1409trait Sized {}
1410
1411fn foo() -> impl Fn() { loop {} }
1412fn foo1() -> impl Fn(f64) { loop {} }
1413fn foo2() -> impl Fn(f64, f64) { loop {} }
1414fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
1415fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
1416fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
1417fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
1418fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
1419
1420fn main() {
1421 let foo = foo();
1422 // ^^^ impl Fn()
1423 let foo = foo1();
1424 // ^^^ impl Fn(f64)
1425 let foo = foo2();
1426 // ^^^ impl Fn(f64, f64)
1427 let foo = foo3();
1428 // ^^^ impl Fn(f64, f64) -> u32
1429 let foo = foo4();
1430 // ^^^ &dyn Fn(f64, f64) -> u32
1431 let foo = foo5();
1432 // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
1433 let foo = foo6();
1434 // ^^^ impl Fn(f64, f64) -> u32 + Sized
1435 let foo = foo7();
1436 // ^^^ *const (impl Fn(f64, f64) -> u32 + Sized)
1437}
1438"#,
1439 )
1440 }
1404} 1441}
diff --git a/crates/ide_db/src/helpers/famous_defs_fixture.rs b/crates/ide_db/src/helpers/famous_defs_fixture.rs
index f3d355861..5e88de64d 100644
--- a/crates/ide_db/src/helpers/famous_defs_fixture.rs
+++ b/crates/ide_db/src/helpers/famous_defs_fixture.rs
@@ -1,4 +1,5 @@
1//- /libcore.rs crate:core 1//- /libcore.rs crate:core
2//! Signatures of traits, types and functions from the core lib for use in tests.
2pub mod convert { 3pub mod convert {
3 pub trait From<T> { 4 pub trait From<T> {
4 fn from(t: T) -> Self; 5 fn from(t: T) -> Self;