From e9e3ab549d5a73f85e19eed5b915d78870f8892c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 12 Jan 2021 17:26:08 +0100 Subject: Move FamousDefs fixture out into its own file --- crates/ide_db/src/helpers.rs | 89 +---------------- crates/ide_db/src/helpers/famous_defs_fixture.rs | 119 +++++++++++++++++++++++ 2 files changed, 120 insertions(+), 88 deletions(-) create mode 100644 crates/ide_db/src/helpers/famous_defs_fixture.rs 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 { - pub const FIXTURE: &'static str = r#"//- /libcore.rs crate:core -pub mod convert { - pub trait From { - fn from(t: T) -> Self; - } -} - -pub mod default { - pub trait Default { - fn default() -> Self; - } -} - -pub mod iter { - pub use self::traits::{collect::IntoIterator, iterator::Iterator}; - mod traits { - pub(crate) mod iterator { - use crate::option::Option; - pub trait Iterator { - type Item; - fn next(&mut self) -> Option; - fn by_ref(&mut self) -> &mut Self { - self - } - fn take(self, n: usize) -> crate::iter::Take { - crate::iter::Take { inner: self } - } - } - - impl Iterator for &mut I { - type Item = I::Item; - fn next(&mut self) -> Option { - (**self).next() - } - } - } - pub(crate) mod collect { - pub trait IntoIterator { - type Item; - } - } - } - - pub use self::sources::*; - pub(crate) mod sources { - use super::Iterator; - use crate::option::Option::{self, *}; - pub struct Repeat { - element: A, - } - - pub fn repeat(elt: T) -> Repeat { - Repeat { element: elt } - } - - impl Iterator for Repeat { - type Item = A; - - fn next(&mut self) -> Option { - None - } - } - } - - pub use self::adapters::*; - pub(crate) mod adapters { - use super::Iterator; - use crate::option::Option::{self, *}; - pub struct Take { pub(crate) inner: I } - impl Iterator for Take where I: Iterator { - type Item = ::Item; - fn next(&mut self) -> Option<::Item> { - None - } - } - } -} - -pub mod option { - pub enum Option { None, Some(T)} -} - -pub mod prelude { - pub use crate::{convert::From, iter::{IntoIterator, Iterator}, option::Option::{self, *}, default::Default}; -} -#[prelude_import] -pub use prelude::*; -"#; + pub const FIXTURE: &'static str = include_str!("helpers/famous_defs_fixture.rs"); pub fn core(&self) -> Option { 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..f3d355861 --- /dev/null +++ b/crates/ide_db/src/helpers/famous_defs_fixture.rs @@ -0,0 +1,119 @@ +//- /libcore.rs crate:core +pub mod convert { + pub trait From { + fn from(t: T) -> Self; + } +} + +pub mod default { + pub trait Default { + fn default() -> Self; + } +} + +pub mod iter { + pub use self::traits::{collect::IntoIterator, iterator::Iterator}; + mod traits { + pub(crate) mod iterator { + use crate::option::Option; + pub trait Iterator { + type Item; + fn next(&mut self) -> Option; + fn by_ref(&mut self) -> &mut Self { + self + } + fn take(self, n: usize) -> crate::iter::Take { + crate::iter::Take { inner: self } + } + } + + impl Iterator for &mut I { + type Item = I::Item; + fn next(&mut self) -> Option { + (**self).next() + } + } + } + pub(crate) mod collect { + pub trait IntoIterator { + type Item; + } + } + } + + pub use self::sources::*; + pub(crate) mod sources { + use super::Iterator; + use crate::option::Option::{self, *}; + pub struct Repeat { + element: A, + } + + pub fn repeat(elt: T) -> Repeat { + Repeat { element: elt } + } + + impl Iterator for Repeat { + type Item = A; + + fn next(&mut self) -> Option { + None + } + } + } + + pub use self::adapters::*; + pub(crate) mod adapters { + use super::Iterator; + use crate::option::Option::{self, *}; + pub struct Take { + pub(crate) inner: I, + } + impl Iterator for Take + where + I: Iterator, + { + type Item = ::Item; + fn next(&mut self) -> Option<::Item> { + None + } + } + } +} + +pub mod ops { + #[lang = "fn"] + pub trait Fn: FnMut { + extern "rust-call" fn call(&self, args: Args) -> Self::Output; + } + + #[lang = "fn_mut"] + pub trait FnMut: FnOnce { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; + } + #[lang = "fn_once"] + pub trait FnOnce { + #[lang = "fn_once_output"] + type Output; + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; + } +} + +pub mod option { + pub enum Option { + None, + Some(T), + } +} + +pub mod prelude { + pub use crate::{ + convert::From, + default::Default, + iter::{IntoIterator, Iterator}, + ops::{Fn, FnMut, FnOnce}, + option::Option::{self, *}, + }; +} +#[prelude_import] +pub use prelude::*; -- cgit v1.2.3 From 3d6480bc3103f7238b1b0e020518e8aa72af3156 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 12 Jan 2021 20:19:13 +0100 Subject: Render Fn* trait objects and impl types as rust does --- crates/hir_ty/src/display.rs | 100 +++++++++++++++++------ crates/hir_ty/src/tests/display_source_code.rs | 15 ++++ crates/hir_ty/src/tests/traits.rs | 8 +- crates/ide/src/inlay_hints.rs | 37 +++++++++ crates/ide_db/src/helpers/famous_defs_fixture.rs | 1 + 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 @@ //! FIXME: write short doc here -use std::fmt; +use std::{borrow::Cow, fmt}; use crate::{ db::HirDatabase, utils::generics, ApplicationTy, CallableDefId, FnSig, GenericPredicate, - Lifetime, Obligation, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, + Lifetime, Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, }; +use arrayvec::ArrayVec; use hir_def::{ - find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId, - Lookup, ModuleId, + db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, + AssocContainerId, HasModule, Lookup, ModuleId, TraitId, }; use hir_expand::name::Name; @@ -257,25 +258,45 @@ impl HirDisplay for ApplicationTy { t.hir_fmt(f)?; write!(f, "; _]")?; } - TypeCtor::RawPtr(m) => { + TypeCtor::RawPtr(m) | TypeCtor::Ref(m) => { let t = self.parameters.as_single(); + let ty_display = + t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target); - write!(f, "*{}", m.as_keyword_for_ptr())?; - if matches!(t, Ty::Dyn(predicates) if predicates.len() > 1) { - write!(f, "(")?; - t.hir_fmt(f)?; - write!(f, ")")?; + if matches!(self.ctor, TypeCtor::RawPtr(_)) { + write!(f, "*{}", m.as_keyword_for_ptr())?; } else { - t.hir_fmt(f)?; + write!(f, "&{}", m.as_keyword_for_ref())?; + } + + let datas; + let predicates = match t { + Ty::Dyn(predicates) if predicates.len() > 1 => { + Cow::Borrowed(predicates.as_ref()) + } + &Ty::Opaque(OpaqueTy { + opaque_ty_id: OpaqueTyId::ReturnTypeImplTrait(func, idx), + ref parameters, + }) => { + datas = + f.db.return_type_impl_traits(func).expect("impl trait id without data"); + let data = (*datas) + .as_ref() + .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); + let bounds = data.subst(parameters); + Cow::Owned(bounds.value) + } + _ => Cow::Borrowed(&[][..]), + }; + + if let [GenericPredicate::Implemented(trait_ref), _] = predicates.as_ref() { + let trait_ = trait_ref.trait_; + if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) { + return write!(f, "{}", ty_display); + } } - } - TypeCtor::Ref(m) => { - let t = self.parameters.as_single(); - let ty_display = - t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target); - write!(f, "&{}", m.as_keyword_for_ref())?; - if matches!(t, Ty::Dyn(predicates) if predicates.len() > 1) { + if predicates.len() > 1 { write!(f, "(")?; write!(f, "{}", ty_display)?; write!(f, ")")?; @@ -595,6 +616,17 @@ impl HirDisplay for FnSig { } } +fn fn_traits(db: &dyn DefDatabase, trait_: TraitId) -> impl Iterator { + let krate = trait_.lookup(db).container.module(db).krate; + let fn_traits = [ + db.lang_item(krate, "fn".into()), + db.lang_item(krate, "fn_mut".into()), + db.lang_item(krate, "fn_once".into()), + ]; + // FIXME: Replace ArrayVec when into_iter is a thing on arrays + ArrayVec::from(fn_traits).into_iter().flatten().flat_map(|it| it.as_trait()) +} + pub fn write_bounds_like_dyn_trait( predicates: &[GenericPredicate], f: &mut HirFormatter, @@ -607,10 +639,15 @@ pub fn write_bounds_like_dyn_trait( // predicate for that trait). let mut first = true; let mut angle_open = false; + let mut is_fn_trait = false; for p in predicates.iter() { match p { GenericPredicate::Implemented(trait_ref) => { - if angle_open { + let trait_ = trait_ref.trait_; + if !is_fn_trait { + is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_); + } + if !is_fn_trait && angle_open { write!(f, ">")?; angle_open = false; } @@ -620,14 +657,27 @@ pub fn write_bounds_like_dyn_trait( // We assume that the self type is $0 (i.e. the // existential) here, which is the only thing that's // possible in actual Rust, and hence don't print it - write!(f, "{}", f.db.trait_data(trait_ref.trait_).name)?; - if trait_ref.substs.len() > 1 { - write!(f, "<")?; - f.write_joined(&trait_ref.substs[1..], ", ")?; - // there might be assoc type bindings, so we leave the angle brackets open - angle_open = true; + write!(f, "{}", f.db.trait_data(trait_).name)?; + if let [_, params @ ..] = &*trait_ref.substs.0 { + if is_fn_trait { + if let Some(args) = params.first().and_then(|it| it.as_tuple()) { + write!(f, "(")?; + f.write_joined(&*args.0, ", ")?; + write!(f, ")")?; + } + } else if !params.is_empty() { + write!(f, "<")?; + f.write_joined(params, ", ")?; + // there might be assoc type bindings, so we leave the angle brackets open + angle_open = true; + } } } + GenericPredicate::Projection(projection_pred) if is_fn_trait => { + is_fn_trait = false; + write!(f, " -> ")?; + projection_pred.ty.hir_fmt(f)?; + } GenericPredicate::Projection(projection_pred) => { // in types in actual Rust, these will always come // 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() { "#, ); } + +#[test] +fn render_raw_ptr_impl_ty() { + check_types_source_code( + r#" +trait Sized {} +trait Unpin {} +fn foo() -> *const (impl Unpin + Sized) { loop {} } +fn main() { + let foo = foo(); + foo; +} //^ *const (impl Unpin + Sized) +"#, + ); +} 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() { 406..417 '&self.inner': &*mut T 407..411 'self': &Box 407..417 'self.inner': *mut T - 478..575 '{ ...(&s) }': FnOnce::Output,)>, (&Option,)> + 478..575 '{ ...(&s) }': FnOnce::Output), (&Option,)> 488..489 's': Option 492..504 'Option::None': Option - 514..515 'f': Box,)>> + 514..515 'f': Box)> 549..562 'box (|ps| {})': Box<|{unknown}| -> ()> 554..561 '|ps| {}': |{unknown}| -> () 555..557 'ps': {unknown} 559..561 '{}': () - 568..569 'f': Box,)>> - 568..573 'f(&s)': FnOnce::Output,)>, (&Option,)> + 568..569 'f': Box)> + 568..573 'f(&s)': FnOnce::Output), (&Option,)> 570..572 '&s': &Option 571..572 's': Option "#]], 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 @@ -1398,6 +1398,43 @@ fn main() { Foo::bar(&Foo); //^^^^ self } +"#, + ) + } + + #[test] + fn fn_hints() { + check( + r#" +trait Sized {} + +fn foo() -> impl Fn() { loop {} } +fn foo1() -> impl Fn(f64) { loop {} } +fn foo2() -> impl Fn(f64, f64) { loop {} } +fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } +fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } +fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } +fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } +fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } + +fn main() { + let foo = foo(); + // ^^^ impl Fn() + let foo = foo1(); + // ^^^ impl Fn(f64) + let foo = foo2(); + // ^^^ impl Fn(f64, f64) + let foo = foo3(); + // ^^^ impl Fn(f64, f64) -> u32 + let foo = foo4(); + // ^^^ &dyn Fn(f64, f64) -> u32 + let foo = foo5(); + // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32 + let foo = foo6(); + // ^^^ impl Fn(f64, f64) -> u32 + Sized + let foo = foo7(); + // ^^^ *const (impl Fn(f64, f64) -> u32 + Sized) +} "#, ) } 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 @@ //- /libcore.rs crate:core +//! Signatures of traits, types and functions from the core lib for use in tests. pub mod convert { pub trait From { 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 { } fn is_exclude_file(d: &Path) -> bool { - let file_names = ["tests.rs"]; + let file_names = ["tests.rs", "famous_defs_fixture.rs"]; d.file_name() .unwrap_or_default() -- cgit v1.2.3