From a4d969b30e5422f0787492b67283aa389f858187 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 18 Feb 2024 12:32:36 +0100 Subject: [PATCH 01/12] Refactor trait implementations in `core::convert::num`. --- library/core/src/convert/num.rs | 692 +++++++++++++++----------------- 1 file changed, 325 insertions(+), 367 deletions(-) diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 08dc8f48dfedc..46a9006c14665 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -19,7 +19,7 @@ pub trait FloatToInt: private::Sealed + Sized { } macro_rules! impl_float_to_int { - ( $Float: ident => $( $Int: ident )+ ) => { + ($Float:ty => $($Int:ty),+) => { #[unstable(feature = "convert_float_to_int", issue = "67057")] impl private::Sealed for $Float {} $( @@ -35,14 +35,38 @@ macro_rules! impl_float_to_int { } } -impl_float_to_int!(f32 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); -impl_float_to_int!(f64 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); +impl_float_to_int!(f32 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); +impl_float_to_int!(f64 => u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); // Conversion traits for primitive integer and float types // Conversions T -> T are covered by a blanket impl and therefore excluded // Some conversions from and to usize/isize are not implemented due to portability concerns macro_rules! impl_from { - ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { + (bool => $Int:ty $(,)?) => { + impl_from!( + bool => $Int, + #[stable(feature = "from_bool", since = "1.28.0")], + concat!( + "Converts a [`bool`] to [`", stringify!($Int), "`] losslessly.\n", + "The resulting value is `0` for `false` and `1` for `true` values.\n", + "\n", + "# Examples\n", + "\n", + "```\n", + "assert_eq!(", stringify!($Int), "::from(true), 1);\n", + "assert_eq!(", stringify!($Int), "::from(false), 0);\n", + "```\n", + ), + ); + }; + ($Small:ty => $Large:ty, #[$attr:meta] $(,)?) => { + impl_from!( + $Small => $Large, + #[$attr], + concat!("Converts [`", stringify!($Small), "`] to [`", stringify!($Large), "`] losslessly."), + ); + }; + ($Small:ty => $Large:ty, #[$attr:meta], $doc:expr $(,)?) => { #[$attr] impl From<$Small> for $Large { // Rustdocs on the impl block show a "[+] show undocumented items" toggle. @@ -54,91 +78,66 @@ macro_rules! impl_from { } } }; - ($Small: ty, $Large: ty, #[$attr:meta]) => { - impl_from!($Small, - $Large, - #[$attr], - concat!("Converts `", - stringify!($Small), - "` to `", - stringify!($Large), - "` losslessly.")); - } } -macro_rules! impl_from_bool { - ($target: ty, #[$attr:meta]) => { - impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `", - stringify!($target), "`. The resulting value is `0` for `false` and `1` for `true` -values. - -# Examples - -``` -assert_eq!(", stringify!($target), "::from(true), 1); -assert_eq!(", stringify!($target), "::from(false), 0); -```")); - }; -} - -// Bool -> Any -impl_from_bool! { u8, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { u16, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { u32, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { u64, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { u128, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { usize, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i8, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i16, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i32, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i64, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] } -impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] } - -// Unsigned -> Unsigned -impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, u128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u8, usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, u128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u32, u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u32, u128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u64, u128, #[stable(feature = "i128", since = "1.26.0")] } - -// Signed -> Signed -impl_from! { i8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i8, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { i8, isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i16, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { i32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { i32, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { i64, i128, #[stable(feature = "i128", since = "1.26.0")] } - -// Unsigned -> Signed -impl_from! { u8, i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u8, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u16, i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u16, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u32, i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } -impl_from! { u32, i128, #[stable(feature = "i128", since = "1.26.0")] } -impl_from! { u64, i128, #[stable(feature = "i128", since = "1.26.0")] } +// boolean -> integer +impl_from!(bool => u8); +impl_from!(bool => u16); +impl_from!(bool => u32); +impl_from!(bool => u64); +impl_from!(bool => u128); +impl_from!(bool => usize); +impl_from!(bool => i8); +impl_from!(bool => i16); +impl_from!(bool => i32); +impl_from!(bool => i64); +impl_from!(bool => i128); +impl_from!(bool => isize); + +// unsigned integer -> unsigned integer +impl_from!(u8 => u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u8 => u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u8 => u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u8 => u128, #[stable(feature = "i128", since = "1.26.0")]); +impl_from!(u8 => usize, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u16 => u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u16 => u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u16 => u128, #[stable(feature = "i128", since = "1.26.0")]); +impl_from!(u32 => u64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u32 => u128, #[stable(feature = "i128", since = "1.26.0")]); +impl_from!(u64 => u128, #[stable(feature = "i128", since = "1.26.0")]); + +// signed integer -> signed integer +impl_from!(i8 => i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(i8 => i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(i8 => i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(i8 => i128, #[stable(feature = "i128", since = "1.26.0")]); +impl_from!(i8 => isize, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(i16 => i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(i16 => i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(i16 => i128, #[stable(feature = "i128", since = "1.26.0")]); +impl_from!(i32 => i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(i32 => i128, #[stable(feature = "i128", since = "1.26.0")]); +impl_from!(i64 => i128, #[stable(feature = "i128", since = "1.26.0")]); + +// unsigned integer -> signed integer +impl_from!(u8 => i16, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u8 => i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u8 => i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u8 => i128, #[stable(feature = "i128", since = "1.26.0")]); +impl_from!(u16 => i32, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u16 => i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u16 => i128, #[stable(feature = "i128", since = "1.26.0")]); +impl_from!(u32 => i64, #[stable(feature = "lossless_int_conv", since = "1.5.0")]); +impl_from!(u32 => i128, #[stable(feature = "i128", since = "1.26.0")]); +impl_from!(u64 => i128, #[stable(feature = "i128", since = "1.26.0")]); // The C99 standard defines bounds on INTPTR_MIN, INTPTR_MAX, and UINTPTR_MAX // which imply that pointer-sized integers must be at least 16 bits: // https://port70.net/~nsz/c/c99/n1256.html#7.18.2.4 -impl_from! { u16, usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } -impl_from! { u8, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } -impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")] } +impl_from!(u16 => usize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")]); +impl_from!(u8 => isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")]); +impl_from!(i16 => isize, #[stable(feature = "lossless_iusize_conv", since = "1.26.0")]); // RISC-V defines the possibility of a 128-bit address space (RV128). @@ -150,66 +149,54 @@ impl_from! { i16, isize, #[stable(feature = "lossless_iusize_conv", since = "1.2 // they fit in the significand, which is 24 bits in f32 and 53 bits in f64. // Lossy float conversions are not implemented at this time. -// Signed -> Float -impl_from! { i8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { i8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { i16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { i16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { i32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } - -// Unsigned -> Float -impl_from! { u8, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { u8, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { u16, f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { u16, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } -impl_from! { u32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } - -// Float -> Float -impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")] } - -// bool -> Float -#[stable(feature = "float_from_bool", since = "1.68.0")] -impl From for f32 { - /// Converts `bool` to `f32` losslessly. The resulting value is positive - /// `0.0` for `false` and `1.0` for `true` values. - /// - /// # Examples - /// ``` - /// let x: f32 = false.into(); - /// assert_eq!(x, 0.0); - /// assert!(x.is_sign_positive()); - /// - /// let y: f32 = true.into(); - /// assert_eq!(y, 1.0); - /// ``` - #[inline] - fn from(small: bool) -> Self { - small as u8 as Self - } -} -#[stable(feature = "float_from_bool", since = "1.68.0")] -impl From for f64 { - /// Converts `bool` to `f64` losslessly. The resulting value is positive - /// `0.0` for `false` and `1.0` for `true` values. - /// - /// # Examples - /// ``` - /// let x: f64 = false.into(); - /// assert_eq!(x, 0.0); - /// assert!(x.is_sign_positive()); - /// - /// let y: f64 = true.into(); - /// assert_eq!(y, 1.0); - /// ``` - #[inline] - fn from(small: bool) -> Self { - small as u8 as Self - } +// signed integer -> float +impl_from!(i8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(i32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); + +// unsigned integer -> float +impl_from!(u8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); +impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); + +// float -> float +impl_from!(f32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); + +macro_rules! impl_float_from_bool { + ($float:ty) => { + #[stable(feature = "float_from_bool", since = "1.68.0")] + impl From for $float { + #[doc = concat!("Converts a [`bool`] to [`", stringify!($float),"`] losslessly.")] + /// The resulting value is positive `0.0` for `false` and `1.0` for `true` values. + /// + /// # Examples + /// ``` + #[doc = concat!("let x: ", stringify!($float)," = false.into();")] + /// assert_eq!(x, 0.0); + /// assert!(x.is_sign_positive()); + /// + #[doc = concat!("let y: ", stringify!($float)," = true.into();")] + /// assert_eq!(y, 1.0); + /// ``` + #[inline] + fn from(small: bool) -> Self { + small as u8 as Self + } + } + }; } +// boolean -> float +impl_float_from_bool!(f32); +impl_float_from_bool!(f64); + // no possible bounds violation -macro_rules! try_from_unbounded { - ($source:ty, $($target:ty),*) => {$( +macro_rules! impl_try_from_unbounded { + ($source:ty => $($target:ty),+) => {$( #[stable(feature = "try_from", since = "1.34.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -226,8 +213,8 @@ macro_rules! try_from_unbounded { } // only negative bounds -macro_rules! try_from_lower_bounded { - ($source:ty, $($target:ty),*) => {$( +macro_rules! impl_try_from_lower_bounded { + ($source:ty => $($target:ty),+) => {$( #[stable(feature = "try_from", since = "1.34.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -248,8 +235,8 @@ macro_rules! try_from_lower_bounded { } // unsigned to signed (only positive bound) -macro_rules! try_from_upper_bounded { - ($source:ty, $($target:ty),*) => {$( +macro_rules! impl_try_from_upper_bounded { + ($source:ty => $($target:ty),+) => {$( #[stable(feature = "try_from", since = "1.34.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -270,8 +257,8 @@ macro_rules! try_from_upper_bounded { } // all other cases -macro_rules! try_from_both_bounded { - ($source:ty, $($target:ty),*) => {$( +macro_rules! impl_try_from_both_bounded { + ($source:ty => $($target:ty),+) => {$( #[stable(feature = "try_from", since = "1.34.0")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -294,65 +281,66 @@ macro_rules! try_from_both_bounded { } macro_rules! rev { - ($mac:ident, $source:ty, $($target:ty),*) => {$( - $mac!($target, $source); + ($mac:ident, $source:ty => $($target:ty),+) => {$( + $mac!($target => $source); )*} } -// intra-sign conversions -try_from_upper_bounded!(u16, u8); -try_from_upper_bounded!(u32, u16, u8); -try_from_upper_bounded!(u64, u32, u16, u8); -try_from_upper_bounded!(u128, u64, u32, u16, u8); - -try_from_both_bounded!(i16, i8); -try_from_both_bounded!(i32, i16, i8); -try_from_both_bounded!(i64, i32, i16, i8); -try_from_both_bounded!(i128, i64, i32, i16, i8); - -// unsigned-to-signed -try_from_upper_bounded!(u8, i8); -try_from_upper_bounded!(u16, i8, i16); -try_from_upper_bounded!(u32, i8, i16, i32); -try_from_upper_bounded!(u64, i8, i16, i32, i64); -try_from_upper_bounded!(u128, i8, i16, i32, i64, i128); - -// signed-to-unsigned -try_from_lower_bounded!(i8, u8, u16, u32, u64, u128); -try_from_lower_bounded!(i16, u16, u32, u64, u128); -try_from_lower_bounded!(i32, u32, u64, u128); -try_from_lower_bounded!(i64, u64, u128); -try_from_lower_bounded!(i128, u128); -try_from_both_bounded!(i16, u8); -try_from_both_bounded!(i32, u16, u8); -try_from_both_bounded!(i64, u32, u16, u8); -try_from_both_bounded!(i128, u64, u32, u16, u8); +// unsigned integer -> unsigned integer +impl_try_from_upper_bounded!(u16 => u8); +impl_try_from_upper_bounded!(u32 => u8, u16); +impl_try_from_upper_bounded!(u64 => u8, u16, u32); +impl_try_from_upper_bounded!(u128 => u8, u16, u32, u64); + +// signed integer -> signed integer +impl_try_from_both_bounded!(i16 => i8); +impl_try_from_both_bounded!(i32 => i8, i16); +impl_try_from_both_bounded!(i64 => i8, i16, i32); +impl_try_from_both_bounded!(i128 => i8, i16, i32, i64); + +// unsigned integer -> signed integer +impl_try_from_upper_bounded!(u8 => i8); +impl_try_from_upper_bounded!(u16 => i8, i16); +impl_try_from_upper_bounded!(u32 => i8, i16, i32); +impl_try_from_upper_bounded!(u64 => i8, i16, i32, i64); +impl_try_from_upper_bounded!(u128 => i8, i16, i32, i64, i128); + +// signed integer -> unsigned integer +impl_try_from_lower_bounded!(i8 => u8, u16, u32, u64, u128); +impl_try_from_both_bounded!(i16 => u8); +impl_try_from_lower_bounded!(i16 => u16, u32, u64, u128); +impl_try_from_both_bounded!(i32 => u8, u16); +impl_try_from_lower_bounded!(i32 => u32, u64, u128); +impl_try_from_both_bounded!(i64 => u8, u16, u32); +impl_try_from_lower_bounded!(i64 => u64, u128); +impl_try_from_both_bounded!(i128 => u8, u16, u32, u64); +impl_try_from_lower_bounded!(i128 => u128); // usize/isize -try_from_upper_bounded!(usize, isize); -try_from_lower_bounded!(isize, usize); +impl_try_from_upper_bounded!(usize => isize); +impl_try_from_lower_bounded!(isize => usize); #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { use super::TryFromIntError; use crate::convert::TryFrom; - try_from_upper_bounded!(usize, u8); - try_from_unbounded!(usize, u16, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16); - try_from_unbounded!(usize, i32, i64, i128); + impl_try_from_upper_bounded!(usize => u8); + impl_try_from_unbounded!(usize => u16, u32, u64, u128); + impl_try_from_upper_bounded!(usize => i8, i16); + impl_try_from_unbounded!(usize => i32, i64, i128); - try_from_both_bounded!(isize, u8); - try_from_lower_bounded!(isize, u16, u32, u64, u128); - try_from_both_bounded!(isize, i8); - try_from_unbounded!(isize, i16, i32, i64, i128); + impl_try_from_both_bounded!(isize => u8); + impl_try_from_lower_bounded!(isize => u16, u32, u64, u128); + impl_try_from_both_bounded!(isize => i8); + impl_try_from_unbounded!(isize => i16, i32, i64, i128); - rev!(try_from_upper_bounded, usize, u32, u64, u128); - rev!(try_from_lower_bounded, usize, i8, i16); - rev!(try_from_both_bounded, usize, i32, i64, i128); + rev!(impl_try_from_upper_bounded, usize => u32, u64, u128); + rev!(impl_try_from_lower_bounded, usize => i8, i16); + rev!(impl_try_from_both_bounded, usize => i32, i64, i128); - rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); - rev!(try_from_both_bounded, isize, i32, i64, i128); + rev!(impl_try_from_upper_bounded, isize => u16, u32, u64, u128); + rev!(impl_try_from_both_bounded, isize => i32, i64, i128); } #[cfg(target_pointer_width = "32")] @@ -360,25 +348,25 @@ mod ptr_try_from_impls { use super::TryFromIntError; use crate::convert::TryFrom; - try_from_upper_bounded!(usize, u8, u16); - try_from_unbounded!(usize, u32, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32); - try_from_unbounded!(usize, i64, i128); - - try_from_both_bounded!(isize, u8, u16); - try_from_lower_bounded!(isize, u32, u64, u128); - try_from_both_bounded!(isize, i8, i16); - try_from_unbounded!(isize, i32, i64, i128); - - rev!(try_from_unbounded, usize, u32); - rev!(try_from_upper_bounded, usize, u64, u128); - rev!(try_from_lower_bounded, usize, i8, i16, i32); - rev!(try_from_both_bounded, usize, i64, i128); - - rev!(try_from_unbounded, isize, u16); - rev!(try_from_upper_bounded, isize, u32, u64, u128); - rev!(try_from_unbounded, isize, i32); - rev!(try_from_both_bounded, isize, i64, i128); + impl_try_from_upper_bounded!(usize => u8, u16); + impl_try_from_unbounded!(usize => u32, u64, u128); + impl_try_from_upper_bounded!(usize => i8, i16, i32); + impl_try_from_unbounded!(usize => i64, i128); + + impl_try_from_both_bounded!(isize => u8, u16); + impl_try_from_lower_bounded!(isize => u32, u64, u128); + impl_try_from_both_bounded!(isize => i8, i16); + impl_try_from_unbounded!(isize => i32, i64, i128); + + rev!(impl_try_from_unbounded, usize => u32); + rev!(impl_try_from_upper_bounded, usize => u64, u128); + rev!(impl_try_from_lower_bounded, usize => i8, i16, i32); + rev!(impl_try_from_both_bounded, usize => i64, i128); + + rev!(impl_try_from_unbounded, isize => u16); + rev!(impl_try_from_upper_bounded, isize => u32, u64, u128); + rev!(impl_try_from_unbounded, isize => i32); + rev!(impl_try_from_both_bounded, isize => i64, i128); } #[cfg(target_pointer_width = "64")] @@ -386,195 +374,165 @@ mod ptr_try_from_impls { use super::TryFromIntError; use crate::convert::TryFrom; - try_from_upper_bounded!(usize, u8, u16, u32); - try_from_unbounded!(usize, u64, u128); - try_from_upper_bounded!(usize, i8, i16, i32, i64); - try_from_unbounded!(usize, i128); - - try_from_both_bounded!(isize, u8, u16, u32); - try_from_lower_bounded!(isize, u64, u128); - try_from_both_bounded!(isize, i8, i16, i32); - try_from_unbounded!(isize, i64, i128); - - rev!(try_from_unbounded, usize, u32, u64); - rev!(try_from_upper_bounded, usize, u128); - rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); - rev!(try_from_both_bounded, usize, i128); - - rev!(try_from_unbounded, isize, u16, u32); - rev!(try_from_upper_bounded, isize, u64, u128); - rev!(try_from_unbounded, isize, i32, i64); - rev!(try_from_both_bounded, isize, i128); + impl_try_from_upper_bounded!(usize => u8, u16, u32); + impl_try_from_unbounded!(usize => u64, u128); + impl_try_from_upper_bounded!(usize => i8, i16, i32, i64); + impl_try_from_unbounded!(usize => i128); + + impl_try_from_both_bounded!(isize => u8, u16, u32); + impl_try_from_lower_bounded!(isize => u64, u128); + impl_try_from_both_bounded!(isize => i8, i16, i32); + impl_try_from_unbounded!(isize => i64, i128); + + rev!(impl_try_from_unbounded, usize => u32, u64); + rev!(impl_try_from_upper_bounded, usize => u128); + rev!(impl_try_from_lower_bounded, usize => i8, i16, i32, i64); + rev!(impl_try_from_both_bounded, usize => i128); + + rev!(impl_try_from_unbounded, isize => u16, u32); + rev!(impl_try_from_upper_bounded, isize => u64, u128); + rev!(impl_try_from_unbounded, isize => i32, i64); + rev!(impl_try_from_both_bounded, isize => i128); } // Conversion traits for non-zero integer types -use crate::num::NonZeroI128; -use crate::num::NonZeroI16; -use crate::num::NonZeroI32; -use crate::num::NonZeroI64; -use crate::num::NonZeroI8; -use crate::num::NonZeroIsize; -use crate::num::NonZeroU128; -use crate::num::NonZeroU16; -use crate::num::NonZeroU32; -use crate::num::NonZeroU64; -use crate::num::NonZeroU8; -use crate::num::NonZeroUsize; - -macro_rules! nzint_impl_from { - ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { - #[$attr] - impl From<$Small> for $Large { +use crate::num::NonZero; + +macro_rules! impl_nonzero_int_from_nonzero_int { + ($Small:ty => $Large:ty) => { + #[stable(feature = "nz_int_conv", since = "1.41.0")] + impl From> for NonZero<$Large> { // Rustdocs on the impl block show a "[+] show undocumented items" toggle. // Rustdocs on functions do not. - #[doc = $doc] + #[doc = concat!("Converts [NonZero]\\<[", stringify!($Small), "]> ")] + #[doc = concat!("to [NonZero]\\<[", stringify!($Large), "]> losslessly.")] #[inline] - fn from(small: $Small) -> Self { + fn from(small: NonZero<$Small>) -> Self { // SAFETY: input type guarantees the value is non-zero - unsafe { - Self::new_unchecked(From::from(small.get())) - } + unsafe { Self::new_unchecked(From::from(small.get())) } } } }; - ($Small: ty, $Large: ty, #[$attr:meta]) => { - nzint_impl_from!($Small, - $Large, - #[$attr], - concat!("Converts `", - stringify!($Small), - "` to `", - stringify!($Large), - "` losslessly.")); - } } -// Non-zero Unsigned -> Non-zero Unsigned -nzint_impl_from! { NonZeroU8, NonZeroU16, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU8, NonZeroU32, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU8, NonZeroU64, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU8, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU8, NonZeroUsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU16, NonZeroU32, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU16, NonZeroU64, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU16, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU16, NonZeroUsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU32, NonZeroU64, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU32, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU64, NonZeroU128, #[stable(feature = "nz_int_conv", since = "1.41.0")] } - -// Non-zero Signed -> Non-zero Signed -nzint_impl_from! { NonZeroI8, NonZeroI16, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroI8, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroI8, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroI8, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroI8, NonZeroIsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroI16, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroI16, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroI16, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroI16, NonZeroIsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroI32, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroI32, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroI64, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] } - -// NonZero UnSigned -> Non-zero Signed -nzint_impl_from! { NonZeroU8, NonZeroI16, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU8, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU8, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU8, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU8, NonZeroIsize, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU16, NonZeroI32, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU16, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU16, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU32, NonZeroI64, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU32, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] } -nzint_impl_from! { NonZeroU64, NonZeroI128, #[stable(feature = "nz_int_conv", since = "1.41.0")] } - -macro_rules! nzint_impl_try_from_int { - ($Int: ty, $NonZeroInt: ty, #[$attr:meta], $doc: expr) => { - #[$attr] - impl TryFrom<$Int> for $NonZeroInt { +// non-zero unsigned integer -> non-zero unsigned integer +impl_nonzero_int_from_nonzero_int!(u8 => u16); +impl_nonzero_int_from_nonzero_int!(u8 => u32); +impl_nonzero_int_from_nonzero_int!(u8 => u64); +impl_nonzero_int_from_nonzero_int!(u8 => u128); +impl_nonzero_int_from_nonzero_int!(u8 => usize); +impl_nonzero_int_from_nonzero_int!(u16 => u32); +impl_nonzero_int_from_nonzero_int!(u16 => u64); +impl_nonzero_int_from_nonzero_int!(u16 => u128); +impl_nonzero_int_from_nonzero_int!(u16 => usize); +impl_nonzero_int_from_nonzero_int!(u32 => u64); +impl_nonzero_int_from_nonzero_int!(u32 => u128); +impl_nonzero_int_from_nonzero_int!(u64 => u128); + +// non-zero signed integer -> non-zero signed integer +impl_nonzero_int_from_nonzero_int!(i8 => i16); +impl_nonzero_int_from_nonzero_int!(i8 => i32); +impl_nonzero_int_from_nonzero_int!(i8 => i64); +impl_nonzero_int_from_nonzero_int!(i8 => i128); +impl_nonzero_int_from_nonzero_int!(i8 => isize); +impl_nonzero_int_from_nonzero_int!(i16 => i32); +impl_nonzero_int_from_nonzero_int!(i16 => i64); +impl_nonzero_int_from_nonzero_int!(i16 => i128); +impl_nonzero_int_from_nonzero_int!(i16 => isize); +impl_nonzero_int_from_nonzero_int!(i32 => i64); +impl_nonzero_int_from_nonzero_int!(i32 => i128); +impl_nonzero_int_from_nonzero_int!(i64 => i128); + +// non-zero unsigned -> non-zero signed integer +impl_nonzero_int_from_nonzero_int!(u8 => i16); +impl_nonzero_int_from_nonzero_int!(u8 => i32); +impl_nonzero_int_from_nonzero_int!(u8 => i64); +impl_nonzero_int_from_nonzero_int!(u8 => i128); +impl_nonzero_int_from_nonzero_int!(u8 => isize); +impl_nonzero_int_from_nonzero_int!(u16 => i32); +impl_nonzero_int_from_nonzero_int!(u16 => i64); +impl_nonzero_int_from_nonzero_int!(u16 => i128); +impl_nonzero_int_from_nonzero_int!(u32 => i64); +impl_nonzero_int_from_nonzero_int!(u32 => i128); +impl_nonzero_int_from_nonzero_int!(u64 => i128); + +macro_rules! impl_nonzero_int_try_from_int { + ($Int:ty) => { + #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] + impl TryFrom<$Int> for NonZero<$Int> { type Error = TryFromIntError; // Rustdocs on the impl block show a "[+] show undocumented items" toggle. // Rustdocs on functions do not. - #[doc = $doc] + #[doc = concat!("Attempts to convert [`", stringify!($Int), "`] ")] + #[doc = concat!("to [NonZero]\\<[", stringify!($Int), "]>.")] #[inline] fn try_from(value: $Int) -> Result { Self::new(value).ok_or(TryFromIntError(())) } } }; - ($Int: ty, $NonZeroInt: ty, #[$attr:meta]) => { - nzint_impl_try_from_int!($Int, - $NonZeroInt, - #[$attr], - concat!("Attempts to convert `", - stringify!($Int), - "` to `", - stringify!($NonZeroInt), - "`.")); - } } -// Int -> Non-zero Int -nzint_impl_try_from_int! { u8, NonZeroU8, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } -nzint_impl_try_from_int! { u16, NonZeroU16, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } -nzint_impl_try_from_int! { u32, NonZeroU32, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } -nzint_impl_try_from_int! { u64, NonZeroU64, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } -nzint_impl_try_from_int! { u128, NonZeroU128, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } -nzint_impl_try_from_int! { usize, NonZeroUsize, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } -nzint_impl_try_from_int! { i8, NonZeroI8, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } -nzint_impl_try_from_int! { i16, NonZeroI16, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } -nzint_impl_try_from_int! { i32, NonZeroI32, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } -nzint_impl_try_from_int! { i64, NonZeroI64, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } -nzint_impl_try_from_int! { i128, NonZeroI128, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } -nzint_impl_try_from_int! { isize, NonZeroIsize, #[stable(feature = "nzint_try_from_int_conv", since = "1.46.0")] } - -macro_rules! nzint_impl_try_from_nzint { - ($From:ty => $To:ty, $doc: expr) => { +// integer -> non-zero integer +impl_nonzero_int_try_from_int!(u8); +impl_nonzero_int_try_from_int!(u16); +impl_nonzero_int_try_from_int!(u32); +impl_nonzero_int_try_from_int!(u64); +impl_nonzero_int_try_from_int!(u128); +impl_nonzero_int_try_from_int!(usize); +impl_nonzero_int_try_from_int!(i8); +impl_nonzero_int_try_from_int!(i16); +impl_nonzero_int_try_from_int!(i32); +impl_nonzero_int_try_from_int!(i64); +impl_nonzero_int_try_from_int!(i128); +impl_nonzero_int_try_from_int!(isize); + +macro_rules! impl_nonzero_int_try_from_nonzero_int { + ($source:ty => $($target:ty),+) => {$( #[stable(feature = "nzint_try_from_nzint_conv", since = "1.49.0")] - impl TryFrom<$From> for $To { + impl TryFrom> for NonZero<$target> { type Error = TryFromIntError; // Rustdocs on the impl block show a "[+] show undocumented items" toggle. // Rustdocs on functions do not. - #[doc = $doc] + #[doc = concat!("Attempts to convert [NonZero]\\<[", stringify!($source), "]> ")] + #[doc = concat!("to [NonZero]\\<[", stringify!($target), "]>.")] #[inline] - fn try_from(value: $From) -> Result { - TryFrom::try_from(value.get()).map(|v| { - // SAFETY: $From is a NonZero type, so v is not zero. - unsafe { Self::new_unchecked(v) } - }) + fn try_from(value: NonZero<$source>) -> Result { + // SAFETY: Input is guaranteed to be non-zero. + Ok(unsafe { Self::new_unchecked(<$target>::try_from(value.get())?) }) } } - }; - ($To:ty: $($From: ty),*) => {$( - nzint_impl_try_from_nzint!( - $From => $To, - concat!( - "Attempts to convert `", - stringify!($From), - "` to `", - stringify!($To), - "`.", - ) - ); )*}; } -// Non-zero int -> non-zero unsigned int -nzint_impl_try_from_nzint! { NonZeroU8: NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } -nzint_impl_try_from_nzint! { NonZeroU16: NonZeroI8, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } -nzint_impl_try_from_nzint! { NonZeroU32: NonZeroI8, NonZeroI16, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } -nzint_impl_try_from_nzint! { NonZeroU64: NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } -nzint_impl_try_from_nzint! { NonZeroU128: NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroUsize, NonZeroIsize } -nzint_impl_try_from_nzint! { NonZeroUsize: NonZeroI8, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroIsize } - -// Non-zero int -> non-zero signed int -nzint_impl_try_from_nzint! { NonZeroI8: NonZeroU8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } -nzint_impl_try_from_nzint! { NonZeroI16: NonZeroU16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } -nzint_impl_try_from_nzint! { NonZeroI32: NonZeroU32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } -nzint_impl_try_from_nzint! { NonZeroI64: NonZeroU64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize } -nzint_impl_try_from_nzint! { NonZeroI128: NonZeroU128, NonZeroUsize, NonZeroIsize } -nzint_impl_try_from_nzint! { NonZeroIsize: NonZeroU16, NonZeroU32, NonZeroI32, NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize } +// unsigned non-zero integer -> unsigned non-zero integer +impl_nonzero_int_try_from_nonzero_int!(u16 => u8); +impl_nonzero_int_try_from_nonzero_int!(u32 => u8, u16, usize); +impl_nonzero_int_try_from_nonzero_int!(u64 => u8, u16, u32, usize); +impl_nonzero_int_try_from_nonzero_int!(u128 => u8, u16, u32, u64, usize); +impl_nonzero_int_try_from_nonzero_int!(usize => u8, u16, u32, u64, u128); + +// signed non-zero integer -> signed non-zero integer +impl_nonzero_int_try_from_nonzero_int!(i16 => i8); +impl_nonzero_int_try_from_nonzero_int!(i32 => i8, i16, isize); +impl_nonzero_int_try_from_nonzero_int!(i64 => i8, i16, i32, isize); +impl_nonzero_int_try_from_nonzero_int!(i128 => i8, i16, i32, i64, isize); +impl_nonzero_int_try_from_nonzero_int!(isize => i8, i16, i32, i64, i128); + +// unsigned non-zero integer -> signed non-zero integer +impl_nonzero_int_try_from_nonzero_int!(u8 => i8); +impl_nonzero_int_try_from_nonzero_int!(u16 => i8, i16, isize); +impl_nonzero_int_try_from_nonzero_int!(u32 => i8, i16, i32, isize); +impl_nonzero_int_try_from_nonzero_int!(u64 => i8, i16, i32, i64, isize); +impl_nonzero_int_try_from_nonzero_int!(u128 => i8, i16, i32, i64, i128, isize); +impl_nonzero_int_try_from_nonzero_int!(usize => i8, i16, i32, i64, i128, isize); + +// signed non-zero integer -> unsigned non-zero integer +impl_nonzero_int_try_from_nonzero_int!(i8 => u8, u16, u32, u64, u128, usize); +impl_nonzero_int_try_from_nonzero_int!(i16 => u8, u16, u32, u64, u128, usize); +impl_nonzero_int_try_from_nonzero_int!(i32 => u8, u16, u32, u64, u128, usize); +impl_nonzero_int_try_from_nonzero_int!(i64 => u8, u16, u32, u64, u128, usize); +impl_nonzero_int_try_from_nonzero_int!(i128 => u8, u16, u32, u64, u128, usize); +impl_nonzero_int_try_from_nonzero_int!(isize => u8, u16, u32, u64, u128, usize); From 994d55158dcfe0b1b299591bb552af14c63c6e60 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 Feb 2024 02:13:28 +0000 Subject: [PATCH 02/12] Simply do not ICE --- .../rustc_trait_selection/src/solve/fulfill.rs | 5 ++++- .../next-solver/coherence-fulfill-overflow.rs | 15 +++++++++++++++ .../next-solver/coherence-fulfill-overflow.stderr | 11 +++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/next-solver/coherence-fulfill-overflow.rs create mode 100644 tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 63555a305d855..97f715b6386c2 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -109,7 +109,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let mut errors = Vec::new(); for i in 0.. { if !infcx.tcx.recursion_limit().value_within_limit(i) { - unimplemented!("overflowed on pending obligations: {:?}", self.obligations); + // Only return true errors that we have accumulated while processing; + // keep ambiguities around, *including overflows*, because they shouldn't + // be considered true errors. + return errors; } let mut has_changed = false; diff --git a/tests/ui/traits/next-solver/coherence-fulfill-overflow.rs b/tests/ui/traits/next-solver/coherence-fulfill-overflow.rs new file mode 100644 index 0000000000000..ff577da32c23a --- /dev/null +++ b/tests/ui/traits/next-solver/coherence-fulfill-overflow.rs @@ -0,0 +1,15 @@ +//@ compile-flags: -Znext-solver=coherence + +#![recursion_limit = "10"] + +trait Trait {} + +struct W(*const T); +trait TwoW {} +impl TwoW for W> {} + +impl Trait for W {} +impl Trait for T {} +//~^ ERROR conflicting implementations of trait `Trait` for type `W + +fn main() {} diff --git a/tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr new file mode 100644 index 0000000000000..406c0ccca9723 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence-fulfill-overflow.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `W>>>>>>>>>>>>>>>>>>>>` + --> $DIR/coherence-fulfill-overflow.rs:12:1 + | +LL | impl Trait for W {} + | ------------------------------------- first implementation here +LL | impl Trait for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W>>>>>>>>>>>>>>>>>>>>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. From 18fdf59bf5fc20d1c651f1d0e1dfae5cf421f685 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 Feb 2024 02:58:07 +0000 Subject: [PATCH 03/12] Don't use raw parameter types in find_builder_fn --- compiler/rustc_hir_typeck/src/method/suggest.rs | 8 ++++++-- tests/ui/issues/issue-30123.stderr | 5 +++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 4151298b42f0a..5aededa62bd79 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -34,8 +34,8 @@ use rustc_middle::ty::IsSuggestable; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::DefIdSet; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::Symbol; use rustc_span::{edit_distance, ExpnKind, FileName, MacroKind, Span}; +use rustc_span::{Symbol, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote; use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _; @@ -1597,7 +1597,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter) .filter_map(|item| { // Only assoc fns that return `Self`, `Option` or `Result`. - let ret_ty = self.tcx.fn_sig(item.def_id).skip_binder().output(); + let ret_ty = self + .tcx + .fn_sig(item.def_id) + .instantiate(self.tcx, self.fresh_args_for_item(DUMMY_SP, item.def_id)) + .output(); let ret_ty = self.tcx.instantiate_bound_regions_with_erased(ret_ty); let ty::Adt(def, args) = ret_ty.kind() else { return None; diff --git a/tests/ui/issues/issue-30123.stderr b/tests/ui/issues/issue-30123.stderr index cf71a01b58a5c..c086b45ac9bc0 100644 --- a/tests/ui/issues/issue-30123.stderr +++ b/tests/ui/issues/issue-30123.stderr @@ -4,6 +4,11 @@ error[E0599]: no function or associated item named `new_undirected` found for st LL | let ug = Graph::::new_undirected(); | ^^^^^^^^^^^^^^ function or associated item not found in `Graph` | +note: if you're trying to build a new `issue_30123_aux::Graph`, consider using `issue_30123_aux::Graph::::new` which returns `issue_30123_aux::Graph<_, _>` + --> $DIR/auxiliary/issue-30123-aux.rs:14:5 + | +LL | pub fn new() -> Self { + | ^^^^^^^^^^^^^^^^^^^^ = note: the function or associated item was found for - `issue_30123_aux::Graph` From 1c80aadb0566a344adc028b06f47f1a21ec21e0c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 Feb 2024 03:01:35 +0000 Subject: [PATCH 04/12] test --- tests/ui/ufcs/bad-builder.rs | 6 ++++++ tests/ui/ufcs/bad-builder.stderr | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/ui/ufcs/bad-builder.rs create mode 100644 tests/ui/ufcs/bad-builder.stderr diff --git a/tests/ui/ufcs/bad-builder.rs b/tests/ui/ufcs/bad-builder.rs new file mode 100644 index 0000000000000..350c96acca08b --- /dev/null +++ b/tests/ui/ufcs/bad-builder.rs @@ -0,0 +1,6 @@ +fn hello() -> Vec { + Vec::::mew() + //~^ ERROR no function or associated item named `mew` found for struct `Vec` in the current scope +} + +fn main() {} diff --git a/tests/ui/ufcs/bad-builder.stderr b/tests/ui/ufcs/bad-builder.stderr new file mode 100644 index 0000000000000..7fa47c82de2f7 --- /dev/null +++ b/tests/ui/ufcs/bad-builder.stderr @@ -0,0 +1,20 @@ +error[E0599]: no function or associated item named `mew` found for struct `Vec` in the current scope + --> $DIR/bad-builder.rs:2:15 + | +LL | Vec::::mew() + | ^^^ + | | + | function or associated item not found in `Vec` + | help: there is an associated function with a similar name: `new` + | +note: if you're trying to build a new `Vec` consider using one of the following associated functions: + Vec::::new + Vec::::with_capacity + Vec::::from_raw_parts + Vec::::new_in + and 2 others + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. From 762febdaf33667995578ec8183a2379e28bb6b40 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 20 Feb 2024 15:43:29 +0000 Subject: [PATCH 05/12] Fix stray trait mismatch in resolve_associated_item for AsyncFn --- compiler/rustc_ty_utils/src/instance.rs | 18 +++-------------- .../async-fn/auxiliary/block-on.rs | 20 +++++++++++++++++++ tests/ui/async-await/async-fn/simple.rs | 7 ++++++- 3 files changed, 29 insertions(+), 16 deletions(-) create mode 100644 tests/ui/async-await/async-fn/auxiliary/block-on.rs diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 5fc93d666ab16..3e3bccce47fe4 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -246,7 +246,7 @@ fn resolve_associated_item<'tcx>( span: tcx.def_span(trait_item_id), }) } - } else if tcx.fn_trait_kind_from_def_id(trait_ref.def_id).is_some() { + } else if let Some(target_kind) = tcx.fn_trait_kind_from_def_id(trait_ref.def_id) { // FIXME: This doesn't check for malformed libcore that defines, e.g., // `trait Fn { fn call_once(&self) { .. } }`. This is mostly for extension // methods. @@ -265,13 +265,7 @@ fn resolve_associated_item<'tcx>( } match *rcvr_args.type_at(0).kind() { ty::Closure(closure_def_id, args) => { - let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap(); - Some(Instance::resolve_closure( - tcx, - closure_def_id, - args, - trait_closure_kind, - )) + Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind)) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), @@ -324,13 +318,7 @@ fn resolve_associated_item<'tcx>( } } ty::Closure(closure_def_id, args) => { - let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap(); - Some(Instance::resolve_closure( - tcx, - closure_def_id, - args, - trait_closure_kind, - )) + Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind)) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), diff --git a/tests/ui/async-await/async-fn/auxiliary/block-on.rs b/tests/ui/async-await/async-fn/auxiliary/block-on.rs new file mode 100644 index 0000000000000..dcb710fc97c97 --- /dev/null +++ b/tests/ui/async-await/async-fn/auxiliary/block-on.rs @@ -0,0 +1,20 @@ +//@ edition: 2021 + +#![feature(async_closure, noop_waker)] + +use std::future::Future; +use std::pin::pin; +use std::task::*; + +pub fn block_on(fut: impl Future) -> T { + let mut fut = pin!(fut); + // Poll loop, just to test the future... + let ctx = &mut Context::from_waker(Waker::noop()); + + loop { + match unsafe { fut.as_mut().poll(ctx) } { + Poll::Pending => {} + Poll::Ready(t) => break t, + } + } +} diff --git a/tests/ui/async-await/async-fn/simple.rs b/tests/ui/async-await/async-fn/simple.rs index e2a183a8c0ba0..21972ba5aefad 100644 --- a/tests/ui/async-await/async-fn/simple.rs +++ b/tests/ui/async-await/async-fn/simple.rs @@ -1,8 +1,11 @@ +//@ aux-build:block-on.rs //@ edition: 2021 //@ build-pass #![feature(async_fn_traits)] +extern crate block_on; + use std::ops::AsyncFn; async fn foo() {} @@ -12,5 +15,7 @@ async fn call_asyncly(f: impl AsyncFn(i32) -> i32) -> i32 { } fn main() { - let fut = call_asyncly(|x| async move { x + 1 }); + block_on::block_on(async { + call_asyncly(|x| async move { x + 1 }).await; + }); } From 14a45516951edbbc9dd404529073dc9e9dd40351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Oko=C5=84ski?= Date: Fri, 22 Dec 2023 00:15:44 +0100 Subject: [PATCH 06/12] Correct the simd_masked_{load,store} intrinsic docs --- library/core/src/intrinsics/simd.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 68c8a335b405c..f7818e611f401 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -243,12 +243,13 @@ extern "platform-intrinsic" { /// /// `T` must be a vector. /// - /// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`. + /// `U` must be a pointer to the element type of `T` /// /// `V` must be a vector of integers with the same length as `T` (but any element size). /// /// For each element, if the corresponding value in `mask` is `!0`, read the corresponding - /// pointer from `ptr`. + /// pointer offset from `ptr`. + /// The first element is loaded from `ptr`, the second from `ptr.wrapping_offset(1)` and so on. /// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from /// `val`. /// @@ -264,12 +265,13 @@ extern "platform-intrinsic" { /// /// `T` must be a vector. /// - /// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`. + /// `U` must be a pointer to the element type of `T` /// /// `V` must be a vector of integers with the same length as `T` (but any element size). /// /// For each element, if the corresponding value in `mask` is `!0`, write the corresponding - /// value in `val` to the pointer. + /// value in `val` to the pointer offset from `ptr`. + /// The first element is written to `ptr`, the second to `ptr.wrapping_offset(1)` and so on. /// Otherwise if the corresponding value in `mask` is `0`, do nothing. /// /// # Safety From 05ce209d20232f6d933421f8b8ac58d94557a2aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 20 Feb 2024 10:34:51 +0100 Subject: [PATCH 07/12] Rename some normalization-related items --- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 32 ++++++++++++------ compiler/rustc_middle/src/traits/query.rs | 6 ++-- .../src/traits/normalize.rs | 2 -- .../src/traits/query/normalize.rs | 16 ++++----- .../src/normalize_projection_ty.rs | 33 ++++++++++--------- 6 files changed, 51 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index c648b2bfe9b90..a532635669dfd 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -47,7 +47,7 @@ macro_rules! arena_types { rustc_middle::traits::query::DropckOutlivesResult<'tcx> > >, - [] normalize_projection_ty: + [] normalize_canonicalized_projection_ty: rustc_middle::infer::canonical::Canonical<'tcx, rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::traits::query::NormalizationResult<'tcx> diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 5be45c33e1124..c931d2e5313aa 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -31,7 +31,7 @@ use crate::query::plumbing::{ }; use crate::thir; use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, + CanonicalAliasGoal, CanonicalPredicateGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution, }; @@ -1931,9 +1931,13 @@ rustc_queries! { arena_cache } - /// Do not call this query directly: invoke `normalize` instead. - query normalize_projection_ty( - goal: CanonicalProjectionGoal<'tcx> + ///
+ /// + /// Do not call this query directly: Invoke `normalize` instead. + /// + ///
+ query normalize_canonicalized_projection_ty( + goal: CanonicalAliasGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution, @@ -1941,9 +1945,13 @@ rustc_queries! { desc { "normalizing `{}`", goal.value.value } } - /// Do not call this query directly: invoke `normalize` instead. - query normalize_weak_ty( - goal: CanonicalProjectionGoal<'tcx> + ///
+ /// + /// Do not call this query directly: Invoke `normalize` instead. + /// + ///
+ query normalize_canonicalized_weak_ty( + goal: CanonicalAliasGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution, @@ -1951,9 +1959,13 @@ rustc_queries! { desc { "normalizing `{}`", goal.value.value } } - /// Do not call this query directly: invoke `normalize` instead. - query normalize_inherent_projection_ty( - goal: CanonicalProjectionGoal<'tcx> + ///
+ /// + /// Do not call this query directly: Invoke `normalize` instead. + /// + ///
+ query normalize_canonicalized_inherent_projection_ty( + goal: CanonicalAliasGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution, diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 61d96cad57d77..12e4f70ba5751 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -67,7 +67,7 @@ pub mod type_op { } } -pub type CanonicalProjectionGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>; +pub type CanonicalAliasGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::AliasTy<'tcx>>>; pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; @@ -177,10 +177,10 @@ pub struct MethodAutoderefBadTy<'tcx> { pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, } -/// Result from the `normalize_projection_ty` query. +/// Result of the `normalize_canonicalized_{{,inherent_}projection,weak}_ty` queries. #[derive(Clone, Debug, HashStable, TypeFoldable, TypeVisitable)] pub struct NormalizationResult<'tcx> { - /// Result of normalization. + /// Result of the normalization. pub normalized_ty: Ty<'tcx>, } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index ac62f875fb910..f37d917b4a08e 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -355,8 +355,6 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx let data = data.fold_with(self); - // FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement` - // here like `ty::Projection`? project::normalize_inherent_projection( self.selcx, self.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 26da065246d7e..70fd0b7e50b75 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -1,6 +1,6 @@ //! Code for the 'normalization' query. This consists of a wrapper //! which folds deeply, invoking the underlying -//! `normalize_projection_ty` query when it encounters projections. +//! `normalize_canonicalized_projection_ty` query when it encounters projections. use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; @@ -271,9 +271,9 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); let result = match kind { - ty::Projection => tcx.normalize_projection_ty(c_data), - ty::Weak => tcx.normalize_weak_ty(c_data), - ty::Inherent => tcx.normalize_inherent_projection_ty(c_data), + ty::Projection => tcx.normalize_canonicalized_projection_ty(c_data), + ty::Weak => tcx.normalize_canonicalized_weak_ty(c_data), + ty::Inherent => tcx.normalize_canonicalized_inherent_projection_ty(c_data), kind => unreachable!("did not expect {kind:?} due to match arm above"), }?; // We don't expect ambiguity. @@ -308,10 +308,10 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> } else { result.normalized_ty }; - // `tcx.normalize_projection_ty` may normalize to a type that still has - // unevaluated consts, so keep normalizing here if that's the case. - // Similarly, `tcx.normalize_weak_ty` will only unwrap one layer of type - // and we need to continue folding it to reveal the TAIT behind it. + // `tcx.normalize_canonicalized_projection_ty` may normalize to a type that + // still has unevaluated consts, so keep normalizing here if that's the case. + // Similarly, `tcx.normalize_canonicalized_weak_ty` will only unwrap one layer + // of type and we need to continue folding it to reveal the TAIT behind it. if res != ty && (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) || kind == ty::Weak) { diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 94df28a145465..92a19fb91198c 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::query::{ - normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution, + normalize::NormalizationResult, CanonicalAliasGoal, NoSolution, }; use rustc_trait_selection::traits::{ self, FulfillmentErrorCode, ObligationCause, SelectionContext, @@ -13,18 +13,19 @@ use rustc_trait_selection::traits::{ pub(crate) fn provide(p: &mut Providers) { *p = Providers { - normalize_projection_ty, - normalize_weak_ty, - normalize_inherent_projection_ty, + normalize_canonicalized_projection_ty, + normalize_canonicalized_weak_ty, + normalize_canonicalized_inherent_projection_ty, ..*p }; } -fn normalize_projection_ty<'tcx>( +fn normalize_canonicalized_projection_ty<'tcx>( tcx: TyCtxt<'tcx>, - goal: CanonicalProjectionGoal<'tcx>, + goal: CanonicalAliasGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { - debug!("normalize_provider(goal={:#?})", goal); + debug!("normalize_canonicalized_projection_ty(goal={:#?})", goal); + tcx.infer_ctxt().enter_canonical_trait_query( &goal, |ocx, ParamEnvAnd { param_env, value: goal }| { @@ -61,19 +62,19 @@ fn normalize_projection_ty<'tcx>( return Err(NoSolution); } - // FIXME(associated_const_equality): All users of normalize_projection_ty expected - // a type, but there is the possibility it could've been a const now. Maybe change - // it to a Term later? + // FIXME(associated_const_equality): All users of normalize_canonicalized_projection_ty + // expected a type, but there is the possibility it could've been a const now. + // Maybe change it to a Term later? Ok(NormalizationResult { normalized_ty: answer.ty().unwrap() }) }, ) } -fn normalize_weak_ty<'tcx>( +fn normalize_canonicalized_weak_ty<'tcx>( tcx: TyCtxt<'tcx>, - goal: CanonicalProjectionGoal<'tcx>, + goal: CanonicalAliasGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { - debug!("normalize_provider(goal={:#?})", goal); + debug!("normalize_canonicalized_weak_ty(goal={:#?})", goal); tcx.infer_ctxt().enter_canonical_trait_query( &goal, @@ -95,11 +96,11 @@ fn normalize_weak_ty<'tcx>( ) } -fn normalize_inherent_projection_ty<'tcx>( +fn normalize_canonicalized_inherent_projection_ty<'tcx>( tcx: TyCtxt<'tcx>, - goal: CanonicalProjectionGoal<'tcx>, + goal: CanonicalAliasGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> { - debug!("normalize_provider(goal={:#?})", goal); + debug!("normalize_canonicalized_inherent_projection_ty(goal={:#?})", goal); tcx.infer_ctxt().enter_canonical_trait_query( &goal, From 515d805a0e76b57853bf9e929a2e7b084c475824 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 20 Feb 2024 12:38:23 +0100 Subject: [PATCH 08/12] Introduce expand_weak_alias_tys --- compiler/rustc_middle/src/ty/flags.rs | 5 +- compiler/rustc_middle/src/ty/util.rs | 61 +++++++++++++++++++ compiler/rustc_middle/src/ty/visit.rs | 25 ++++---- .../src/traits/normalize.rs | 20 +++--- compiler/rustc_type_ir/src/flags.rs | 31 +++++----- .../constrained-late-bound-regions.rs | 15 +++++ ...arams.rs => constrained-params-in-impl.rs} | 0 .../unconstrained-late-bound-regions.rs | 23 +++++++ .../unconstrained-late-bound-regions.stderr | 22 +++++++ ...trained-params-in-impl-due-to-overflow.rs} | 0 ...ned-params-in-impl-due-to-overflow.stderr} | 2 +- ...ams.rs => unconstrained-params-in-impl.rs} | 0 ...rr => unconstrained-params-in-impl.stderr} | 2 +- 13 files changed, 165 insertions(+), 41 deletions(-) create mode 100644 tests/ui/lazy-type-alias/constrained-late-bound-regions.rs rename tests/ui/lazy-type-alias/{constrained-params.rs => constrained-params-in-impl.rs} (100%) create mode 100644 tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs create mode 100644 tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr rename tests/ui/lazy-type-alias/{unconstrained-param-due-to-overflow.rs => unconstrained-params-in-impl-due-to-overflow.rs} (100%) rename tests/ui/lazy-type-alias/{unconstrained-param-due-to-overflow.stderr => unconstrained-params-in-impl-due-to-overflow.stderr} (81%) rename tests/ui/lazy-type-alias/{unconstrained-params.rs => unconstrained-params-in-impl.rs} (100%) rename tests/ui/lazy-type-alias/{unconstrained-params.stderr => unconstrained-params-in-impl.stderr} (85%) diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 0f4b5fe228c96..18cf5445e5621 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -181,9 +181,10 @@ impl FlagComputation { &ty::Alias(kind, data) => { self.add_flags(match kind { - ty::Weak | ty::Projection => TypeFlags::HAS_TY_PROJECTION, - ty::Inherent => TypeFlags::HAS_TY_INHERENT, + ty::Projection => TypeFlags::HAS_TY_PROJECTION, + ty::Weak => TypeFlags::HAS_TY_WEAK, ty::Opaque => TypeFlags::HAS_TY_OPAQUE, + ty::Inherent => TypeFlags::HAS_TY_INHERENT, }); self.add_alias_ty(data); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 3f539945841b6..ff9d1ed6ae995 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -11,6 +11,7 @@ use crate::ty::{GenericArgKind, GenericArgsRef}; use rustc_apfloat::Float as _; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -867,6 +868,30 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param)) } + + /// Expand any [weak alias types][weak] contained within the given `value`. + /// + /// This should be used over other normalization routines in situations where + /// it's important not to normalize other alias types and where the predicates + /// on the corresponding type alias shouldn't be taken into consideration. + /// + /// Whenever possible **prefer not to use this function**! Instead, use standard + /// normalization routines or if feasible don't normalize at all. + /// + /// This function comes in handy if you want to mimic the behavior of eager + /// type alias expansion in a localized manner. + /// + ///
+ /// This delays a bug on overflow! Therefore you need to be certain that the + /// contained types get fully normalized at a later stage. Note that even on + /// overflow all well-behaved weak alias types get expanded correctly, so the + /// result is still useful. + ///
+ /// + /// [weak]: ty::Weak + pub fn expand_weak_alias_tys>>(self, value: T) -> T { + value.fold_with(&mut WeakAliasTypeExpander { tcx: self, depth: 0 }) + } } struct OpaqueTypeExpander<'tcx> { @@ -1002,6 +1027,42 @@ impl<'tcx> TypeFolder> for OpaqueTypeExpander<'tcx> { } } +struct WeakAliasTypeExpander<'tcx> { + tcx: TyCtxt<'tcx>, + depth: usize, +} + +impl<'tcx> TypeFolder> for WeakAliasTypeExpander<'tcx> { + fn interner(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + if !ty.has_type_flags(ty::TypeFlags::HAS_TY_WEAK) { + return ty; + } + let ty::Alias(ty::Weak, alias) = ty.kind() else { + return ty.super_fold_with(self); + }; + if !self.tcx.recursion_limit().value_within_limit(self.depth) { + let guar = self.tcx.dcx().delayed_bug("overflow expanding weak alias type"); + return Ty::new_error(self.tcx, guar); + } + + self.depth += 1; + ensure_sufficient_stack(|| { + self.tcx.type_of(alias.def_id).instantiate(self.tcx, alias.args).fold_with(self) + }) + } + + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + if !ct.ty().has_type_flags(ty::TypeFlags::HAS_TY_WEAK) { + return ct; + } + ct.super_fold_with(self) + } +} + impl<'tcx> Ty<'tcx> { /// Returns the `Size` for primitive types (bool, uint, int, char, float). pub fn primitive_size(self, tcx: TyCtxt<'tcx>) -> Size { diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 59292a281edec..1de2ceecae798 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -131,12 +131,13 @@ impl<'tcx> TyCtxt<'tcx> { fn collect_late_bound_regions( self, value: &Binder<'tcx, T>, - just_constraint: bool, + just_constrained: bool, ) -> FxHashSet where T: TypeVisitable>, { - let mut collector = LateBoundRegionsCollector::new(just_constraint); + let mut collector = LateBoundRegionsCollector::new(self, just_constrained); + let value = if just_constrained { self.expand_weak_alias_tys(value) } else { value }; let result = value.as_ref().skip_binder().visit_with(&mut collector); assert!(result.is_continue()); // should never have stopped early collector.regions @@ -258,11 +259,7 @@ struct LateBoundRegionsCollector { impl LateBoundRegionsCollector { fn new(just_constrained: bool) -> Self { - LateBoundRegionsCollector { - current_index: ty::INNERMOST, - regions: Default::default(), - just_constrained, - } + Self { current_index: ty::INNERMOST, regions: Default::default(), just_constrained } } } @@ -278,12 +275,16 @@ impl<'tcx> TypeVisitor> for LateBoundRegionsCollector { } fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - // if we are only looking for "constrained" region, we have to - // ignore the inputs to a projection, as they may not appear - // in the normalized form if self.just_constrained { - if let ty::Alias(..) = t.kind() { - return ControlFlow::Continue(()); + match t.kind() { + // If we are only looking for "constrained" regions, we have to ignore the + // inputs to a projection as they may not appear in the normalized form. + ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) => { + return ControlFlow::Continue(()); + } + // All weak alias types should've been expanded beforehand. + ty::Alias(ty::Weak, _) => bug!("unexpected weak alias type"), + _ => {} } } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index f37d917b4a08e..429e5a5d7a413 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -101,19 +101,17 @@ pub(super) fn needs_normalization<'tcx, T: TypeVisitable>>( value: &T, reveal: Reveal, ) -> bool { + let mut flags = ty::TypeFlags::HAS_TY_PROJECTION + | ty::TypeFlags::HAS_TY_WEAK + | ty::TypeFlags::HAS_TY_INHERENT + | ty::TypeFlags::HAS_CT_PROJECTION; + match reveal { - Reveal::UserFacing => value.has_type_flags( - ty::TypeFlags::HAS_TY_PROJECTION - | ty::TypeFlags::HAS_TY_INHERENT - | ty::TypeFlags::HAS_CT_PROJECTION, - ), - Reveal::All => value.has_type_flags( - ty::TypeFlags::HAS_TY_PROJECTION - | ty::TypeFlags::HAS_TY_INHERENT - | ty::TypeFlags::HAS_TY_OPAQUE - | ty::TypeFlags::HAS_CT_PROJECTION, - ), + Reveal::UserFacing => {} + Reveal::All => flags |= ty::TypeFlags::HAS_TY_OPAQUE, } + + value.has_type_flags(flags) } struct AssocTypeNormalizer<'a, 'b, 'tcx> { diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 1da26cfc24275..b38ef2ad84d48 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -69,32 +69,35 @@ bitflags! { /// Does this have `Projection`? const HAS_TY_PROJECTION = 1 << 10; - /// Does this have `Inherent`? - const HAS_TY_INHERENT = 1 << 11; + /// Does this have `Weak`? + const HAS_TY_WEAK = 1 << 11; /// Does this have `Opaque`? const HAS_TY_OPAQUE = 1 << 12; + /// Does this have `Inherent`? + const HAS_TY_INHERENT = 1 << 13; /// Does this have `ConstKind::Unevaluated`? - const HAS_CT_PROJECTION = 1 << 13; + const HAS_CT_PROJECTION = 1 << 14; /// Could this type be normalized further? const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits() + | TypeFlags::HAS_TY_WEAK.bits() | TypeFlags::HAS_TY_OPAQUE.bits() | TypeFlags::HAS_TY_INHERENT.bits() | TypeFlags::HAS_CT_PROJECTION.bits(); /// Is an error type/const reachable? - const HAS_ERROR = 1 << 14; + const HAS_ERROR = 1 << 15; /// Does this have any region that "appears free" in the type? /// Basically anything but `ReBound` and `ReErased`. - const HAS_FREE_REGIONS = 1 << 15; + const HAS_FREE_REGIONS = 1 << 16; /// Does this have any `ReBound` regions? - const HAS_RE_BOUND = 1 << 16; + const HAS_RE_BOUND = 1 << 17; /// Does this have any `Bound` types? - const HAS_TY_BOUND = 1 << 17; + const HAS_TY_BOUND = 1 << 18; /// Does this have any `ConstKind::Bound` consts? - const HAS_CT_BOUND = 1 << 18; + const HAS_CT_BOUND = 1 << 19; /// Does this have any bound variables? /// Used to check if a global bound is safe to evaluate. const HAS_BOUND_VARS = TypeFlags::HAS_RE_BOUND.bits() @@ -102,22 +105,22 @@ bitflags! { | TypeFlags::HAS_CT_BOUND.bits(); /// Does this have any `ReErased` regions? - const HAS_RE_ERASED = 1 << 19; + const HAS_RE_ERASED = 1 << 20; /// Does this value have parameters/placeholders/inference variables which could be /// replaced later, in a way that would change the results of `impl` specialization? - const STILL_FURTHER_SPECIALIZABLE = 1 << 20; + const STILL_FURTHER_SPECIALIZABLE = 1 << 21; /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`? - const HAS_TY_FRESH = 1 << 21; + const HAS_TY_FRESH = 1 << 22; /// Does this value have `InferConst::Fresh`? - const HAS_CT_FRESH = 1 << 22; + const HAS_CT_FRESH = 1 << 23; /// Does this have `Coroutine` or `CoroutineWitness`? - const HAS_TY_COROUTINE = 1 << 23; + const HAS_TY_COROUTINE = 1 << 24; /// Does this have any binders with bound vars (e.g. that need to be anonymized)? - const HAS_BINDER_VARS = 1 << 24; + const HAS_BINDER_VARS = 1 << 25; } } diff --git a/tests/ui/lazy-type-alias/constrained-late-bound-regions.rs b/tests/ui/lazy-type-alias/constrained-late-bound-regions.rs new file mode 100644 index 0000000000000..e759e72d745a1 --- /dev/null +++ b/tests/ui/lazy-type-alias/constrained-late-bound-regions.rs @@ -0,0 +1,15 @@ +//@ check-pass +// Weak alias types constrain late-bound regions if their normalized form constrains them. + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +type Ref<'a> = &'a (); + +type FnPtr = for<'a> fn(Ref<'a>) -> &'a (); // OK +type DynCl = dyn for<'a> Fn(Ref<'a>) -> &'a (); // OK + +fn map0(_: Ref) -> Ref { &() } // OK +fn map1(_: Ref<'_>) -> Ref<'_> { &() } // OK + +fn main() {} diff --git a/tests/ui/lazy-type-alias/constrained-params.rs b/tests/ui/lazy-type-alias/constrained-params-in-impl.rs similarity index 100% rename from tests/ui/lazy-type-alias/constrained-params.rs rename to tests/ui/lazy-type-alias/constrained-params-in-impl.rs diff --git a/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs b/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs new file mode 100644 index 0000000000000..844570e22d275 --- /dev/null +++ b/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.rs @@ -0,0 +1,23 @@ +// Weak alias types only constrain late-bound regions if their normalized form constrains them. + +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +type NotInjective<'a> = <() as Discard>::Output<'a>; + +type FnPtr0 = for<'a> fn(NotInjective<'a>) -> &'a (); +//~^ ERROR references lifetime `'a`, which is not constrained by the fn input types +type FnPtr1 = for<'a> fn(NotInjectiveEither<'a, ()>) -> NotInjectiveEither<'a, ()>; +//~^ ERROR references lifetime `'a`, which is not constrained by the fn input types +type DynCl = dyn for<'a> Fn(NotInjective<'a>) -> &'a (); +//~^ ERROR references lifetime `'a`, which does not appear in the trait input types + +trait Discard { type Output<'a>; } +impl Discard for () { type Output<'_a> = (); } + +type NotInjectiveEither<'a, Linchpin> = Linchpin +where + Linchpin: Fn() -> &'a (); + + +fn main() {} diff --git a/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr b/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr new file mode 100644 index 0000000000000..241c7761c60f5 --- /dev/null +++ b/tests/ui/lazy-type-alias/unconstrained-late-bound-regions.stderr @@ -0,0 +1,22 @@ +error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types + --> $DIR/unconstrained-late-bound-regions.rs:8:47 + | +LL | type FnPtr0 = for<'a> fn(NotInjective<'a>) -> &'a (); + | ^^^^^^ + +error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types + --> $DIR/unconstrained-late-bound-regions.rs:10:57 + | +LL | type FnPtr1 = for<'a> fn(NotInjectiveEither<'a, ()>) -> NotInjectiveEither<'a, ()>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0582]: binding for associated type `Output` references lifetime `'a`, which does not appear in the trait input types + --> $DIR/unconstrained-late-bound-regions.rs:12:50 + | +LL | type DynCl = dyn for<'a> Fn(NotInjective<'a>) -> &'a (); + | ^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0581, E0582. +For more information about an error, try `rustc --explain E0581`. diff --git a/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs b/tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.rs similarity index 100% rename from tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.rs rename to tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.rs diff --git a/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr b/tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.stderr similarity index 81% rename from tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr rename to tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.stderr index 9af6f5dda0b34..b65c84226ce93 100644 --- a/tests/ui/lazy-type-alias/unconstrained-param-due-to-overflow.stderr +++ b/tests/ui/lazy-type-alias/unconstrained-params-in-impl-due-to-overflow.stderr @@ -1,5 +1,5 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates - --> $DIR/unconstrained-param-due-to-overflow.rs:4:6 + --> $DIR/unconstrained-params-in-impl-due-to-overflow.rs:4:6 | LL | impl Loop {} | ^ unconstrained type parameter diff --git a/tests/ui/lazy-type-alias/unconstrained-params.rs b/tests/ui/lazy-type-alias/unconstrained-params-in-impl.rs similarity index 100% rename from tests/ui/lazy-type-alias/unconstrained-params.rs rename to tests/ui/lazy-type-alias/unconstrained-params-in-impl.rs diff --git a/tests/ui/lazy-type-alias/unconstrained-params.stderr b/tests/ui/lazy-type-alias/unconstrained-params-in-impl.stderr similarity index 85% rename from tests/ui/lazy-type-alias/unconstrained-params.stderr rename to tests/ui/lazy-type-alias/unconstrained-params-in-impl.stderr index 3c52a06c319db..2419c78cba8d9 100644 --- a/tests/ui/lazy-type-alias/unconstrained-params.stderr +++ b/tests/ui/lazy-type-alias/unconstrained-params-in-impl.stderr @@ -1,5 +1,5 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates - --> $DIR/unconstrained-params.rs:4:6 + --> $DIR/unconstrained-params-in-impl.rs:4:6 | LL | impl NotInjective {} | ^ unconstrained type parameter From da01cced15b1a59e5eb40bdf5bb0be9a143d4e5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 20 Feb 2024 13:50:39 +0100 Subject: [PATCH 09/12] Expand weak alias types before collecting constrained and referenced late bound regions --- .../rustc_hir_analysis/src/astconv/bounds.rs | 4 ++-- compiler/rustc_hir_analysis/src/astconv/mod.rs | 4 ++-- compiler/rustc_hir_analysis/src/collect.rs | 2 +- .../error_reporting/nice_region_error/util.rs | 6 +++--- compiler/rustc_middle/src/ty/visit.rs | 18 ++++++++++-------- src/librustdoc/clean/auto_trait.rs | 17 ++++++++--------- 6 files changed, 26 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 6940b4a504584..6d8a5bc0e9008 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -454,9 +454,9 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { // for<'a> ::Item = &'a str // <-- 'a is bad // for<'a> >::Output = &'a str // <-- 'a is ok let late_bound_in_projection_ty = - tcx.collect_constrained_late_bound_regions(&projection_ty); + tcx.collect_constrained_late_bound_regions(projection_ty); let late_bound_in_term = - tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(term)); + tcx.collect_referenced_late_bound_regions(trait_ref.rebind(term)); debug!(?late_bound_in_projection_ty); debug!(?late_bound_in_term); diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 296b63a8292d6..997392b6c4a7f 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2678,9 +2678,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // for<'a> fn(&'a String) -> &'a str <-- 'a is ok let inputs = bare_fn_ty.inputs(); let late_bound_in_args = - tcx.collect_constrained_late_bound_regions(&inputs.map_bound(|i| i.to_owned())); + tcx.collect_constrained_late_bound_regions(inputs.map_bound(|i| i.to_owned())); let output = bare_fn_ty.output(); - let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output); + let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(output); self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { struct_span_code_err!( diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index cffb88a1365b2..6a42fdb1079f4 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -520,7 +520,7 @@ fn get_new_lifetime_name<'tcx>( generics: &hir::Generics<'tcx>, ) -> String { let existing_lifetimes = tcx - .collect_referenced_late_bound_regions(&poly_trait_ref) + .collect_referenced_late_bound_regions(poly_trait_ref) .into_iter() .filter_map(|lt| { if let ty::BoundRegionKind::BrNamed(_, name) = lt { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index bfff00b948e96..f1f8314661f3e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -5,7 +5,7 @@ use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::TyCtxt; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::{self, Binder, Region, Ty, TypeVisitable}; +use rustc_middle::ty::{self, Binder, Region, Ty, TypeFoldable}; use rustc_span::Span; /// Information about the anonymous region we are searching for. @@ -142,10 +142,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { fn includes_region( &self, - ty: Binder<'tcx, impl TypeVisitable>>, + ty: Binder<'tcx, impl TypeFoldable>>, region: ty::BoundRegionKind, ) -> bool { - let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty); + let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(ty); // We are only checking is any region meets the condition so order doesn't matter #[allow(rustc::potential_query_instability)] late_bound_regions.iter().any(|r| *r == region) diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 1de2ceecae798..59d09c3dc7821 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -2,6 +2,7 @@ use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; +use rustc_type_ir::fold::TypeFoldable; use std::ops::ControlFlow; pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; @@ -109,10 +110,10 @@ impl<'tcx> TyCtxt<'tcx> { /// variables will also be equated. pub fn collect_constrained_late_bound_regions( self, - value: &Binder<'tcx, T>, + value: Binder<'tcx, T>, ) -> FxHashSet where - T: TypeVisitable>, + T: TypeFoldable>, { self.collect_late_bound_regions(value, true) } @@ -120,25 +121,26 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns a set of all late-bound regions that appear in `value` anywhere. pub fn collect_referenced_late_bound_regions( self, - value: &Binder<'tcx, T>, + value: Binder<'tcx, T>, ) -> FxHashSet where - T: TypeVisitable>, + T: TypeFoldable>, { self.collect_late_bound_regions(value, false) } fn collect_late_bound_regions( self, - value: &Binder<'tcx, T>, + value: Binder<'tcx, T>, just_constrained: bool, ) -> FxHashSet where - T: TypeVisitable>, + T: TypeFoldable>, { - let mut collector = LateBoundRegionsCollector::new(self, just_constrained); + let mut collector = LateBoundRegionsCollector::new(just_constrained); + let value = value.skip_binder(); let value = if just_constrained { self.expand_weak_alias_tys(value) } else { value }; - let result = value.as_ref().skip_binder().visit_with(&mut collector); + let result = value.visit_with(&mut collector); assert!(result.is_continue()); // should never have stopped early collector.regions } diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 8cc4201c3fc25..fbc2c3c5af459 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -318,15 +318,14 @@ where fn extract_for_generics(&self, pred: ty::Clause<'tcx>) -> FxHashSet { let bound_predicate = pred.kind(); let tcx = self.cx.tcx; - let regions = match bound_predicate.skip_binder() { - ty::ClauseKind::Trait(poly_trait_pred) => { - tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_trait_pred)) - } - ty::ClauseKind::Projection(poly_proj_pred) => { - tcx.collect_referenced_late_bound_regions(&bound_predicate.rebind(poly_proj_pred)) - } - _ => return FxHashSet::default(), - }; + let regions = + match bound_predicate.skip_binder() { + ty::ClauseKind::Trait(poly_trait_pred) => tcx + .collect_referenced_late_bound_regions(bound_predicate.rebind(poly_trait_pred)), + ty::ClauseKind::Projection(poly_proj_pred) => tcx + .collect_referenced_late_bound_regions(bound_predicate.rebind(poly_proj_pred)), + _ => return FxHashSet::default(), + }; regions .into_iter() From 1b3df6f068cb676486c511890148dbb7981b62b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 20 Feb 2024 14:29:50 +0100 Subject: [PATCH 10/12] Use expand_weak_alias_tys when collecting constrained generics params in impls --- .../src/constrained_generic_params.rs | 53 +++++++------------ .../rustc_hir_analysis/src/impl_wf_check.rs | 2 +- .../src/impl_wf_check/min_specialization.rs | 10 ++-- 3 files changed, 25 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 4ce43bb48871d..b8de2e46934dd 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -1,8 +1,8 @@ use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; +use rustc_type_ir::fold::TypeFoldable; use std::ops::ControlFlow; #[derive(Clone, PartialEq, Eq, Hash, Debug)] @@ -33,62 +33,47 @@ pub fn parameters_for_impl<'tcx>( impl_trait_ref: Option>, ) -> FxHashSet { let vec = match impl_trait_ref { - Some(tr) => parameters_for(tcx, &tr, false), - None => parameters_for(tcx, &impl_self_ty, false), + Some(tr) => parameters_for(tcx, tr, false), + None => parameters_for(tcx, impl_self_ty, false), }; vec.into_iter().collect() } /// If `include_nonconstraining` is false, returns the list of parameters that are -/// constrained by `t` - i.e., the value of each parameter in the list is -/// uniquely determined by `t` (see RFC 447). If it is true, return the list -/// of parameters whose values are needed in order to constrain `ty` - these +/// constrained by `value` - i.e., the value of each parameter in the list is +/// uniquely determined by `value` (see RFC 447). If it is true, return the list +/// of parameters whose values are needed in order to constrain `value` - these /// differ, with the latter being a superset, in the presence of projections. pub fn parameters_for<'tcx>( tcx: TyCtxt<'tcx>, - t: &impl TypeVisitable>, + value: impl TypeFoldable>, include_nonconstraining: bool, ) -> Vec { - let mut collector = - ParameterCollector { tcx, parameters: vec![], include_nonconstraining, depth: 0 }; - t.visit_with(&mut collector); + let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining }; + let value = if !include_nonconstraining { tcx.expand_weak_alias_tys(value) } else { value }; + value.visit_with(&mut collector); collector.parameters } -struct ParameterCollector<'tcx> { - tcx: TyCtxt<'tcx>, +struct ParameterCollector { parameters: Vec, include_nonconstraining: bool, - depth: usize, } -impl<'tcx> TypeVisitor> for ParameterCollector<'tcx> { +impl<'tcx> TypeVisitor> for ParameterCollector { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { match *t.kind() { + // Projections are not injective in general. ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) if !self.include_nonconstraining => { - // Projections are not injective in general. return ControlFlow::Continue(()); } - ty::Alias(ty::Weak, alias) if !self.include_nonconstraining => { - if !self.tcx.recursion_limit().value_within_limit(self.depth) { - // Other constituent types may still constrain some generic params, consider - // ` (Overflow, T)` for example. Therefore we want to continue instead of - // breaking. Only affects diagnostics. - return ControlFlow::Continue(()); - } - self.depth += 1; - return ensure_sufficient_stack(|| { - self.tcx - .type_of(alias.def_id) - .instantiate(self.tcx, alias.args) - .visit_with(self) - }); - } - ty::Param(data) => { - self.parameters.push(Parameter::from(data)); + // All weak alias types should've been expanded beforehand. + ty::Alias(ty::Weak, _) if !self.include_nonconstraining => { + bug!("unexpected weak alias type") } + ty::Param(param) => self.parameters.push(Parameter::from(param)), _ => {} } @@ -224,12 +209,12 @@ pub fn setup_constraining_predicates<'tcx>( // `<::Baz as Iterator>::Output = ::Output` // Then the projection only applies if `T` is known, but it still // does not determine `U`. - let inputs = parameters_for(tcx, &projection.projection_ty, true); + let inputs = parameters_for(tcx, projection.projection_ty, true); let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p)); if !relies_only_on_inputs { continue; } - input_parameters.extend(parameters_for(tcx, &projection.term, false)); + input_parameters.extend(parameters_for(tcx, projection.term, false)); } else { continue; } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index b4cec1d9882b6..9d7866fe3e0cb 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -111,7 +111,7 @@ fn enforce_impl_params_are_constrained( match item.kind { ty::AssocKind::Type => { if item.defaultness(tcx).has_value() { - cgp::parameters_for(tcx, &tcx.type_of(def_id).instantiate_identity(), true) + cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true) } else { vec![] } diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index bd4fce81377d4..be1be1a135407 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -133,7 +133,7 @@ fn check_always_applicable( res = res.and(check_constness(tcx, impl1_def_id, impl2_node, span)); res = res.and(check_static_lifetimes(tcx, &parent_args, span)); - res = res.and(check_duplicate_params(tcx, impl1_args, &parent_args, span)); + res = res.and(check_duplicate_params(tcx, impl1_args, parent_args, span)); res = res.and(check_predicates(tcx, impl1_def_id, impl1_args, impl2_node, impl2_args, span)); res @@ -266,15 +266,15 @@ fn unconstrained_parent_impl_args<'tcx>( continue; } - unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true)); + unconstrained_parameters.extend(cgp::parameters_for(tcx, projection_ty, true)); - for param in cgp::parameters_for(tcx, &projected_ty, false) { + for param in cgp::parameters_for(tcx, projected_ty, false) { if !unconstrained_parameters.contains(¶m) { constrained_params.insert(param.0); } } - unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true)); + unconstrained_parameters.extend(cgp::parameters_for(tcx, projected_ty, true)); } } @@ -309,7 +309,7 @@ fn unconstrained_parent_impl_args<'tcx>( fn check_duplicate_params<'tcx>( tcx: TyCtxt<'tcx>, impl1_args: GenericArgsRef<'tcx>, - parent_args: &Vec>, + parent_args: Vec>, span: Span, ) -> Result<(), ErrorGuaranteed> { let mut base_params = cgp::parameters_for(tcx, parent_args, true); From f515f99e9149b1f9c8d247b1d0fd543b1cd1fd37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 20 Feb 2024 15:08:15 +0100 Subject: [PATCH 11/12] Move the peeling function for weak alias types --- .../src/coherence/inherent_impls.rs | 29 +--------------- compiler/rustc_middle/src/ty/util.rs | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 4823472cf9617..32f312012548a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -144,7 +144,7 @@ impl<'tcx> InherentCollect<'tcx> { let id = id.owner_id.def_id; let item_span = self.tcx.def_span(id); let self_ty = self.tcx.type_of(id).instantiate_identity(); - let self_ty = peel_off_weak_aliases(self.tcx, self_ty); + let self_ty = self.tcx.peel_off_weak_alias_tys(self_ty); match *self_ty.kind() { ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()), ty::Foreign(did) => self.check_def_id(id, self_ty, did), @@ -186,30 +186,3 @@ impl<'tcx> InherentCollect<'tcx> { } } } - -/// Peel off all weak alias types in this type until there are none left. -/// -///
-/// -/// This assumes that `ty` gets normalized later and that any overflows occurring -/// during said normalization get reported. -/// -///
-fn peel_off_weak_aliases<'tcx>(tcx: TyCtxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> { - let ty::Alias(ty::Weak, _) = ty.kind() else { return ty }; - - let limit = tcx.recursion_limit(); - let mut depth = 0; - - while let ty::Alias(ty::Weak, alias) = ty.kind() { - if !limit.value_within_limit(depth) { - let guar = tcx.dcx().delayed_bug("overflow expanding weak alias type"); - return Ty::new_error(tcx, guar); - } - - ty = tcx.type_of(alias.def_id).instantiate(tcx, alias.args); - depth += 1; - } - - ty -} diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index ff9d1ed6ae995..72a1905c147ae 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -892,6 +892,39 @@ impl<'tcx> TyCtxt<'tcx> { pub fn expand_weak_alias_tys>>(self, value: T) -> T { value.fold_with(&mut WeakAliasTypeExpander { tcx: self, depth: 0 }) } + + /// Peel off all [weak alias types] in this type until there are none left. + /// + /// This only expands weak alias types in “head” / outermost positions. It can + /// be used over [expand_weak_alias_tys] as an optimization in situations where + /// one only really cares about the *kind* of the final aliased type but not + /// the types the other constituent types alias. + /// + ///
+ /// This delays a bug on overflow! Therefore you need to be certain that the + /// type gets fully normalized at a later stage. + ///
+ /// + /// [weak]: ty::Weak + /// [expand_weak_alias_tys]: Self::expand_weak_alias_tys + pub fn peel_off_weak_alias_tys(self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + let ty::Alias(ty::Weak, _) = ty.kind() else { return ty }; + + let limit = self.recursion_limit(); + let mut depth = 0; + + while let ty::Alias(ty::Weak, alias) = ty.kind() { + if !limit.value_within_limit(depth) { + let guar = self.dcx().delayed_bug("overflow expanding weak alias type"); + return Ty::new_error(self, guar); + } + + ty = self.type_of(alias.def_id).instantiate(self, alias.args); + depth += 1; + } + + ty + } } struct OpaqueTypeExpander<'tcx> { From 9ac73cbdc60bb7c32b72e9e963ed1a90da1c022f Mon Sep 17 00:00:00 2001 From: Malobre Date: Tue, 20 Feb 2024 18:05:55 +0100 Subject: [PATCH 12/12] docs: add missing "the" to `str::strip_prefix` doc --- library/core/src/str/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index e11d13f8bed16..f965a50058b1b 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2192,8 +2192,8 @@ impl str { /// Returns a string slice with the prefix removed. /// - /// If the string starts with the pattern `prefix`, returns substring after the prefix, wrapped - /// in `Some`. Unlike `trim_start_matches`, this method removes the prefix exactly once. + /// If the string starts with the pattern `prefix`, returns the substring after the prefix, + /// wrapped in `Some`. Unlike `trim_start_matches`, this method removes the prefix exactly once. /// /// If the string does not start with `prefix`, returns `None`. ///