From 35611872210094bfa7d9eaacc83badb218ed045e Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Thu, 31 Mar 2022 00:58:43 +0900 Subject: [PATCH 01/14] Improve floating point documentation: - Refine the "NaN as a special value" top level explanation of f32 - Refine `const NAN` docstring. - Refine `fn is_sign_positive` and `fn is_sign_negative` docstrings. - Refine `fn min` and `fn max` docstrings. - Refine `fn trunc` docstrings. - Refine `fn powi` docstrings. - Refine `fn copysign` docstrings. - Reword `NaN` and `NAN` as plain "NaN", unless they refer to the specific `const NAN`. - Reword "a number" to `self` in function docstrings to clarify. - Remove "Returns NAN if the number is NAN" as this is told to be the default behavior in the top explanation. - Remove "propagating NaNs", as full propagation (preservation of payloads) is not guaranteed. --- library/core/src/num/f32.rs | 51 ++++++++++++++++++++---------- library/core/src/num/f64.rs | 51 ++++++++++++++++++++---------- library/core/src/primitive_docs.rs | 18 ++++++++--- library/std/src/f32.rs | 26 ++++++++------- library/std/src/f64.rs | 26 ++++++++------- library/std/src/primitive_docs.rs | 18 ++++++++--- 6 files changed, 126 insertions(+), 64 deletions(-) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 17ca854768546..835651c5057fa 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -418,6 +418,15 @@ impl f32 { pub const MAX_10_EXP: i32 = 38; /// Not a Number (NaN). + /// + /// Note that IEEE-745 doesn't define just a single NaN value; + /// a plethora of bit patterns are considered to be NaN. + /// Furthermore, the standard makes a difference + /// between a "signaling" and a "quiet" NaN, + /// and allows inspecting its "payload" (the unspecified bits in the bit pattern). + /// This constant isn't guaranteed to equal to any specific NaN bitpattern, + /// and the stability of its representation over Rust versions + /// and target platforms isn't guaranteed. #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const NAN: f32 = 0.0_f32 / 0.0_f32; /// Infinity (∞). @@ -427,7 +436,7 @@ impl f32 { #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32; - /// Returns `true` if this value is `NaN`. + /// Returns `true` if this value is NaN. /// /// ``` /// let nan = f32::NAN; @@ -476,7 +485,7 @@ impl f32 { self.abs_private() == Self::INFINITY } - /// Returns `true` if this number is neither infinite nor `NaN`. + /// Returns `true` if this number is neither infinite nor NaN. /// /// ``` /// let f = 7.0f32; @@ -527,7 +536,7 @@ impl f32 { } /// Returns `true` if the number is neither zero, infinite, - /// [subnormal], or `NaN`. + /// [subnormal], or NaN. /// /// ``` /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 @@ -582,8 +591,12 @@ impl f32 { } } - /// Returns `true` if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. + /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with + /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any + /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that + /// the bit pattern of NaNs are conserved over arithmetic operations, the result of + /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. + /// See [explanation of NaN as a special value](f32) for more info. /// /// ``` /// let f = 7.0_f32; @@ -600,8 +613,12 @@ impl f32 { !self.is_sign_negative() } - /// Returns `true` if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. + /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with + /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any + /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that + /// the bit pattern of NaNs are conserved over arithmetic operations, the result of + /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. + /// See [explanation of NaN as a special value](f32) for more info. /// /// ``` /// let f = 7.0f32; @@ -674,8 +691,10 @@ impl f32 { /// Returns the maximum of the two numbers. /// - /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs. - /// This matches the behavior of libm’s fmax. + /// If one of the arguments is NaN, then the other argument is returned. + /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs; + /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. + /// This also matches the behavior of libm’s fmax. /// /// ``` /// let x = 1.0f32; @@ -683,8 +702,6 @@ impl f32 { /// /// assert_eq!(x.max(y), y); /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -694,8 +711,10 @@ impl f32 { /// Returns the minimum of the two numbers. /// - /// Follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs. - /// This matches the behavior of libm’s fmin. + /// If one of the arguments is NaN, then the other argument is returned. + /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs; + /// this function handles all NaNs the same way and avoids minNum's problems with associativity. + /// This also matches the behavior of libm’s fmin. /// /// ``` /// let x = 1.0f32; @@ -703,8 +722,6 @@ impl f32 { /// /// assert_eq!(x.min(y), x); /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -712,7 +729,7 @@ impl f32 { intrinsics::minnumf32(self, other) } - /// Returns the maximum of the two numbers, propagating NaNs. + /// Returns the maximum of the two numbers. /// /// This returns NaN when *either* argument is NaN, as opposed to /// [`f32::max`] which only returns NaN when *both* arguments are NaN. @@ -744,7 +761,7 @@ impl f32 { } } - /// Returns the minimum of the two numbers, propagating NaNs. + /// Returns the minimum of the two numbers. /// /// This returns NaN when *either* argument is NaN, as opposed to /// [`f32::min`] which only returns NaN when *both* arguments are NaN. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 350d8529de57a..b0971233f250f 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -417,6 +417,15 @@ impl f64 { pub const MAX_10_EXP: i32 = 308; /// Not a Number (NaN). + /// + /// Note that IEEE-745 doesn't define just a single NaN value; + /// a plethora of bit patterns are considered to be NaN. + /// Furthermore, the standard makes a difference + /// between a "signaling" and a "quiet" NaN, + /// and allows inspecting its "payload" (the unspecified bits in the bit pattern). + /// This constant isn't guaranteed to equal to any specific NaN bitpattern, + /// and the stability of its representation over Rust versions + /// and target platforms isn't guaranteed. #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const NAN: f64 = 0.0_f64 / 0.0_f64; /// Infinity (∞). @@ -426,7 +435,7 @@ impl f64 { #[stable(feature = "assoc_int_consts", since = "1.43.0")] pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64; - /// Returns `true` if this value is `NaN`. + /// Returns `true` if this value is NaN. /// /// ``` /// let nan = f64::NAN; @@ -475,7 +484,7 @@ impl f64 { self.abs_private() == Self::INFINITY } - /// Returns `true` if this number is neither infinite nor `NaN`. + /// Returns `true` if this number is neither infinite nor NaN. /// /// ``` /// let f = 7.0f64; @@ -526,7 +535,7 @@ impl f64 { } /// Returns `true` if the number is neither zero, infinite, - /// [subnormal], or `NaN`. + /// [subnormal], or NaN. /// /// ``` /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64 @@ -581,8 +590,12 @@ impl f64 { } } - /// Returns `true` if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. + /// Returns `true` if `self` has a positive sign, including `+0.0`, NaNs with + /// positive sign bit and positive infinity. Note that IEEE-745 doesn't assign any + /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that + /// the bit pattern of NaNs are conserved over arithmetic operations, the result of + /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. + /// See [explanation of NaN as a special value](f32) for more info. /// /// ``` /// let f = 7.0_f64; @@ -608,8 +621,12 @@ impl f64 { self.is_sign_positive() } - /// Returns `true` if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. + /// Returns `true` if `self` has a negative sign, including `-0.0`, NaNs with + /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any + /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that + /// the bit pattern of NaNs are conserved over arithmetic operations, the result of + /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. + /// See [explanation of NaN as a special value](f32) for more info. /// /// ``` /// let f = 7.0_f64; @@ -690,8 +707,10 @@ impl f64 { /// Returns the maximum of the two numbers. /// - /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs. - /// This matches the behavior of libm’s fmax. + /// If one of the arguments is NaN, then the other argument is returned. + /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs; + /// this function handles all NaNs the same way and avoids maxNum's problems with associativity. + /// This also matches the behavior of libm’s fmax. /// /// ``` /// let x = 1.0_f64; @@ -699,8 +718,6 @@ impl f64 { /// /// assert_eq!(x.max(y), y); /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -710,8 +727,10 @@ impl f64 { /// Returns the minimum of the two numbers. /// - /// Follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs. - /// This matches the behavior of libm’s fmin. + /// If one of the arguments is NaN, then the other argument is returned. + /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs; + /// this function handles all NaNs the same way and avoids minNum's problems with associativity. + /// This also matches the behavior of libm’s fmin. /// /// ``` /// let x = 1.0_f64; @@ -719,8 +738,6 @@ impl f64 { /// /// assert_eq!(x.min(y), x); /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. #[must_use = "this returns the result of the comparison, without modifying either input"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -728,7 +745,7 @@ impl f64 { intrinsics::minnumf64(self, other) } - /// Returns the maximum of the two numbers, propagating NaNs. + /// Returns the maximum of the two numbers. /// /// This returns NaN when *either* argument is NaN, as opposed to /// [`f64::max`] which only returns NaN when *both* arguments are NaN. @@ -760,7 +777,7 @@ impl f64 { } } - /// Returns the minimum of the two numbers, propagating NaNs. + /// Returns the minimum of the two numbers. /// /// This returns NaN when *either* argument is NaN, as opposed to /// [`f64::min`] which only returns NaN when *both* arguments are NaN. diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 225a679efd221..188cb8f983bc1 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -977,10 +977,20 @@ mod prim_tuple {} /// like `1.0 / 0.0`. /// - [NaN (not a number)](#associatedconstant.NAN): this value results from /// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected -/// behavior: it is unequal to any float, including itself! It is also neither -/// smaller nor greater than any float, making it impossible to sort. Lastly, -/// it is considered infectious as almost all calculations where one of the -/// operands is NaN will also result in NaN. +/// behavior: +/// - It is unequal to any float, including itself! +/// - It is also neither smaller nor greater than any float, making it +/// impossible to sort by the default comparison operation. This is the +/// reason `f32` doesn't implement the `Ord` and `Eq` traits. +/// - It is also considered *infectious* as almost all calculations where one +/// of the operands is NaN will also result in NaN. The explanations on this +/// page only explicitly document behavior on NaN operands if this default +/// is *not* observed by the operation. +/// - Lastly, there are multiple bit patterns that are considered NaN. +/// Rust does not currently guarantee that the bit patterns of NaN are +/// preserved over arithmetic operations, +/// so there may be some surprising results upon inspecting the bit patterns, +/// as the same calculations might produce NaNs with different bit patterns. /// /// For more information on floating point numbers, see [Wikipedia][wikipedia]. /// diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 70b5941c7c72b..469db1b7c2836 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -30,7 +30,7 @@ pub use core::f32::{ #[cfg(not(test))] #[cfg_attr(bootstrap, lang = "f32_runtime")] impl f32 { - /// Returns the largest integer less than or equal to a number. + /// Returns the largest integer less than or equal to `self`. /// /// # Examples /// @@ -51,7 +51,7 @@ impl f32 { unsafe { intrinsics::floorf32(self) } } - /// Returns the smallest integer greater than or equal to a number. + /// Returns the smallest integer greater than or equal to `self`. /// /// # Examples /// @@ -70,7 +70,7 @@ impl f32 { unsafe { intrinsics::ceilf32(self) } } - /// Returns the nearest integer to a number. Round half-way cases away from + /// Returns the nearest integer to `self`. Round half-way cases away from /// `0.0`. /// /// # Examples @@ -90,7 +90,8 @@ impl f32 { unsafe { intrinsics::roundf32(self) } } - /// Returns the integer part of a number. + /// Returns the integer part of `self`. + /// This means that non-integer numbers are always truncated towards zero. /// /// # Examples /// @@ -111,7 +112,7 @@ impl f32 { unsafe { intrinsics::truncf32(self) } } - /// Returns the fractional part of a number. + /// Returns the fractional part of `self`. /// /// # Examples /// @@ -132,8 +133,7 @@ impl f32 { self - self.trunc() } - /// Computes the absolute value of `self`. Returns `NAN` if the - /// number is `NAN`. + /// Computes the absolute value of `self`. /// /// # Examples /// @@ -161,7 +161,7 @@ impl f32 { /// /// - `1.0` if the number is positive, `+0.0` or `INFINITY` /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` - /// - `NAN` if the number is `NAN` + /// - NaN if the number is NaN /// /// # Examples /// @@ -185,8 +185,10 @@ impl f32 { /// `sign`. /// /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise - /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of - /// `sign` is returned. + /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of + /// `sign` is returned. Note, however, that conserving the sign bit on NaN + /// across arithmetical operations is not generally guaranteed. + /// See [explanation of NaN as a special value](primitive@f32) for more info. /// /// # Examples /// @@ -299,7 +301,9 @@ impl f32 { /// Raises a number to an integer power. /// - /// Using this function is generally faster than using `powf` + /// Using this function is generally faster than using `powf`. + /// It might have different sequence of rounding operations than `powf`, + /// so the results are not guaranteed to agree. /// /// # Examples /// diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index b90d068ec10d3..a291a777e5565 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -30,7 +30,7 @@ pub use core::f64::{ #[cfg(not(test))] #[cfg_attr(bootstrap, lang = "f64_runtime")] impl f64 { - /// Returns the largest integer less than or equal to a number. + /// Returns the largest integer less than or equal to `self`. /// /// # Examples /// @@ -51,7 +51,7 @@ impl f64 { unsafe { intrinsics::floorf64(self) } } - /// Returns the smallest integer greater than or equal to a number. + /// Returns the smallest integer greater than or equal to `self`. /// /// # Examples /// @@ -70,7 +70,7 @@ impl f64 { unsafe { intrinsics::ceilf64(self) } } - /// Returns the nearest integer to a number. Round half-way cases away from + /// Returns the nearest integer to `self`. Round half-way cases away from /// `0.0`. /// /// # Examples @@ -90,7 +90,8 @@ impl f64 { unsafe { intrinsics::roundf64(self) } } - /// Returns the integer part of a number. + /// Returns the integer part of `self`. + /// This means that non-integer numbers are always truncated towards zero. /// /// # Examples /// @@ -111,7 +112,7 @@ impl f64 { unsafe { intrinsics::truncf64(self) } } - /// Returns the fractional part of a number. + /// Returns the fractional part of `self`. /// /// # Examples /// @@ -132,8 +133,7 @@ impl f64 { self - self.trunc() } - /// Computes the absolute value of `self`. Returns `NAN` if the - /// number is `NAN`. + /// Computes the absolute value of `self`. /// /// # Examples /// @@ -161,7 +161,7 @@ impl f64 { /// /// - `1.0` if the number is positive, `+0.0` or `INFINITY` /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` - /// - `NAN` if the number is `NAN` + /// - NaN if the number is NaN /// /// # Examples /// @@ -185,8 +185,10 @@ impl f64 { /// `sign`. /// /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise - /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of - /// `sign` is returned. + /// equal to `-self`. If `self` is a NaN, then a NaN with the sign bit of + /// `sign` is returned. Note, however, that conserving the sign bit on NaN + /// across arithmetical operations is not generally guaranteed. + /// See [explanation of NaN as a special value](primitive@f32) for more info. /// /// # Examples /// @@ -299,7 +301,9 @@ impl f64 { /// Raises a number to an integer power. /// - /// Using this function is generally faster than using `powf` + /// Using this function is generally faster than using `powf`. + /// It might have different sequence of rounding operations than `powf`, + /// so the results are not guaranteed to agree. /// /// # Examples /// diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 225a679efd221..188cb8f983bc1 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -977,10 +977,20 @@ mod prim_tuple {} /// like `1.0 / 0.0`. /// - [NaN (not a number)](#associatedconstant.NAN): this value results from /// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected -/// behavior: it is unequal to any float, including itself! It is also neither -/// smaller nor greater than any float, making it impossible to sort. Lastly, -/// it is considered infectious as almost all calculations where one of the -/// operands is NaN will also result in NaN. +/// behavior: +/// - It is unequal to any float, including itself! +/// - It is also neither smaller nor greater than any float, making it +/// impossible to sort by the default comparison operation. This is the +/// reason `f32` doesn't implement the `Ord` and `Eq` traits. +/// - It is also considered *infectious* as almost all calculations where one +/// of the operands is NaN will also result in NaN. The explanations on this +/// page only explicitly document behavior on NaN operands if this default +/// is *not* observed by the operation. +/// - Lastly, there are multiple bit patterns that are considered NaN. +/// Rust does not currently guarantee that the bit patterns of NaN are +/// preserved over arithmetic operations, +/// so there may be some surprising results upon inspecting the bit patterns, +/// as the same calculations might produce NaNs with different bit patterns. /// /// For more information on floating point numbers, see [Wikipedia][wikipedia]. /// From a96577892858571c2894bbc68d9ff60e02284360 Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Thu, 31 Mar 2022 02:22:26 +0900 Subject: [PATCH 02/14] Fix: is_sign_positive -> is_sign_negative --- library/core/src/num/f32.rs | 2 +- library/core/src/num/f64.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 835651c5057fa..cae7c26941d0c 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -617,7 +617,7 @@ impl f32 { /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that /// the bit pattern of NaNs are conserved over arithmetic operations, the result of - /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. + /// `is_sign_negative` on a NaN might produce an unexpected result in some cases. /// See [explanation of NaN as a special value](f32) for more info. /// /// ``` diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index b0971233f250f..eefb045073d72 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -625,7 +625,7 @@ impl f64 { /// negative sign bit and negative infinity. Note that IEEE-745 doesn't assign any /// meaning to the sign bit in case of a NaN, and as Rust doesn't guarantee that /// the bit pattern of NaNs are conserved over arithmetic operations, the result of - /// `is_sign_positive` on a NaN might produce an unexpected result in some cases. + /// `is_sign_negative` on a NaN might produce an unexpected result in some cases. /// See [explanation of NaN as a special value](f32) for more info. /// /// ``` From fff5a06f282ae6927fca1fbf8e8ed437e6772b9e Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Thu, 31 Mar 2022 02:28:52 +0900 Subject: [PATCH 03/14] Add references to explanation about portability to f{32,64}::{from,to}_{be,le,ne}_bytes --- library/core/src/num/f32.rs | 18 ++++++++++++++++++ library/core/src/num/f64.rs | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index cae7c26941d0c..b408b5d3d5de5 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -902,6 +902,9 @@ impl f32 { /// Return the memory representation of this floating point number as a byte array in /// big-endian (network) byte order. /// + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// /// # Examples /// /// ``` @@ -920,6 +923,9 @@ impl f32 { /// Return the memory representation of this floating point number as a byte array in /// little-endian byte order. /// + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// /// # Examples /// /// ``` @@ -944,6 +950,9 @@ impl f32 { /// [`to_be_bytes`]: f32::to_be_bytes /// [`to_le_bytes`]: f32::to_le_bytes /// + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// /// # Examples /// /// ``` @@ -968,6 +977,9 @@ impl f32 { /// Create a floating point value from its representation as a byte array in big endian. /// + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// /// # Examples /// /// ``` @@ -984,6 +996,9 @@ impl f32 { /// Create a floating point value from its representation as a byte array in little endian. /// + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// /// # Examples /// /// ``` @@ -1007,6 +1022,9 @@ impl f32 { /// [`from_be_bytes`]: f32::from_be_bytes /// [`from_le_bytes`]: f32::from_le_bytes /// + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// /// # Examples /// /// ``` diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index eefb045073d72..db39612265186 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -918,6 +918,9 @@ impl f64 { /// Return the memory representation of this floating point number as a byte array in /// big-endian (network) byte order. /// + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// /// # Examples /// /// ``` @@ -936,6 +939,9 @@ impl f64 { /// Return the memory representation of this floating point number as a byte array in /// little-endian byte order. /// + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// /// # Examples /// /// ``` @@ -960,6 +966,9 @@ impl f64 { /// [`to_be_bytes`]: f64::to_be_bytes /// [`to_le_bytes`]: f64::to_le_bytes /// + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// /// # Examples /// /// ``` @@ -984,6 +993,9 @@ impl f64 { /// Create a floating point value from its representation as a byte array in big endian. /// + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// /// # Examples /// /// ``` @@ -1000,6 +1012,9 @@ impl f64 { /// Create a floating point value from its representation as a byte array in little endian. /// + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// /// # Examples /// /// ``` @@ -1023,6 +1038,9 @@ impl f64 { /// [`from_be_bytes`]: f64::from_be_bytes /// [`from_le_bytes`]: f64::from_le_bytes /// + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). + /// /// # Examples /// /// ``` From 4ee8b64a81b2e518d24f2e8acd2dfeebc686dd5d Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Thu, 31 Mar 2022 11:27:23 +0900 Subject: [PATCH 04/14] Improve wording of "NaN as a special value" top level explanation --- library/core/src/primitive_docs.rs | 9 +++++---- library/std/src/primitive_docs.rs | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 188cb8f983bc1..ab4bb0f26696b 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -978,14 +978,15 @@ mod prim_tuple {} /// - [NaN (not a number)](#associatedconstant.NAN): this value results from /// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected /// behavior: -/// - It is unequal to any float, including itself! +/// - It is unequal to any float, including itself! This is the reason `f32` +/// doesn't implement the `Eq` trait. /// - It is also neither smaller nor greater than any float, making it -/// impossible to sort by the default comparison operation. This is the -/// reason `f32` doesn't implement the `Ord` and `Eq` traits. +/// impossible to sort by the default comparison operation, which is the +/// reason `f32` doesn't implement the `Ord` trait. /// - It is also considered *infectious* as almost all calculations where one /// of the operands is NaN will also result in NaN. The explanations on this /// page only explicitly document behavior on NaN operands if this default -/// is *not* observed by the operation. +/// is deviated from. /// - Lastly, there are multiple bit patterns that are considered NaN. /// Rust does not currently guarantee that the bit patterns of NaN are /// preserved over arithmetic operations, diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 188cb8f983bc1..ab4bb0f26696b 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -978,14 +978,15 @@ mod prim_tuple {} /// - [NaN (not a number)](#associatedconstant.NAN): this value results from /// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected /// behavior: -/// - It is unequal to any float, including itself! +/// - It is unequal to any float, including itself! This is the reason `f32` +/// doesn't implement the `Eq` trait. /// - It is also neither smaller nor greater than any float, making it -/// impossible to sort by the default comparison operation. This is the -/// reason `f32` doesn't implement the `Ord` and `Eq` traits. +/// impossible to sort by the default comparison operation, which is the +/// reason `f32` doesn't implement the `Ord` trait. /// - It is also considered *infectious* as almost all calculations where one /// of the operands is NaN will also result in NaN. The explanations on this /// page only explicitly document behavior on NaN operands if this default -/// is *not* observed by the operation. +/// is deviated from. /// - Lastly, there are multiple bit patterns that are considered NaN. /// Rust does not currently guarantee that the bit patterns of NaN are /// preserved over arithmetic operations, From 57eec0ce13951bdd124e5c896f82fa2b74b9d913 Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Thu, 31 Mar 2022 17:59:36 +0900 Subject: [PATCH 05/14] Re-introduce "propagating NaN" to `maximum`/`minimum`, add "ignoring NaN" to `max`/`min`, add disclaimer about the "propagation". --- library/core/src/num/f32.rs | 14 ++++++++++---- library/core/src/num/f64.rs | 14 ++++++++++---- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index b408b5d3d5de5..e3d40b58a3834 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -689,7 +689,7 @@ impl f32 { self * (value / 180.0f32) } - /// Returns the maximum of the two numbers. + /// Returns the maximum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs; @@ -709,7 +709,7 @@ impl f32 { intrinsics::maxnumf32(self, other) } - /// Returns the minimum of the two numbers. + /// Returns the minimum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs; @@ -729,7 +729,7 @@ impl f32 { intrinsics::minnumf32(self, other) } - /// Returns the maximum of the two numbers. + /// Returns the maximum of the two numbers, propagating NaN. /// /// This returns NaN when *either* argument is NaN, as opposed to /// [`f32::max`] which only returns NaN when *both* arguments are NaN. @@ -746,6 +746,9 @@ impl f32 { /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. /// Note that this follows the semantics specified in IEEE 754-2019. + /// + /// Also note that "propagation" of NaNs here doesn't mean that the bitpattern of a NaN operand + /// is necessarily conserved; see [explanation of NaN as a special value](f32) for more info. #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] @@ -761,7 +764,7 @@ impl f32 { } } - /// Returns the minimum of the two numbers. + /// Returns the minimum of the two numbers, propagating NaN. /// /// This returns NaN when *either* argument is NaN, as opposed to /// [`f32::min`] which only returns NaN when *both* arguments are NaN. @@ -778,6 +781,9 @@ impl f32 { /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. /// Note that this follows the semantics specified in IEEE 754-2019. + /// + /// Also note that "propagation" of NaNs here doesn't mean that the bitpattern of a NaN operand + /// is necessarily conserved; see [explanation of NaN as a special value](f32) for more info. #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index db39612265186..51ccf7e855475 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -705,7 +705,7 @@ impl f64 { self * (value / 180.0) } - /// Returns the maximum of the two numbers. + /// Returns the maximum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs; @@ -725,7 +725,7 @@ impl f64 { intrinsics::maxnumf64(self, other) } - /// Returns the minimum of the two numbers. + /// Returns the minimum of the two numbers, ignoring NaN. /// /// If one of the arguments is NaN, then the other argument is returned. /// This follows the IEEE-754 2008 semantics for minNum, except for handling of signaling NaNs; @@ -745,7 +745,7 @@ impl f64 { intrinsics::minnumf64(self, other) } - /// Returns the maximum of the two numbers. + /// Returns the maximum of the two numbers, propagating NaN. /// /// This returns NaN when *either* argument is NaN, as opposed to /// [`f64::max`] which only returns NaN when *both* arguments are NaN. @@ -762,6 +762,9 @@ impl f64 { /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. /// Note that this follows the semantics specified in IEEE 754-2019. + /// + /// Also note that "propagation" of NaNs here doesn't mean that the bitpattern of a NaN operand + /// is necessarily conserved; see [explanation of NaN as a special value](f32) for more info. #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] @@ -777,7 +780,7 @@ impl f64 { } } - /// Returns the minimum of the two numbers. + /// Returns the minimum of the two numbers, propagating NaN. /// /// This returns NaN when *either* argument is NaN, as opposed to /// [`f64::min`] which only returns NaN when *both* arguments are NaN. @@ -794,6 +797,9 @@ impl f64 { /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. /// Note that this follows the semantics specified in IEEE 754-2019. + /// + /// Also note that "propagation" of NaNs here doesn't mean that the bitpattern of a NaN operand + /// is necessarily conserved; see [explanation of NaN as a special value](f32) for more info. #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] From 21f1037c5846f1c796699dcbc2cdf38c663210e1 Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Thu, 31 Mar 2022 18:18:10 +0900 Subject: [PATCH 06/14] Further refine the disclaimer about NaN bit patterns. --- library/core/src/primitive_docs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index ab4bb0f26696b..ac4e668112b94 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -989,8 +989,9 @@ mod prim_tuple {} /// is deviated from. /// - Lastly, there are multiple bit patterns that are considered NaN. /// Rust does not currently guarantee that the bit patterns of NaN are -/// preserved over arithmetic operations, -/// so there may be some surprising results upon inspecting the bit patterns, +/// preserved over arithmetic operations, and they are not guaranteed to be +/// portable or even fully deterministic! This means that there may be some +/// surprising results upon inspecting the bit patterns, /// as the same calculations might produce NaNs with different bit patterns. /// /// For more information on floating point numbers, see [Wikipedia][wikipedia]. From 7175c499ecc32cb3ff713be0bbac9fd12990a34e Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Thu, 31 Mar 2022 18:50:14 +0900 Subject: [PATCH 07/14] match std f32 primitive docs to core f32 primitive docs --- library/std/src/primitive_docs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index ab4bb0f26696b..ac4e668112b94 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -989,8 +989,9 @@ mod prim_tuple {} /// is deviated from. /// - Lastly, there are multiple bit patterns that are considered NaN. /// Rust does not currently guarantee that the bit patterns of NaN are -/// preserved over arithmetic operations, -/// so there may be some surprising results upon inspecting the bit patterns, +/// preserved over arithmetic operations, and they are not guaranteed to be +/// portable or even fully deterministic! This means that there may be some +/// surprising results upon inspecting the bit patterns, /// as the same calculations might produce NaNs with different bit patterns. /// /// For more information on floating point numbers, see [Wikipedia][wikipedia]. From dea776512b07469092ee98e8c3d4543c6f377729 Mon Sep 17 00:00:00 2001 From: Pyry Kontio Date: Mon, 2 May 2022 23:29:02 +0900 Subject: [PATCH 08/14] Fix nits --- library/core/src/num/f32.rs | 8 ++++---- library/core/src/num/f64.rs | 8 ++++---- library/std/src/f32.rs | 2 +- library/std/src/f64.rs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index e3d40b58a3834..74d337f1dc05f 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -747,8 +747,8 @@ impl f32 { /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. /// Note that this follows the semantics specified in IEEE 754-2019. /// - /// Also note that "propagation" of NaNs here doesn't mean that the bitpattern of a NaN operand - /// is necessarily conserved; see [explanation of NaN as a special value](f32) for more info. + /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN + /// operand is conserved; see [explanation of NaN as a special value](f32) for more info. #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] @@ -782,8 +782,8 @@ impl f32 { /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. /// Note that this follows the semantics specified in IEEE 754-2019. /// - /// Also note that "propagation" of NaNs here doesn't mean that the bitpattern of a NaN operand - /// is necessarily conserved; see [explanation of NaN as a special value](f32) for more info. + /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN + /// operand is conserved; see [explanation of NaN as a special value](f32) for more info. #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 51ccf7e855475..c8ce6f0e3a82d 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -763,8 +763,8 @@ impl f64 { /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. /// Note that this follows the semantics specified in IEEE 754-2019. /// - /// Also note that "propagation" of NaNs here doesn't mean that the bitpattern of a NaN operand - /// is necessarily conserved; see [explanation of NaN as a special value](f32) for more info. + /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN + /// operand is conserved; see [explanation of NaN as a special value](f32) for more info. #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] @@ -798,8 +798,8 @@ impl f64 { /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0. /// Note that this follows the semantics specified in IEEE 754-2019. /// - /// Also note that "propagation" of NaNs here doesn't mean that the bitpattern of a NaN operand - /// is necessarily conserved; see [explanation of NaN as a special value](f32) for more info. + /// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN + /// operand is conserved; see [explanation of NaN as a special value](f32) for more info. #[must_use = "this returns the result of the comparison, without modifying either input"] #[unstable(feature = "float_minimum_maximum", issue = "91079")] #[inline] diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 469db1b7c2836..4cf234a527d56 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -302,7 +302,7 @@ impl f32 { /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf`. - /// It might have different sequence of rounding operations than `powf`, + /// It might have a different sequence of rounding operations than `powf`, /// so the results are not guaranteed to agree. /// /// # Examples diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index a291a777e5565..d28bd386c2a4c 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -302,7 +302,7 @@ impl f64 { /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf`. - /// It might have different sequence of rounding operations than `powf`, + /// It might have a different sequence of rounding operations than `powf`, /// so the results are not guaranteed to agree. /// /// # Examples From df446cb2afd1d968abe4ac47cb8cb4076730a4f0 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 8 May 2022 09:37:36 -0700 Subject: [PATCH 09/14] Revert "Implement [OsStr]::join", which was merged without FCP This reverts commit 4fcbc53820ab423bbeb41f07822369aa05da1d68. --- library/std/src/ffi/os_str.rs | 17 ----------------- library/std/src/ffi/os_str/tests.rs | 14 -------------- library/std/src/lib.rs | 2 -- 3 files changed, 33 deletions(-) diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index dd316bdb2c6ce..9b5e5d6c0cc4b 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -1222,23 +1222,6 @@ impl OsStr { } } -#[unstable(feature = "slice_concat_ext", issue = "27747")] -impl> alloc::slice::Join<&OsStr> for [S] { - type Output = OsString; - - fn join(slice: &Self, sep: &OsStr) -> OsString { - let Some(first) = slice.first() else { - return OsString::new(); - }; - let first = first.borrow().to_owned(); - slice[1..].iter().fold(first, |mut a, b| { - a.push(sep); - a.push(b.borrow()); - a - }) - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Borrow for OsString { #[inline] diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs index d7926749aae20..283f2b577e896 100644 --- a/library/std/src/ffi/os_str/tests.rs +++ b/library/std/src/ffi/os_str/tests.rs @@ -84,20 +84,6 @@ fn test_os_string_reserve_exact() { assert!(os_string.capacity() >= 33) } -#[test] -fn test_os_string_join() { - let strings = [OsStr::new("hello"), OsStr::new("dear"), OsStr::new("world")]; - assert_eq!("hello", strings[..1].join(OsStr::new(" "))); - assert_eq!("hello dear world", strings.join(OsStr::new(" "))); - assert_eq!("hellodearworld", strings.join(OsStr::new(""))); - assert_eq!("hello.\n dear.\n world", strings.join(OsStr::new(".\n "))); - - assert_eq!("dear world", strings[1..].join(&OsString::from(" "))); - - let strings_abc = [OsString::from("a"), OsString::from("b"), OsString::from("c")]; - assert_eq!("a b c", strings_abc.join(OsStr::new(" "))); -} - #[test] fn test_os_string_default() { let os_string: OsString = Default::default(); diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c394865d886e8..8ee50925f85f8 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -241,7 +241,6 @@ #![feature(intra_doc_pointers)] #![feature(lang_items)] #![feature(let_chains)] -#![feature(let_else)] #![feature(linkage)] #![feature(min_specialization)] #![feature(must_not_suspend)] @@ -302,7 +301,6 @@ #![feature(toowned_clone_into)] #![feature(try_reserve_kind)] #![feature(vec_into_raw_parts)] -#![feature(slice_concat_trait)] // // Library features (unwind): #![feature(panic_unwind)] From 84adf0d8dd5fa68050ef0f3684ab701f5fc5a4cf Mon Sep 17 00:00:00 2001 From: Badel2 <2badel2@gmail.com> Date: Sun, 8 May 2022 19:57:47 +0200 Subject: [PATCH 10/14] Actually fix ICE from #96583 PR #96746 fixed a very similar bug, so the same logic is used in a different place. --- compiler/rustc_typeck/src/check/expr.rs | 31 ++++++++++++++++--------- src/test/ui/typeck/issue-96738.rs | 1 + src/test/ui/typeck/issue-96738.stderr | 18 ++++++++++++-- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index a1e8d2040dd80..f3a5b9f13dd1b 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -44,7 +44,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::error::TypeError::{FieldMisMatch, Sorts}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable}; +use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TypeFoldable}; use rustc_session::parse::feature_err; use rustc_span::hygiene::DesugaringKind; use rustc_span::lev_distance::find_best_match_for_name; @@ -2034,17 +2034,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base: &'tcx hir::Expr<'tcx>, def_id: DefId, ) { - let local_id = def_id.expect_local(); - let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id); - let node = self.tcx.hir().get(hir_id); - - if let Some(fields) = node.tuple_fields() { - let kind = match self.tcx.opt_def_kind(local_id) { - Some(DefKind::Ctor(of, _)) => of, - _ => return, - }; + if let Some(local_id) = def_id.as_local() { + let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_id); + let node = self.tcx.hir().get(hir_id); + + if let Some(fields) = node.tuple_fields() { + let kind = match self.tcx.opt_def_kind(local_id) { + Some(DefKind::Ctor(of, _)) => of, + _ => return, + }; - suggest_call_constructor(base.span, kind, fields.len(), err); + suggest_call_constructor(base.span, kind, fields.len(), err); + } + } else { + // The logic here isn't smart but `associated_item_def_ids` + // doesn't work nicely on local. + if let DefKind::Ctor(of, _) = self.tcx.def_kind(def_id) { + let parent_def_id = self.tcx.parent(def_id); + let fields = self.tcx.associated_item_def_ids(parent_def_id); + suggest_call_constructor(base.span, of, fields.len(), err); + } } } diff --git a/src/test/ui/typeck/issue-96738.rs b/src/test/ui/typeck/issue-96738.rs index 7f1d1428eb9b4..ce2556f869c7c 100644 --- a/src/test/ui/typeck/issue-96738.rs +++ b/src/test/ui/typeck/issue-96738.rs @@ -1,3 +1,4 @@ fn main() { Some.nonexistent_method(); //~ ERROR: no method named `nonexistent_method` found + Some.nonexistent_field; //~ ERROR: no field `nonexistent_field` } diff --git a/src/test/ui/typeck/issue-96738.stderr b/src/test/ui/typeck/issue-96738.stderr index 58c83a36a3bdc..32f53849848c7 100644 --- a/src/test/ui/typeck/issue-96738.stderr +++ b/src/test/ui/typeck/issue-96738.stderr @@ -11,6 +11,20 @@ help: call the constructor LL | (Some)(_).nonexistent_method(); | + ++++ -error: aborting due to previous error +error[E0609]: no field `nonexistent_field` on type `fn(_) -> Option<_> {Option::<_>::Some}` + --> $DIR/issue-96738.rs:3:10 + | +LL | Some.nonexistent_field; + | ---- ^^^^^^^^^^^^^^^^^ + | | + | this is the constructor of an enum variant + | +help: call the constructor + | +LL | (Some)(_).nonexistent_field; + | + ++++ + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0599`. +Some errors have detailed explanations: E0599, E0609. +For more information about an error, try `rustc --explain E0599`. From 9d157ada35c0e363e30344526755649c3399f7de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 9 Apr 2022 17:19:33 +0200 Subject: [PATCH 11/14] Warn on unused doc(hidden) on trait impl items --- compiler/rustc_passes/src/check_attr.rs | 76 ++++++++++++++++++- .../alloc/src/collections/vec_deque/iter.rs | 1 - .../src/collections/vec_deque/iter_mut.rs | 1 - library/alloc/src/vec/into_iter.rs | 1 - library/core/src/convert/num.rs | 1 - library/core/src/iter/adapters/cloned.rs | 1 - library/core/src/iter/adapters/copied.rs | 1 - library/core/src/iter/adapters/enumerate.rs | 1 - library/core/src/iter/adapters/fuse.rs | 1 - library/core/src/iter/adapters/map.rs | 1 - library/core/src/iter/adapters/zip.rs | 1 - library/core/src/iter/range.rs | 1 - library/core/src/slice/iter.rs | 11 --- library/core/src/slice/iter/macros.rs | 1 - library/core/src/str/iter.rs | 1 - .../lint/unused/unused-attr-doc-hidden.fixed | 42 ++++++++++ .../ui/lint/unused/unused-attr-doc-hidden.rs | 42 ++++++++++ .../lint/unused/unused-attr-doc-hidden.stderr | 67 ++++++++++++++++ 18 files changed, 225 insertions(+), 26 deletions(-) create mode 100644 src/test/ui/lint/unused/unused-attr-doc-hidden.fixed create mode 100644 src/test/ui/lint/unused/unused-attr-doc-hidden.rs create mode 100644 src/test/ui/lint/unused/unused-attr-doc-hidden.stderr diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index b297012f19f2f..2b0fa57cba8b1 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -4,7 +4,8 @@ //! conflicts between multiple such attributes attached to the same //! item. -use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; +use rustc_ast::tokenstream::DelimSpan; +use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MacArgs, MetaItemKind, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; @@ -810,6 +811,68 @@ impl CheckAttrVisitor<'_> { } } + /// Checks `#[doc(hidden)]` attributes. Returns `true` if valid. + fn check_doc_hidden( + &self, + attr: &Attribute, + meta_index: usize, + meta: &NestedMetaItem, + hir_id: HirId, + target: Target, + ) -> bool { + if let Target::AssocConst + | Target::AssocTy + | Target::Method(MethodKind::Trait { body: true }) = target + { + let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); + let containing_item = self.tcx.hir().expect_item(parent_hir_id); + + if Target::from_item(containing_item) == Target::Impl { + let meta_items = attr.meta_item_list().unwrap(); + + let (span, replacement_span) = if meta_items.len() == 1 { + (attr.span, attr.span) + } else { + let meta_span = meta.span(); + ( + meta_span, + meta_span.until(match meta_items.get(meta_index + 1) { + Some(next_item) => next_item.span(), + None => match attr.get_normal_item().args { + MacArgs::Delimited(DelimSpan { close, .. }, ..) => close, + _ => unreachable!(), + }, + }), + ) + }; + + // FIXME: #[doc(hidden)] was previously erroneously allowed on trait impl items, + // so for backward compatibility only emit a warning and do not mark it as invalid. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| { + lint.build("`#[doc(hidden)]` is ignored on trait impl items") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .note( + "whether the impl item is `doc(hidden)` or not \ + entirely depends on the corresponding trait item", + ) + .span_suggestion( + replacement_span, + "remove this attribute", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + }); + } + } + + true + } + /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid. fn check_attr_not_crate_level( &self, @@ -928,7 +991,7 @@ impl CheckAttrVisitor<'_> { let mut is_valid = true; if let Some(mi) = attr.meta() && let Some(list) = mi.meta_item_list() { - for meta in list { + for (meta_index, meta) in list.into_iter().enumerate() { if let Some(i_meta) = meta.meta_item() { match i_meta.name_or_empty() { sym::alias @@ -969,6 +1032,15 @@ impl CheckAttrVisitor<'_> { is_valid = false; } + sym::hidden if !self.check_doc_hidden(attr, + meta_index, + meta, + hir_id, + target, + ) => { + is_valid = false; + } + // no_default_passes: deprecated // passes: deprecated // plugins: removed, but rustdoc warns about it itself diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index e8290809276fb..19198ab3aa1b5 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -122,7 +122,6 @@ impl<'a, T> Iterator for Iter<'a, T> { } #[inline] - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { // Safety: The TrustedRandomAccess contract requires that callers only pass an index // that is in bounds. diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs index ee2df0d516012..b78c0d5e1b3cf 100644 --- a/library/alloc/src/collections/vec_deque/iter_mut.rs +++ b/library/alloc/src/collections/vec_deque/iter_mut.rs @@ -100,7 +100,6 @@ impl<'a, T> Iterator for IterMut<'a, T> { } #[inline] - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { // Safety: The TrustedRandomAccess contract requires that callers only pass an index // that is in bounds. diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 8134eea570ad7..a7df6f59b5989 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -202,7 +202,6 @@ impl Iterator for IntoIter { self.len() } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item where Self: TrustedRandomAccessNoCoerce, diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 2b6ea90bf0430..4fa5d129bc6af 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -25,7 +25,6 @@ macro_rules! impl_float_to_int { $( #[unstable(feature = "convert_float_to_int", issue = "67057")] impl FloatToInt<$Int> for $Float { - #[doc(hidden)] #[inline] unsafe fn to_int_unchecked(self) -> $Int { // SAFETY: the safety contract must be upheld by the caller. diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index 71a5a4ea831ff..aba24a79dcf79 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -60,7 +60,6 @@ where self.it.map(T::clone).fold(init, f) } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where Self: TrustedRandomAccessNoCoerce, diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index e5f2886dcafad..f9bfd77d7fbbf 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -81,7 +81,6 @@ where self.it.advance_by(n) } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where Self: TrustedRandomAccessNoCoerce, diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 10b4db84b3904..14a126951115c 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -128,7 +128,6 @@ where } #[rustc_inherit_overflow_checks] - #[doc(hidden)] #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> ::Item where diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index fbf752c6f2024..8adb53c671428 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -129,7 +129,6 @@ where } #[inline] - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where Self: TrustedRandomAccessNoCoerce, diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 6cbb35dc7c629..9e25dbe462c91 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -124,7 +124,6 @@ where self.iter.fold(init, map_fold(self.f, g)) } - #[doc(hidden)] #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> B where diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index de44bd66501e2..8153c8cfef133 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -95,7 +95,6 @@ where } #[inline] - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where Self: TrustedRandomAccessNoCoerce, diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 0ae94c05da658..f7aeee8c9adc6 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -752,7 +752,6 @@ impl Iterator for ops::Range { } #[inline] - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item where Self: TrustedRandomAccessNoCoerce, diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 98dd1521d0e85..772a9698d84cc 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1322,7 +1322,6 @@ impl<'a, T> Iterator for Windows<'a, T> { } } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { // SAFETY: since the caller guarantees that `i` is in bounds, // which means that `i` cannot overflow an `isize`, and the @@ -1478,7 +1477,6 @@ impl<'a, T> Iterator for Chunks<'a, T> { } } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; // SAFETY: the caller guarantees that `i` is in bounds, @@ -1657,7 +1655,6 @@ impl<'a, T> Iterator for ChunksMut<'a, T> { } } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; // SAFETY: see comments for `Chunks::__iterator_get_unchecked`. @@ -1830,7 +1827,6 @@ impl<'a, T> Iterator for ChunksExact<'a, T> { self.next_back() } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`. @@ -1984,7 +1980,6 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> { self.next_back() } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let start = idx * self.chunk_size; // SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`. @@ -2248,7 +2243,6 @@ impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> { self.iter.last() } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] { // SAFETY: The safety guarantees of `__iterator_get_unchecked` are // transferred to the caller. @@ -2367,7 +2361,6 @@ impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> { self.iter.last() } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a mut [T; N] { // SAFETY: The safety guarantees of `__iterator_get_unchecked` are transferred to // the caller. @@ -2520,7 +2513,6 @@ impl<'a, T> Iterator for RChunks<'a, T> { } } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; let start = match end.checked_sub(self.chunk_size) { @@ -2689,7 +2681,6 @@ impl<'a, T> Iterator for RChunksMut<'a, T> { } } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; let start = match end.checked_sub(self.chunk_size) { @@ -2856,7 +2847,6 @@ impl<'a, T> Iterator for RChunksExact<'a, T> { self.next_back() } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; let start = end - self.chunk_size; @@ -3016,7 +3006,6 @@ impl<'a, T> Iterator for RChunksExactMut<'a, T> { self.next_back() } - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { let end = self.v.len() - idx * self.chunk_size; let start = end - self.chunk_size; diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 78bf3381b4d26..c05242222dde7 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -325,7 +325,6 @@ macro_rules! iterator { None } - #[doc(hidden)] #[inline] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { // SAFETY: the caller must guarantee that `i` is in bounds of diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index e529bccbc7999..f46acc11f2dd3 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -298,7 +298,6 @@ impl Iterator for Bytes<'_> { } #[inline] - #[doc(hidden)] unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 { // SAFETY: the caller must uphold the safety contract // for `Iterator::__iterator_get_unchecked`. diff --git a/src/test/ui/lint/unused/unused-attr-doc-hidden.fixed b/src/test/ui/lint/unused/unused-attr-doc-hidden.fixed new file mode 100644 index 0000000000000..36a14097ac308 --- /dev/null +++ b/src/test/ui/lint/unused/unused-attr-doc-hidden.fixed @@ -0,0 +1,42 @@ +#![deny(unused_attributes)] +#![crate_type = "lib"] +// run-rustfix + +pub trait Trait { + type It; + const IT: (); + fn it0(); + fn it1(); + fn it2(); +} + +pub struct Implementor; + +impl Trait for Implementor { + + type It = (); + //~^^ ERROR `#[doc(hidden)]` is ignored + //~| WARNING this was previously accepted + + + const IT: () = (); + //~^^ ERROR `#[doc(hidden)]` is ignored + //~| WARNING this was previously accepted + + #[doc(alias = "aka")] + fn it0() {} + //~^^ ERROR `#[doc(hidden)]` is ignored + //~| WARNING this was previously accepted + + #[doc(alias = "this", )] + fn it1() {} + //~^^ ERROR `#[doc(hidden)]` is ignored + //~| WARNING this was previously accepted + + #[doc()] + fn it2() {} + //~^^ ERROR `#[doc(hidden)]` is ignored + //~| WARNING this was previously accepted + //~| ERROR `#[doc(hidden)]` is ignored + //~| WARNING this was previously accepted +} diff --git a/src/test/ui/lint/unused/unused-attr-doc-hidden.rs b/src/test/ui/lint/unused/unused-attr-doc-hidden.rs new file mode 100644 index 0000000000000..e58c4f22f31ab --- /dev/null +++ b/src/test/ui/lint/unused/unused-attr-doc-hidden.rs @@ -0,0 +1,42 @@ +#![deny(unused_attributes)] +#![crate_type = "lib"] +// run-rustfix + +pub trait Trait { + type It; + const IT: (); + fn it0(); + fn it1(); + fn it2(); +} + +pub struct Implementor; + +impl Trait for Implementor { + #[doc(hidden)] + type It = (); + //~^^ ERROR `#[doc(hidden)]` is ignored + //~| WARNING this was previously accepted + + #[doc(hidden)] + const IT: () = (); + //~^^ ERROR `#[doc(hidden)]` is ignored + //~| WARNING this was previously accepted + + #[doc(hidden, alias = "aka")] + fn it0() {} + //~^^ ERROR `#[doc(hidden)]` is ignored + //~| WARNING this was previously accepted + + #[doc(alias = "this", hidden,)] + fn it1() {} + //~^^ ERROR `#[doc(hidden)]` is ignored + //~| WARNING this was previously accepted + + #[doc(hidden, hidden)] + fn it2() {} + //~^^ ERROR `#[doc(hidden)]` is ignored + //~| WARNING this was previously accepted + //~| ERROR `#[doc(hidden)]` is ignored + //~| WARNING this was previously accepted +} diff --git a/src/test/ui/lint/unused/unused-attr-doc-hidden.stderr b/src/test/ui/lint/unused/unused-attr-doc-hidden.stderr new file mode 100644 index 0000000000000..fd1202a29de2e --- /dev/null +++ b/src/test/ui/lint/unused/unused-attr-doc-hidden.stderr @@ -0,0 +1,67 @@ +error: `#[doc(hidden)]` is ignored on trait impl items + --> $DIR/unused-attr-doc-hidden.rs:16:5 + | +LL | #[doc(hidden)] + | ^^^^^^^^^^^^^^ help: remove this attribute + | +note: the lint level is defined here + --> $DIR/unused-attr-doc-hidden.rs:1:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item + +error: `#[doc(hidden)]` is ignored on trait impl items + --> $DIR/unused-attr-doc-hidden.rs:21:5 + | +LL | #[doc(hidden)] + | ^^^^^^^^^^^^^^ help: remove this attribute + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item + +error: `#[doc(hidden)]` is ignored on trait impl items + --> $DIR/unused-attr-doc-hidden.rs:26:11 + | +LL | #[doc(hidden, alias = "aka")] + | ^^^^^^-- + | | + | help: remove this attribute + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item + +error: `#[doc(hidden)]` is ignored on trait impl items + --> $DIR/unused-attr-doc-hidden.rs:31:27 + | +LL | #[doc(alias = "this", hidden,)] + | ^^^^^^- + | | + | help: remove this attribute + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item + +error: `#[doc(hidden)]` is ignored on trait impl items + --> $DIR/unused-attr-doc-hidden.rs:36:11 + | +LL | #[doc(hidden, hidden)] + | ^^^^^^-- + | | + | help: remove this attribute + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item + +error: `#[doc(hidden)]` is ignored on trait impl items + --> $DIR/unused-attr-doc-hidden.rs:36:19 + | +LL | #[doc(hidden, hidden)] + | ^^^^^^ help: remove this attribute + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: whether the impl item is `doc(hidden)` or not entirely depends on the corresponding trait item + +error: aborting due to 6 previous errors + From e14eae6226847f2940e8158cb83253ecebbdc61c Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 8 May 2022 21:34:36 -0400 Subject: [PATCH 12/14] Remove subst_spanned --- compiler/rustc_middle/src/ty/subst.rs | 48 ++++--------------- compiler/rustc_typeck/src/astconv/mod.rs | 10 +--- .../rustc_typeck/src/check/fn_ctxt/_impl.rs | 9 +--- 3 files changed, 14 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 5063420e975d1..5b1fb70872988 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -10,7 +10,7 @@ use rustc_data_structures::intern::{Interned, WithStableHash}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; use rustc_serialize::{self, Decodable, Encodable}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::DUMMY_SP; use smallvec::SmallVec; use core::intrinsics; @@ -498,34 +498,14 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } } -/////////////////////////////////////////////////////////////////////////// -// Public trait `Subst` -// -// Just call `foo.subst(tcx, substs)` to perform a substitution across -// `foo`. Or use `foo.subst_spanned(tcx, substs, Some(span))` when -// there is more information available (for better errors). - +// Just call `foo.subst(tcx, substs)` to perform a substitution across `foo`. pub trait Subst<'tcx>: Sized { - fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self { - self.subst_spanned(tcx, substs, None) - } - - fn subst_spanned( - self, - tcx: TyCtxt<'tcx>, - substs: &[GenericArg<'tcx>], - span: Option, - ) -> Self; + fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> Self; } impl<'tcx, T: TypeFoldable<'tcx>> Subst<'tcx> for T { - fn subst_spanned( - self, - tcx: TyCtxt<'tcx>, - substs: &[GenericArg<'tcx>], - span: Option, - ) -> T { - let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 }; + fn subst(self, tcx: TyCtxt<'tcx>, substs: &[GenericArg<'tcx>]) -> T { + let mut folder = SubstFolder { tcx, substs, binders_passed: 0 }; self.fold_with(&mut folder) } } @@ -537,9 +517,6 @@ struct SubstFolder<'a, 'tcx> { tcx: TyCtxt<'tcx>, substs: &'a [GenericArg<'tcx>], - /// The location for which the substitution is performed, if available. - span: Option, - /// Number of region binders we have passed through while doing the substitution binders_passed: u32, } @@ -571,13 +548,12 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { match rk { Some(GenericArgKind::Lifetime(lt)) => self.shift_region_through_binders(lt), _ => { - let span = self.span.unwrap_or(DUMMY_SP); let msg = format!( "Region parameter out of range \ when substituting in region {} (index={})", data.name, data.index ); - span_bug!(span, "{}", msg); + span_bug!(DUMMY_SP, "{}", msg); } } } @@ -617,9 +593,8 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { let ty = match opt_ty { Some(GenericArgKind::Type(ty)) => ty, Some(kind) => { - let span = self.span.unwrap_or(DUMMY_SP); span_bug!( - span, + DUMMY_SP, "expected type for `{:?}` ({:?}/{}) but found {:?} \ when substituting, substs={:?}", p, @@ -630,9 +605,8 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { ); } None => { - let span = self.span.unwrap_or(DUMMY_SP); span_bug!( - span, + DUMMY_SP, "type parameter `{:?}` ({:?}/{}) out of range \ when substituting, substs={:?}", p, @@ -652,9 +626,8 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { let ct = match opt_ct { Some(GenericArgKind::Const(ct)) => ct, Some(kind) => { - let span = self.span.unwrap_or(DUMMY_SP); span_bug!( - span, + DUMMY_SP, "expected const for `{:?}` ({:?}/{}) but found {:?} \ when substituting substs={:?}", p, @@ -665,9 +638,8 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { ); } None => { - let span = self.span.unwrap_or(DUMMY_SP); span_bug!( - span, + DUMMY_SP, "const parameter `{:?}` ({:?}/{}) out of range \ when substituting substs={:?}", p, diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 93f6b4a6b5aa8..3c1676b1aac67 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -523,11 +523,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.astconv .normalize_ty( self.span, - tcx.at(self.span).type_of(param.def_id).subst_spanned( - tcx, - substs, - Some(self.span), - ), + tcx.at(self.span).type_of(param.def_id).subst(tcx, substs), ) .into() } @@ -547,9 +543,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericParamDefKind::Const { has_default } => { let ty = tcx.at(self.span).type_of(param.def_id); if !infer_args && has_default { - tcx.const_param_default(param.def_id) - .subst_spanned(tcx, substs.unwrap(), Some(self.span)) - .into() + tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into() } else { if infer_args { self.astconv.ct_infer(ty, Some(param), self.span).into() diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 93b0edb84c054..d824c1d7cf252 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1403,10 +1403,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // is missing. let default = tcx.type_of(param.def_id); self.fcx - .normalize_ty( - self.span, - default.subst_spanned(tcx, substs.unwrap(), Some(self.span)), - ) + .normalize_ty(self.span, default.subst(tcx, substs.unwrap())) .into() } else { // If no type arguments were provided, we have to infer them. @@ -1418,9 +1415,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } GenericParamDefKind::Const { has_default } => { if !infer_args && has_default { - tcx.const_param_default(param.def_id) - .subst_spanned(tcx, substs.unwrap(), Some(self.span)) - .into() + tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into() } else { self.fcx.var_for_def(self.span, param) } From 657499df644c15546c3c9fd0635d4886d47e6cdf Mon Sep 17 00:00:00 2001 From: Jack Huey <31162821+jackh726@users.noreply.github.com> Date: Sun, 8 May 2022 21:49:12 -0400 Subject: [PATCH 13/14] Reorder erasing/replacing late bound vars and substs --- .../rustc_typeck/src/check/method/confirm.rs | 16 +++++----------- compiler/rustc_typeck/src/check/method/mod.rs | 2 +- compiler/rustc_typeck/src/check/method/probe.rs | 14 ++++++-------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index bc0fa9165561d..1b619776b857c 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -462,19 +462,13 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let sig = self.tcx.fn_sig(def_id); - // Instantiate late-bound regions and substitute the trait - // parameters into the method type to get the actual method type. - // - // N.B., instantiate late-bound regions first so that - // `instantiate_type_scheme` can normalize associated types that - // may reference those regions. - let method_sig = self.replace_bound_vars_with_fresh_vars(sig); - debug!("late-bound lifetimes from method instantiated, method_sig={:?}", method_sig); + let sig = sig.subst(self.tcx, all_substs); + debug!("type scheme substituted, sig={:?}", sig); - let method_sig = method_sig.subst(self.tcx, all_substs); - debug!("type scheme substituted, method_sig={:?}", method_sig); + let sig = self.replace_bound_vars_with_fresh_vars(sig); + debug!("late-bound lifetimes from method instantiated, sig={:?}", sig); - (method_sig, method_predicates) + (sig, method_predicates) } fn add_obligations( diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 8137d70292182..1dd5e45fdc174 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -461,8 +461,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `instantiate_type_scheme` can normalize associated types that // may reference those regions. let fn_sig = tcx.fn_sig(def_id); - let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0; let fn_sig = fn_sig.subst(self.tcx, substs); + let fn_sig = self.replace_bound_vars_with_fresh_vars(span, infer::FnCall, fn_sig).0; let InferOk { value, obligations: o } = if is_op { self.normalize_op_associated_types_in_as_infer_ok(span, fn_sig, opt_input_expr) diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index c7d0f61c601a8..c28ab9fa1ee40 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -1784,12 +1784,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let generics = self.tcx.generics_of(method); assert_eq!(substs.len(), generics.parent_count as usize); - // Erase any late-bound regions from the method and substitute - // in the values from the substitution. - let xform_fn_sig = self.erase_late_bound_regions(fn_sig); - - if generics.params.is_empty() { - xform_fn_sig.subst(self.tcx, substs) + let xform_fn_sig = if generics.params.is_empty() { + fn_sig.subst(self.tcx, substs) } else { let substs = InternalSubsts::for_item(self.tcx, method, |param, _| { let i = param.index as usize; @@ -1807,8 +1803,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } }); - xform_fn_sig.subst(self.tcx, substs) - } + fn_sig.subst(self.tcx, substs) + }; + + self.erase_late_bound_regions(xform_fn_sig) } /// Gets the type of an impl and generate substitutions with placeholders. From 521d2c3d3cc4814586aa13c74197f0894c021abc Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 8 May 2022 22:19:40 -0700 Subject: [PATCH 14/14] Remove unused param from search.js::checkPath --- src/librustdoc/html/static/js/search.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 1e3894c1fcd27..677e9b5f03ab2 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1089,7 +1089,7 @@ window.initSearch = rawSearchIndex => { return parsedQuery.literalSearch ? MAX_LEV_DISTANCE + 1 : lev; } - function checkPath(contains, lastElem, ty) { + function checkPath(contains, ty) { if (contains.length === 0) { return 0; } @@ -1306,7 +1306,7 @@ window.initSearch = rawSearchIndex => { } if (elem.fullPath.length > 1) { - lev = checkPath(elem.pathWithoutLast, elem.pathLast, row); + lev = checkPath(elem.pathWithoutLast, row); if (lev > MAX_LEV_DISTANCE || (parsedQuery.literalSearch && lev !== 0)) { return; } else if (lev > 0) {