diff options
-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 | ||||
-rw-r--r-- | crates/ide/src/inlay_hints.rs | 37 | ||||
-rw-r--r-- | crates/ide_db/src/helpers/famous_defs_fixture.rs | 1 | ||||
-rw-r--r-- | xtask/tests/tidy.rs | 2 |
6 files changed, 133 insertions, 30 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 | "#]], |
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#" | ||
1409 | trait Sized {} | ||
1410 | |||
1411 | fn foo() -> impl Fn() { loop {} } | ||
1412 | fn foo1() -> impl Fn(f64) { loop {} } | ||
1413 | fn foo2() -> impl Fn(f64, f64) { loop {} } | ||
1414 | fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } | ||
1415 | fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } | ||
1416 | fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } | ||
1417 | fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } | ||
1418 | fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } | ||
1419 | |||
1420 | fn 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. | ||
2 | pub mod convert { | 3 | pub mod convert { |
3 | pub trait From<T> { | 4 | pub trait From<T> { |
4 | fn from(t: T) -> Self; | 5 | fn from(t: T) -> Self; |
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() |