mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-22 20:03:37 +00:00
Improve the function pointer docs
* Reduce duplicate impls; show only the `fn (T)` and include a sentence saying that there exists up to twelve of them. * Show `Copy` and `Clone`. * Show auto traits like `Send` and `Sync`, and blanket impls like `Any`.
This commit is contained in:
parent
1169832f2f
commit
5271e32c46
@ -4,7 +4,7 @@ enum, union, or trait object.
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0118
|
||||
impl fn(u8) { // error: no nominal type found for inherent implementation
|
||||
impl<T> T { // error: no nominal type found for inherent implementation
|
||||
fn get_state(&self) -> String {
|
||||
// ...
|
||||
}
|
||||
@ -20,8 +20,8 @@ trait LiveLongAndProsper {
|
||||
fn get_state(&self) -> String;
|
||||
}
|
||||
|
||||
// and now you can implement it on fn(u8)
|
||||
impl LiveLongAndProsper for fn(u8) {
|
||||
// and now you can implement it on T
|
||||
impl<T> LiveLongAndProsper for T {
|
||||
fn get_state(&self) -> String {
|
||||
"He's dead, Jim!".to_owned()
|
||||
}
|
||||
@ -33,9 +33,9 @@ For example, `NewType` is a newtype over `Foo` in `struct NewType(Foo)`.
|
||||
Example:
|
||||
|
||||
```
|
||||
struct TypeWrapper(fn(u8));
|
||||
struct TypeWrapper<T>(T);
|
||||
|
||||
impl TypeWrapper {
|
||||
impl<T> TypeWrapper<T> {
|
||||
fn get_state(&self) -> String {
|
||||
"Fascinating!".to_owned()
|
||||
}
|
||||
|
@ -219,8 +219,9 @@ impl<'tcx> InherentCollect<'tcx> {
|
||||
| ty::RawPtr(_)
|
||||
| ty::Ref(..)
|
||||
| ty::Never
|
||||
| ty::FnPtr(_)
|
||||
| ty::Tuple(..) => self.check_primitive_impl(item.def_id, self_ty, items, ty.span),
|
||||
ty::FnPtr(_) | ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
|
||||
ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
ty.span,
|
||||
|
@ -1441,11 +1441,16 @@ mod prim_ref {}
|
||||
/// Note that all of this is not portable to platforms where function pointers and data pointers
|
||||
/// have different sizes.
|
||||
///
|
||||
/// ### Traits
|
||||
/// ### Trait implementations
|
||||
///
|
||||
/// Function pointers implement the following traits:
|
||||
/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic
|
||||
/// function pointers of varying length. Note that this is a convenience notation to avoid
|
||||
/// repetitive documentation, not valid Rust syntax.
|
||||
///
|
||||
/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
|
||||
/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
|
||||
/// may change:
|
||||
///
|
||||
/// * [`Clone`]
|
||||
/// * [`PartialEq`]
|
||||
/// * [`Eq`]
|
||||
/// * [`PartialOrd`]
|
||||
@ -1454,15 +1459,50 @@ mod prim_ref {}
|
||||
/// * [`Pointer`]
|
||||
/// * [`Debug`]
|
||||
///
|
||||
/// The following traits are implemented for function pointers with any number of arguments and
|
||||
/// any ABI. These traits have implementations that are automatically generated by the compiler,
|
||||
/// so are not limited by missing language features:
|
||||
///
|
||||
/// * [`Clone`]
|
||||
/// * [`Copy`]
|
||||
/// * [`Send`]
|
||||
/// * [`Sync`]
|
||||
/// * [`Unpin`]
|
||||
/// * [`UnwindSafe`]
|
||||
/// * [`RefUnwindSafe`]
|
||||
///
|
||||
/// [`Hash`]: hash::Hash
|
||||
/// [`Pointer`]: fmt::Pointer
|
||||
/// [`UnwindSafe`]: panic::UnwindSafe
|
||||
/// [`RefUnwindSafe`]: panic::RefUnwindSafe
|
||||
///
|
||||
/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
|
||||
/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
|
||||
/// may change.
|
||||
///
|
||||
/// In addition, function pointers of *any* signature, ABI, or safety are [`Copy`], and all *safe*
|
||||
/// function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`]. This works because these traits
|
||||
/// are specially known to the compiler.
|
||||
/// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
|
||||
/// these traits are specially known to the compiler.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
mod prim_fn {}
|
||||
|
||||
// Required to make auto trait impls render.
|
||||
// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
|
||||
#[doc(hidden)]
|
||||
#[cfg(not(bootstrap))]
|
||||
impl<Ret, T> fn(T) -> Ret {}
|
||||
|
||||
// Fake impl that's only really used for docs.
|
||||
#[cfg(doc)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
|
||||
/// This trait is implemented on function pointers with any number of arguments.
|
||||
impl<Ret, T> Clone for fn(T) -> Ret {
|
||||
fn clone(&self) -> Self {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
// Fake impl that's only really used for docs.
|
||||
#[cfg(doc)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
|
||||
/// This trait is implemented on function pointers with any number of arguments.
|
||||
impl<Ret, T> Copy for fn(T) -> Ret {
|
||||
// empty
|
||||
}
|
||||
|
@ -1819,6 +1819,27 @@ pub fn hash<T: ?Sized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
|
||||
hashee.hash(into);
|
||||
}
|
||||
|
||||
// If this is a unary fn pointer, it adds a doc comment.
|
||||
// Otherwise, it hides the docs entirely.
|
||||
macro_rules! maybe_fnptr_doc {
|
||||
(@ #[$meta:meta] $item:item) => {
|
||||
#[doc(hidden)]
|
||||
#[$meta]
|
||||
$item
|
||||
};
|
||||
($a:ident @ #[$meta:meta] $item:item) => {
|
||||
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
|
||||
#[doc = "This trait is implemented for function pointers with up to twelve arguments."]
|
||||
#[$meta]
|
||||
$item
|
||||
};
|
||||
($a:ident $($rest_a:ident)+ @ #[$meta:meta] $item:item) => {
|
||||
#[doc(hidden)]
|
||||
#[$meta]
|
||||
$item
|
||||
};
|
||||
}
|
||||
|
||||
// FIXME(strict_provenance_magic): function pointers have buggy codegen that
|
||||
// necessitates casting to a usize to get the backend to do the right thing.
|
||||
// for now I will break AVR to silence *a billion* lints. We should probably
|
||||
@ -1827,51 +1848,72 @@ pub fn hash<T: ?Sized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
|
||||
// Impls for function pointers
|
||||
macro_rules! fnptr_impls_safety_abi {
|
||||
($FnTy: ty, $($Arg: ident),*) => {
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> PartialEq for $FnTy {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
*self as usize == *other as usize
|
||||
maybe_fnptr_doc! {
|
||||
$($Arg)* @
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> PartialEq for $FnTy {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
*self as usize == *other as usize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> Eq for $FnTy {}
|
||||
maybe_fnptr_doc! {
|
||||
$($Arg)* @
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> Eq for $FnTy {}
|
||||
}
|
||||
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> PartialOrd for $FnTy {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
(*self as usize).partial_cmp(&(*other as usize))
|
||||
maybe_fnptr_doc! {
|
||||
$($Arg)* @
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> PartialOrd for $FnTy {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
(*self as usize).partial_cmp(&(*other as usize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> Ord for $FnTy {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
(*self as usize).cmp(&(*other as usize))
|
||||
maybe_fnptr_doc! {
|
||||
$($Arg)* @
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> Ord for $FnTy {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
(*self as usize).cmp(&(*other as usize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> hash::Hash for $FnTy {
|
||||
fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
|
||||
state.write_usize(*self as usize)
|
||||
maybe_fnptr_doc! {
|
||||
$($Arg)* @
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> hash::Hash for $FnTy {
|
||||
fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
|
||||
state.write_usize(*self as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::pointer_fmt_inner(*self as usize, f)
|
||||
maybe_fnptr_doc! {
|
||||
$($Arg)* @
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::pointer_fmt_inner(*self as usize, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::pointer_fmt_inner(*self as usize, f)
|
||||
maybe_fnptr_doc! {
|
||||
$($Arg)* @
|
||||
#[stable(feature = "fnptr_impls", since = "1.4.0")]
|
||||
impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::pointer_fmt_inner(*self as usize, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1441,11 +1441,16 @@ mod prim_ref {}
|
||||
/// Note that all of this is not portable to platforms where function pointers and data pointers
|
||||
/// have different sizes.
|
||||
///
|
||||
/// ### Traits
|
||||
/// ### Trait implementations
|
||||
///
|
||||
/// Function pointers implement the following traits:
|
||||
/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic
|
||||
/// function pointers of varying length. Note that this is a convenience notation to avoid
|
||||
/// repetitive documentation, not valid Rust syntax.
|
||||
///
|
||||
/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
|
||||
/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
|
||||
/// may change:
|
||||
///
|
||||
/// * [`Clone`]
|
||||
/// * [`PartialEq`]
|
||||
/// * [`Eq`]
|
||||
/// * [`PartialOrd`]
|
||||
@ -1454,15 +1459,50 @@ mod prim_ref {}
|
||||
/// * [`Pointer`]
|
||||
/// * [`Debug`]
|
||||
///
|
||||
/// The following traits are implemented for function pointers with any number of arguments and
|
||||
/// any ABI. These traits have implementations that are automatically generated by the compiler,
|
||||
/// so are not limited by missing language features:
|
||||
///
|
||||
/// * [`Clone`]
|
||||
/// * [`Copy`]
|
||||
/// * [`Send`]
|
||||
/// * [`Sync`]
|
||||
/// * [`Unpin`]
|
||||
/// * [`UnwindSafe`]
|
||||
/// * [`RefUnwindSafe`]
|
||||
///
|
||||
/// [`Hash`]: hash::Hash
|
||||
/// [`Pointer`]: fmt::Pointer
|
||||
/// [`UnwindSafe`]: panic::UnwindSafe
|
||||
/// [`RefUnwindSafe`]: panic::RefUnwindSafe
|
||||
///
|
||||
/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
|
||||
/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
|
||||
/// may change.
|
||||
///
|
||||
/// In addition, function pointers of *any* signature, ABI, or safety are [`Copy`], and all *safe*
|
||||
/// function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`]. This works because these traits
|
||||
/// are specially known to the compiler.
|
||||
/// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
|
||||
/// these traits are specially known to the compiler.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
mod prim_fn {}
|
||||
|
||||
// Required to make auto trait impls render.
|
||||
// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
|
||||
#[doc(hidden)]
|
||||
#[cfg(not(bootstrap))]
|
||||
impl<Ret, T> fn(T) -> Ret {}
|
||||
|
||||
// Fake impl that's only really used for docs.
|
||||
#[cfg(doc)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
|
||||
/// This trait is implemented on function pointers with any number of arguments.
|
||||
impl<Ret, T> Clone for fn(T) -> Ret {
|
||||
fn clone(&self) -> Self {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
// Fake impl that's only really used for docs.
|
||||
#[cfg(doc)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
|
||||
/// This trait is implemented on function pointers with any number of arguments.
|
||||
impl<Ret, T> Copy for fn(T) -> Ret {
|
||||
// empty
|
||||
}
|
||||
|
@ -1841,7 +1841,7 @@ impl PrimitiveType {
|
||||
Reference => [RefSimplifiedType(Mutability::Not), RefSimplifiedType(Mutability::Mut)].into_iter().collect(),
|
||||
// FIXME: This will be wrong if we ever add inherent impls
|
||||
// for function pointers.
|
||||
Fn => ArrayVec::new(),
|
||||
Fn => single(FunctionSimplifiedType(1)),
|
||||
Never => single(NeverSimplifiedType),
|
||||
}
|
||||
})
|
||||
|
@ -1165,18 +1165,38 @@ impl clean::Impl {
|
||||
|
||||
if let clean::Type::Tuple(types) = &self.for_ &&
|
||||
let [clean::Type::Generic(name)] = &types[..] &&
|
||||
(self.kind.is_fake_variadic() || self.kind.is_auto()) {
|
||||
(self.kind.is_fake_variadic() || self.kind.is_auto())
|
||||
{
|
||||
// Hardcoded anchor library/core/src/primitive_docs.rs
|
||||
// Link should match `# Trait implementations`
|
||||
primitive_link_fragment(f, PrimitiveType::Tuple, &format!("({name}₁, {name}₂, …, {name}ₙ)"), "#trait-implementations-1", cx)?;
|
||||
} else if let clean::Type::BareFunction(bare_fn) = &self.for_ &&
|
||||
} else if let clean::BareFunction(bare_fn) = &self.for_ &&
|
||||
let [clean::Argument { type_: clean::Type::Generic(name), .. }] = &bare_fn.decl.inputs.values[..] &&
|
||||
(self.kind.is_fake_variadic() || self.kind.is_auto()) {
|
||||
(self.kind.is_fake_variadic() || self.kind.is_auto())
|
||||
{
|
||||
// Hardcoded anchor library/core/src/primitive_docs.rs
|
||||
// Link should match `# Trait implementations`
|
||||
primitive_link_fragment(f, PrimitiveType::Tuple, &format!("fn ({name}₁, {name}₂, …, {name}ₙ)"), "#trait-implementations-1", cx)?;
|
||||
// Not implemented.
|
||||
assert!(!bare_fn.decl.c_variadic);
|
||||
|
||||
let hrtb = bare_fn.print_hrtb_with_space(cx);
|
||||
let unsafety = bare_fn.unsafety.print_with_space();
|
||||
let abi = print_abi_with_space(bare_fn.abi);
|
||||
if f.alternate() {
|
||||
write!(
|
||||
f,
|
||||
"{hrtb:#}{unsafety}{abi:#}",
|
||||
)?;
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"{hrtb}{unsafety}{abi}",
|
||||
)?;
|
||||
}
|
||||
let ellipsis = if bare_fn.decl.c_variadic {
|
||||
", ..."
|
||||
} else {
|
||||
""
|
||||
};
|
||||
primitive_link_fragment(f, PrimitiveType::Tuple, &format!("fn ({name}₁, {name}₂, …, {name}ₙ{ellipsis})"), "#trait-implementations-1", cx)?;
|
||||
// Write output.
|
||||
if let clean::FnRetTy::Return(ty) = &bare_fn.decl.output {
|
||||
write!(f, " -> ")?;
|
||||
|
@ -1,4 +1,4 @@
|
||||
impl fn(u8) { //~ ERROR E0118
|
||||
impl<T> T { //~ ERROR E0118
|
||||
fn get_state(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
error[E0118]: no nominal type found for inherent implementation
|
||||
--> $DIR/E0118.rs:1:6
|
||||
--> $DIR/E0118.rs:1:9
|
||||
|
|
||||
LL | impl fn(u8) {
|
||||
| ^^^^^^ impl requires a nominal type
|
||||
LL | impl<T> T {
|
||||
| ^ impl requires a nominal type
|
||||
|
|
||||
= note: either implement a trait on it or create a newtype to wrap it instead
|
||||
|
||||
|
@ -4,5 +4,7 @@ struct Foo {
|
||||
|
||||
impl *mut Foo {} //~ ERROR E0390
|
||||
|
||||
impl fn(Foo) {} //~ ERROR E0390
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
@ -6,6 +6,14 @@ LL | impl *mut Foo {}
|
||||
|
|
||||
= help: consider using an extension trait instead
|
||||
|
||||
error: aborting due to previous error
|
||||
error[E0390]: cannot define inherent `impl` for primitive types
|
||||
--> $DIR/E0390.rs:7:6
|
||||
|
|
||||
LL | impl fn(Foo) {}
|
||||
| ^^^^^^^
|
||||
|
|
||||
= help: consider using an extension trait instead
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0390`.
|
||||
|
@ -96,13 +96,13 @@ LL | assert_eq!(Foo::Bar, i);
|
||||
= help: the trait `Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}`
|
||||
= help: the following other types implement trait `Debug`:
|
||||
extern "C" fn() -> Ret
|
||||
extern "C" fn(A) -> Ret
|
||||
extern "C" fn(A, ...) -> Ret
|
||||
extern "C" fn(A, B) -> Ret
|
||||
extern "C" fn(A, B, ...) -> Ret
|
||||
extern "C" fn(A, B, C) -> Ret
|
||||
extern "C" fn(A, B, C, ...) -> Ret
|
||||
extern "C" fn(A, B, C, D) -> Ret
|
||||
extern "C" fn(A, B, C, D, ...) -> Ret
|
||||
extern "C" fn(A, B, C, D, E) -> Ret
|
||||
and 68 others
|
||||
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user