Rollup merge of #125362 - joboet:tait_hack, r=Nilstrieb

Actually use TAIT instead of emulating it

`core`'s `impl_fn_for_zst` macro is just a hacky way of emulating TAIT. TAIT has become stable enough to be used [in other places](e8fbd99128/library/std/src/backtrace.rs (L431)) inside the standard library, so let's use it in `core` as well.
This commit is contained in:
Guillaume Gomez 2024-05-23 23:39:27 +02:00 committed by GitHub
commit 1e4bde1cb9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 44 additions and 117 deletions

View file

@ -80,47 +80,6 @@ fn $method(&mut self, other: &$u) {
}
}
/// Create a zero-size type similar to a closure type, but named.
macro_rules! impl_fn_for_zst {
($(
$( #[$attr: meta] )*
struct $Name: ident impl$( <$( $lifetime : lifetime ),+> )? Fn =
|$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty
$body: block;
)+) => {
$(
$( #[$attr] )*
struct $Name;
impl $( <$( $lifetime ),+> )? Fn<($( $ArgTy, )*)> for $Name {
#[inline]
extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
$body
}
}
impl $( <$( $lifetime ),+> )? FnMut<($( $ArgTy, )*)> for $Name {
#[inline]
extern "rust-call" fn call_mut(
&mut self,
($( $arg, )*): ($( $ArgTy, )*)
) -> $ReturnTy {
Fn::call(&*self, ($( $arg, )*))
}
}
impl $( <$( $lifetime ),+> )? FnOnce<($( $ArgTy, )*)> for $Name {
type Output = $ReturnTy;
#[inline]
extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy {
Fn::call(&self, ($( $arg, )*))
}
}
)+
}
}
/// A macro for defining `#[cfg]` if-else statements.
///
/// `cfg_if` is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade

View file

@ -255,6 +255,7 @@
#![feature(trait_alias)]
#![feature(transparent_unions)]
#![feature(try_blocks)]
#![feature(type_alias_impl_trait)]
#![feature(unboxed_closures)]
#![feature(unsized_fn_params)]
#![feature(with_negative_coherence)]

View file

@ -108,7 +108,7 @@ pub fn make_ascii_lowercase(&mut self) {
without modifying the original"]
#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
pub fn escape_ascii(&self) -> EscapeAscii<'_> {
EscapeAscii { inner: self.iter().flat_map(EscapeByte) }
EscapeAscii { inner: self.iter().flat_map(|byte| byte.escape_ascii()) }
}
/// Returns a byte slice with leading ASCII whitespace bytes removed.
@ -190,12 +190,7 @@ pub const fn trim_ascii(&self) -> &[u8] {
}
}
impl_fn_for_zst! {
#[derive(Clone)]
struct EscapeByte impl Fn = |byte: &u8| -> ascii::EscapeDefault {
ascii::escape_default(*byte)
};
}
type EscapeByte = impl (Fn(&u8) -> ascii::EscapeDefault) + Copy;
/// An iterator over the escaped version of a byte slice.
///

View file

@ -1274,8 +1274,10 @@ pub struct SplitWhitespace<'a> {
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
#[derive(Clone, Debug)]
pub struct SplitAsciiWhitespace<'a> {
pub(super) inner:
Map<Filter<SliceSplit<'a, u8, IsAsciiWhitespace>, BytesIsNotEmpty>, UnsafeBytesToStr>,
pub(super) inner: Map<
Filter<SliceSplit<'a, u8, IsAsciiWhitespace>, BytesIsNotEmpty<'a>>,
UnsafeBytesToStr<'a>,
>,
}
/// An iterator over the substrings of a string,

View file

