aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-01-14 09:07:15 +0000
committerGitHub <[email protected]>2021-01-14 09:07:15 +0000
commit39167b97d8a62adadecc9b67caac65ec556768cf (patch)
treef3a1c700b36ddc26bb9d189de3d03c84a93e9251
parent6835f2e37c8331ef54d4839a31df195d7dbbeee8 (diff)
parent3d6480bc3103f7238b1b0e020518e8aa72af3156 (diff)
Merge #7260
7260: Render Fn* trait objects and impl types as rust does r=matklad a=Veykril Also fixes raw ptr impl types being rendered ambiguously with multiple predicates. This moves out the `FamousDefs::Fixture` into its own file as well, cause I figured it is big enough to get its own file at this point + we also get highlighting this way when editing it. Fixes #3012 Co-authored-by: Lukas Wirth <[email protected]>
-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.rs89
-rw-r--r--crates/ide_db/src/helpers/famous_defs_fixture.rs120
-rw-r--r--xtask/tests/tidy.rs2
7 files changed, 253 insertions, 118 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.rs b/crates/ide_db/src/helpers.rs
index e3e5670f1..c6763ae36 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -38,94 +38,7 @@ pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Cr
38 38
39#[allow(non_snake_case)] 39#[allow(non_snake_case)]
40impl FamousDefs<'_, '_> { 40impl FamousDefs<'_, '_> {
41 pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core 41 pub const FIXTURE: &'static str = include_str!("helpers/famous_defs_fixture.rs");
42pub mod convert {
43 pub trait From<T> {
44 fn from(t: T) -> Self;
45 }
46}
47
48pub mod default {
49 pub trait Default {
50 fn default() -> Self;
51 }
52}
53
54pub mod iter {
55 pub use self::traits::{collect::IntoIterator, iterator::Iterator};
56 mod traits {
57 pub(crate) mod iterator {
58 use crate::option::Option;
59 pub trait Iterator {
60 type Item;
61 fn next(&mut self) -> Option<Self::Item>;
62 fn by_ref(&mut self) -> &mut Self {
63 self
64 }
65 fn take(self, n: usize) -> crate::iter::Take<Self> {
66 crate::iter::Take { inner: self }
67 }
68 }
69
70 impl<I: Iterator> Iterator for &mut I {
71 type Item = I::Item;
72 fn next(&mut self) -> Option<I::Item> {
73 (**self).next()
74 }
75 }
76 }
77 pub(crate) mod collect {
78 pub trait IntoIterator {
79 type Item;
80 }
81 }
82 }
83
84 pub use self::sources::*;
85 pub(crate) mod sources {
86 use super::Iterator;
87 use crate::option::Option::{self, *};
88 pub struct Repeat<A> {
89 element: A,
90 }
91
92 pub fn repeat<T>(elt: T) -> Repeat<T> {
93 Repeat { element: elt }
94 }
95
96 impl<A> Iterator for Repeat<A> {
97 type Item = A;
98
99 fn next(&mut self) -> Option<A> {
100 None
101 }
102 }
103 }
104
105 pub use self::adapters::*;
106 pub(crate) mod adapters {
107 use super::Iterator;
108 use crate::option::Option::{self, *};
109 pub struct Take<I> { pub(crate) inner: I }
110 impl<I> Iterator for Take<I> where I: Iterator {
111 type Item = <I as Iterator>::Item;
112 fn next(&mut self) -> Option<<I as Iterator>::Item> {
113 None
114 }
115 }
116 }
117}
118
119pub mod option {
120 pub enum Option<T> { None, Some(T)}
121}
122
123pub mod prelude {
124 pub use crate::{convert::From, iter::{IntoIterator, Iterator}, option::Option::{self, *}, default::Default};
125}
126#[prelude_import]
127pub use prelude::*;
128"#;
129 42
130 pub fn core(&self) -> Option<Crate> { 43 pub fn core(&self) -> Option<Crate> {
131 self.find_crate("core") 44 self.find_crate("core")
diff --git a/crates/ide_db/src/helpers/famous_defs_fixture.rs b/crates/ide_db/src/helpers/famous_defs_fixture.rs
new file mode 100644
index 000000000..5e88de64d
--- /dev/null
+++ b/crates/ide_db/src/helpers/famous_defs_fixture.rs
@@ -0,0 +1,120 @@
1//- /libcore.rs crate:core
2//! Signatures of traits, types and functions from the core lib for use in tests.
3pub mod convert {
4 pub trait From<T> {
5 fn from(t: T) -> Self;
6 }
7}
8
9pub mod default {
10 pub trait Default {
11 fn default() -> Self;
12 }
13}
14
15pub mod iter {
16 pub use self::traits::{collect::IntoIterator, iterator::Iterator};
17 mod traits {
18 pub(crate) mod iterator {
19 use crate::option::Option;
20 pub trait Iterator {
21 type Item;
22 fn next(&mut self) -> Option<Self::Item>;
23 fn by_ref(&mut self) -> &mut Self {
24 self
25 }
26 fn take(self, n: usize) -> crate::iter::Take<Self> {
27 crate::iter::Take { inner: self }
28 }
29 }
30
31 impl<I: Iterator> Iterator for &mut I {
32 type Item = I::Item;
33 fn next(&mut self) -> Option<I::Item> {
34 (**self).next()
35 }
36 }
37 }
38 pub(crate) mod collect {
39 pub trait IntoIterator {
40 type Item;
41 }
42 }
43 }
44
45 pub use self::sources::*;
46 pub(crate) mod sources {
47 use super::Iterator;
48 use crate::option::Option::{self, *};
49 pub struct Repeat<A> {
50 element: A,
51 }
52
53 pub fn repeat<T>(elt: T) -> Repeat<T> {
54 Repeat { element: elt }
55 }
56
57 impl<A> Iterator for Repeat<A> {
58 type Item = A;
59
60 fn next(&mut self) -> Option<A> {
61 None
62 }
63 }
64 }
65
66 pub use self::adapters::*;
67 pub(crate) mod adapters {
68 use super::Iterator;
69 use crate::option::Option::{self, *};
70 pub struct Take<I> {
71 pub(crate) inner: I,
72 }
73 impl<I> Iterator for Take<I>
74 where
75 I: Iterator,
76 {
77 type Item = <I as Iterator>::Item;
78 fn next(&mut self) -> Option<<I as Iterator>::Item> {
79 None
80 }
81 }
82 }
83}
84
85pub mod ops {
86 #[lang = "fn"]
87 pub trait Fn<Args>: FnMut<Args> {
88 extern "rust-call" fn call(&self, args: Args) -> Self::Output;
89 }
90
91 #[lang = "fn_mut"]
92 pub trait FnMut<Args>: FnOnce<Args> {
93 extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
94 }
95 #[lang = "fn_once"]
96 pub trait FnOnce<Args> {
97 #[lang = "fn_once_output"]
98 type Output;
99 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
100 }
101}
102
103pub mod option {
104 pub enum Option<T> {
105 None,
106 Some(T),
107 }
108}
109
110pub mod prelude {
111 pub use crate::{
112 convert::From,
113 default::Default,
114 iter::{IntoIterator, Iterator},
115 ops::{Fn, FnMut, FnOnce},
116 option::Option::{self, *},
117 };
118}
119#[prelude_import]
120pub use prelude::*;
diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs
index a957e36af..6abad189a 100644
--- a/xtask/tests/tidy.rs
+++ b/xtask/tests/tidy.rs
@@ -324,7 +324,7 @@ impl TidyDocs {
324 } 324 }
325 325
326 fn is_exclude_file(d: &Path) -> bool { 326 fn is_exclude_file(d: &Path) -> bool {
327 let file_names = ["tests.rs"]; 327 let file_names = ["tests.rs", "famous_defs_fixture.rs"];
328 328
329 d.file_name() 329 d.file_name()
330 .unwrap_or_default() 330 .unwrap_or_default()