@ -983,7 +983,7 @@ pub fn bytes(&self) -> Bytes<'_> {
#[cfg_attr(not(test), rustc_diagnostic_item = "str_split_whitespace")]
#[inline]
pub fn split_whitespace(&self) -> SplitWhitespace<'_> {
SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) }
SplitWhitespace { inner: self.split(char::is_whitespace).filter(|s| !s.is_empty()) }
}
/// Splits a string slice by ASCII whitespace.
@ -1032,8 +1032,13 @@ pub fn split_whitespace(&self) -> SplitWhitespace<'_> {
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
#[inline]
pub fn split_ascii_whitespace(&self) -> SplitAsciiWhitespace<'_> {
let inner =
self.as_bytes().split(IsAsciiWhitespace).filter(BytesIsNotEmpty).map(UnsafeBytesToStr);
let inner = self
.as_bytes()
.split(u8::is_ascii_whitespace)
.filter(|s| !s.is_empty())
// SAFETY: the byte slice came from a string and was only split
// along character boundaries, so the resulting slices are strings.
.map(|bytes| unsafe { from_utf8_unchecked(bytes) });
SplitAsciiWhitespace { inner }
}
@ -1085,7 +1090,11 @@ pub fn split_ascii_whitespace(&self) -> SplitAsciiWhitespace<'_> {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn lines(&self) -> Lines<'_> {
Lines(self.split_inclusive('\n').map(LinesMap))
Lines(self.split_inclusive('\n').map(|line| {
let Some(line) = line.strip_suffix('\n') else { return line };
let Some(line) = line.strip_suffix('\r') else { return line };
line
}))
}
/// An iterator over the lines of a string.
@ -2636,14 +2645,19 @@ pub const fn trim_ascii(&self) -> &str {
#[stable(feature = "str_escape", since = "1.34.0")]
pub fn escape_debug(&self) -> EscapeDebug<'_> {
let mut chars = self.chars();
EscapeDebug {
inner: chars
.next()
.map(|first| first.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL))
.into_iter()
.flatten()
.chain(chars.flat_map(CharEscapeDebugContinue)),
}
let first = chars
.next()
.map(|first| first.escape_debug_ext(EscapeDebugExtArgs::ESCAPE_ALL))
.into_iter()
.flatten();
let inner = first.chain(chars.flat_map(|c| {
c.escape_debug_ext(EscapeDebugExtArgs {
escape_grapheme_extended: false,
escape_single_quote: true,
escape_double_quote: true,
})
}));
EscapeDebug { inner }
}
/// Return an iterator that escapes each char in `self` with [`char::escape_default`].
@ -2681,7 +2695,7 @@ pub fn escape_debug(&self) -> EscapeDebug<'_> {
without modifying the original"]
#[stable(feature = "str_escape", since = "1.34.0")]
pub fn escape_default(&self) -> EscapeDefault<'_> {
EscapeDefault { inner: self.chars().flat_map(CharEscapeDefault) }
EscapeDefault { inner: self.chars().flat_map(char::escape_default) }
}
/// Return an iterator that escapes each char in `self` with [`char::escape_unicode`].
@ -2719,7 +2733,7 @@ pub fn escape_default(&self) -> EscapeDefault<'_> {
without modifying the original"]
#[stable(feature = "str_escape", since = "1.34.0")]
pub fn escape_unicode(&self) -> EscapeUnicode<'_> {
EscapeUnicode { inner: self.chars().flat_map(CharEscapeUnicode) }
EscapeUnicode { inner: self.chars().flat_map(char::escape_unicode) }
}
}
@ -2750,59 +2764,15 @@ fn default() -> Self {
}
}
impl_fn_for_zst! {
/// A nameable, cloneable fn type
#[derive(Clone)]
struct LinesMap impl<'a> Fn = |line: &'a str| -> &'a str {
let Some(line) = line.strip_suffix('\n') else { return line };
let Some(line) = line.strip_suffix('\r') else { return line };
line
};
#[derive(Clone)]
struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug {
c.escape_debug_ext(EscapeDebugExtArgs {
escape_grapheme_extended: false,
escape_single_quote: true,
escape_double_quote: true
})
};
#[derive(Clone)]
struct CharEscapeUnicode impl Fn = |c: char| -> char::EscapeUnicode {
c.escape_unicode()
};
#[derive(Clone)]
struct CharEscapeDefault impl Fn = |c: char| -> char::EscapeDefault {
c.escape_default()
};
#[derive(Clone)]
struct IsWhitespace impl Fn = |c: char| -> bool {
c.is_whitespace()
};
#[derive(Clone)]
struct IsAsciiWhitespace impl Fn = |byte: &u8| -> bool {
byte.is_ascii_whitespace()
};
#[derive(Clone)]
struct IsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b str| -> bool {
!s.is_empty()
};
#[derive(Clone)]
struct BytesIsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b [u8]| -> bool {
!s.is_empty()
};
#[derive(Clone)]
struct UnsafeBytesToStr impl<'a> Fn = |bytes: &'a [u8]| -> &'a str {
// SAFETY: not safe
unsafe { from_utf8_unchecked(bytes) }
};
}
type LinesMap = impl (Fn(&str) -> &str) + Copy;
type CharEscapeDebugContinue = impl (FnMut(char) -> char::EscapeDebug) + Copy;
type CharEscapeUnicode = impl (Fn(char) -> char::EscapeUnicode) + Copy;
type CharEscapeDefault = impl (Fn(char) -> char::EscapeDefault) + Copy;
type IsWhitespace = impl (Fn(char) -> bool) + Copy;
type IsAsciiWhitespace = impl (Fn(&u8) -> bool) + Copy;
type IsNotEmpty = impl (Fn(&&str) -> bool) + Copy;
type BytesIsNotEmpty<'a> = impl (FnMut(&&'a [u8]) -> bool) + Copy;
type UnsafeBytesToStr<'a> = impl (FnMut(&'a [u8]) -> &'a str) + Copy;
// This is required to make `impl From<&str> for Box<dyn Error>` and `impl<E> From<E> for Box<dyn Error>` not overlap.
#[stable(feature = "rust1", since = "1.0.0")]