Rollup merge of #107551 - fee1-dead-contrib:rm_const_fnmut_helper, r=oli-obk
Replace `ConstFnMutClosure` with const closures Also fixes a parser bug. cc `@oli-obk` for compiler changes
This commit is contained in:
commit
e99e05d135
12 changed files with 51 additions and 129 deletions
|
@ -2109,7 +2109,7 @@ impl<'a> Parser<'a> {
|
||||||
ClosureBinder::NotPresent
|
ClosureBinder::NotPresent
|
||||||
};
|
};
|
||||||
|
|
||||||
let constness = self.parse_constness(Case::Sensitive);
|
let constness = self.parse_closure_constness(Case::Sensitive);
|
||||||
|
|
||||||
let movability =
|
let movability =
|
||||||
if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
|
if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
|
||||||
|
|
|
@ -732,9 +732,10 @@ impl<'a> Parser<'a> {
|
||||||
fn check_const_closure(&self) -> bool {
|
fn check_const_closure(&self) -> bool {
|
||||||
self.is_keyword_ahead(0, &[kw::Const])
|
self.is_keyword_ahead(0, &[kw::Const])
|
||||||
&& self.look_ahead(1, |t| match &t.kind {
|
&& self.look_ahead(1, |t| match &t.kind {
|
||||||
token::Ident(kw::Move | kw::Static | kw::Async, _)
|
// async closures do not work with const closures, so we do not parse that here.
|
||||||
| token::OrOr
|
token::Ident(kw::Move | kw::Static, _) | token::OrOr | token::BinOp(token::Or) => {
|
||||||
| token::BinOp(token::Or) => true,
|
true
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1198,8 +1199,18 @@ impl<'a> Parser<'a> {
|
||||||
|
|
||||||
/// Parses constness: `const` or nothing.
|
/// Parses constness: `const` or nothing.
|
||||||
fn parse_constness(&mut self, case: Case) -> Const {
|
fn parse_constness(&mut self, case: Case) -> Const {
|
||||||
// Avoid const blocks to be parsed as const items
|
self.parse_constness_(case, false)
|
||||||
if self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace))
|
}
|
||||||
|
|
||||||
|
/// Parses constness for closures
|
||||||
|
fn parse_closure_constness(&mut self, case: Case) -> Const {
|
||||||
|
self.parse_constness_(case, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_constness_(&mut self, case: Case, is_closure: bool) -> Const {
|
||||||
|
// Avoid const blocks and const closures to be parsed as const items
|
||||||
|
if (self.check_const_closure() == is_closure)
|
||||||
|
&& self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace))
|
||||||
&& self.eat_keyword_case(kw::Const, case)
|
&& self.eat_keyword_case(kw::Const, case)
|
||||||
{
|
{
|
||||||
Const::Yes(self.prev_token.uninterpolated_span())
|
Const::Yes(self.prev_token.uninterpolated_span())
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
|
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
use crate::const_closure::ConstFnMutClosure;
|
|
||||||
use crate::marker::Destruct;
|
use crate::marker::Destruct;
|
||||||
|
|
||||||
use self::Ordering::*;
|
use self::Ordering::*;
|
||||||
|
@ -1291,17 +1290,7 @@ where
|
||||||
F: ~const Destruct,
|
F: ~const Destruct,
|
||||||
K: ~const Destruct,
|
K: ~const Destruct,
|
||||||
{
|
{
|
||||||
const fn imp<T, F: ~const FnMut(&T) -> K, K: ~const Ord>(
|
max_by(v1, v2, const |v1, v2| f(v1).cmp(&f(v2)))
|
||||||
f: &mut F,
|
|
||||||
(v1, v2): (&T, &T),
|
|
||||||
) -> Ordering
|
|
||||||
where
|
|
||||||
T: ~const Destruct,
|
|
||||||
K: ~const Destruct,
|
|
||||||
{
|
|
||||||
f(v1).cmp(&f(v2))
|
|
||||||
}
|
|
||||||
max_by(v1, v2, ConstFnMutClosure::new(&mut f, imp))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
|
// Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
use crate::marker::Destruct;
|
|
||||||
use crate::marker::Tuple;
|
|
||||||
|
|
||||||
/// Struct representing a closure with mutably borrowed data.
|
|
||||||
///
|
|
||||||
/// Example:
|
|
||||||
/// ```no_build
|
|
||||||
/// #![feature(const_mut_refs)]
|
|
||||||
/// use crate::const_closure::ConstFnMutClosure;
|
|
||||||
/// const fn imp(state: &mut i32, (arg,): (i32,)) -> i32 {
|
|
||||||
/// *state += arg;
|
|
||||||
/// *state
|
|
||||||
/// }
|
|
||||||
/// let mut i = 5;
|
|
||||||
/// let mut cl = ConstFnMutClosure::new(&mut i, imp);
|
|
||||||
///
|
|
||||||
/// assert!(7 == cl(2));
|
|
||||||
/// assert!(8 == cl(1));
|
|
||||||
/// ```
|
|
||||||
pub(crate) struct ConstFnMutClosure<CapturedData, Function> {
|
|
||||||
/// The Data captured by the Closure.
|
|
||||||
/// Must be either a (mutable) reference or a tuple of (mutable) references.
|
|
||||||
pub data: CapturedData,
|
|
||||||
/// The Function of the Closure, must be: Fn(CapturedData, ClosureArgs) -> ClosureReturn
|
|
||||||
pub func: Function,
|
|
||||||
}
|
|
||||||
impl<'a, CapturedData: ?Sized, Function> ConstFnMutClosure<&'a mut CapturedData, Function> {
|
|
||||||
/// Function for creating a new closure.
|
|
||||||
///
|
|
||||||
/// `data` is the a mutable borrow of data that is captured from the environment.
|
|
||||||
/// If you want Data to be a tuple of mutable Borrows, the struct must be constructed manually.
|
|
||||||
///
|
|
||||||
/// `func` is the function of the closure, it gets the data and a tuple of the arguments closure
|
|
||||||
/// and return the return value of the closure.
|
|
||||||
pub(crate) const fn new<ClosureArguments, ClosureReturnValue>(
|
|
||||||
data: &'a mut CapturedData,
|
|
||||||
func: Function,
|
|
||||||
) -> Self
|
|
||||||
where
|
|
||||||
Function: ~const Fn(&mut CapturedData, ClosureArguments) -> ClosureReturnValue,
|
|
||||||
{
|
|
||||||
Self { data, func }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_fn_mut_tuple {
|
|
||||||
($($var:ident)*) => {
|
|
||||||
#[allow(unused_parens)]
|
|
||||||
impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
|
|
||||||
FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
|
|
||||||
where
|
|
||||||
Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue+ ~const Destruct,
|
|
||||||
{
|
|
||||||
type Output = ClosureReturnValue;
|
|
||||||
|
|
||||||
extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Output {
|
|
||||||
self.call_mut(args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[allow(unused_parens)]
|
|
||||||
impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
|
|
||||||
FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
|
|
||||||
where
|
|
||||||
Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue,
|
|
||||||
{
|
|
||||||
extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output {
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
let ($($var),*) = &mut self.data;
|
|
||||||
(self.func)(($($var),*), args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
impl_fn_mut_tuple!(A);
|
|
||||||
impl_fn_mut_tuple!(A B);
|
|
||||||
impl_fn_mut_tuple!(A B C);
|
|
||||||
impl_fn_mut_tuple!(A B C D);
|
|
||||||
impl_fn_mut_tuple!(A B C D E);
|
|
|
@ -1,5 +1,4 @@
|
||||||
use crate::array;
|
use crate::array;
|
||||||
use crate::const_closure::ConstFnMutClosure;
|
|
||||||
use crate::iter::{ByRefSized, FusedIterator, Iterator, TrustedRandomAccessNoCoerce};
|
use crate::iter::{ByRefSized, FusedIterator, Iterator, TrustedRandomAccessNoCoerce};
|
||||||
use crate::mem::{self, MaybeUninit};
|
use crate::mem::{self, MaybeUninit};
|
||||||
use crate::ops::{ControlFlow, NeverShortCircuit, Try};
|
use crate::ops::{ControlFlow, NeverShortCircuit, Try};
|
||||||
|
@ -189,13 +188,12 @@ where
|
||||||
I: Iterator,
|
I: Iterator,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
default fn fold<B, F>(mut self, init: B, mut f: F) -> B
|
default fn fold<B, F>(mut self, init: B, f: F) -> B
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
F: FnMut(B, Self::Item) -> B,
|
F: FnMut(B, Self::Item) -> B,
|
||||||
{
|
{
|
||||||
let fold = ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp);
|
self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0
|
||||||
self.try_fold(init, fold).0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
use crate::{
|
use crate::ops::{NeverShortCircuit, Try};
|
||||||
const_closure::ConstFnMutClosure,
|
|
||||||
ops::{NeverShortCircuit, Try},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics.
|
/// Like `Iterator::by_ref`, but requiring `Sized` so it can forward generics.
|
||||||
///
|
///
|
||||||
|
@ -39,13 +36,12 @@ impl<I: Iterator> Iterator for ByRefSized<'_, I> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fold<B, F>(self, init: B, mut f: F) -> B
|
fn fold<B, F>(self, init: B, f: F) -> B
|
||||||
where
|
where
|
||||||
F: FnMut(B, Self::Item) -> B,
|
F: FnMut(B, Self::Item) -> B,
|
||||||
{
|
{
|
||||||
// `fold` needs ownership, so this can't forward directly.
|
// `fold` needs ownership, so this can't forward directly.
|
||||||
I::try_fold(self.0, init, ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp))
|
I::try_fold(self.0, init, NeverShortCircuit::wrap_mut_2(f)).0
|
||||||
.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -76,17 +72,12 @@ impl<I: DoubleEndedIterator> DoubleEndedIterator for ByRefSized<'_, I> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn rfold<B, F>(self, init: B, mut f: F) -> B
|
fn rfold<B, F>(self, init: B, f: F) -> B
|
||||||
where
|
where
|
||||||
F: FnMut(B, Self::Item) -> B,
|
F: FnMut(B, Self::Item) -> B,
|
||||||
{
|
{
|
||||||
// `rfold` needs ownership, so this can't forward directly.
|
// `rfold` needs ownership, so this can't forward directly.
|
||||||
I::try_rfold(
|
I::try_rfold(self.0, init, NeverShortCircuit::wrap_mut_2(f)).0
|
||||||
self.0,
|
|
||||||
init,
|
|
||||||
ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp),
|
|
||||||
)
|
|
||||||
.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -362,15 +362,13 @@ macro_rules! impl_fold_via_try_fold {
|
||||||
};
|
};
|
||||||
(@internal $fold:ident -> $try_fold:ident) => {
|
(@internal $fold:ident -> $try_fold:ident) => {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn $fold<AAA, FFF>(mut self, init: AAA, mut fold: FFF) -> AAA
|
fn $fold<AAA, FFF>(mut self, init: AAA, fold: FFF) -> AAA
|
||||||
where
|
where
|
||||||
FFF: FnMut(AAA, Self::Item) -> AAA,
|
FFF: FnMut(AAA, Self::Item) -> AAA,
|
||||||
{
|
{
|
||||||
use crate::const_closure::ConstFnMutClosure;
|
|
||||||
use crate::ops::NeverShortCircuit;
|
use crate::ops::NeverShortCircuit;
|
||||||
|
|
||||||
let fold = ConstFnMutClosure::new(&mut fold, NeverShortCircuit::wrap_mut_2_imp);
|
self.$try_fold(init, NeverShortCircuit::wrap_mut_2(fold)).0
|
||||||
self.$try_fold(init, fold).0
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -376,8 +376,6 @@ mod bool;
|
||||||
mod tuple;
|
mod tuple;
|
||||||
mod unit;
|
mod unit;
|
||||||
|
|
||||||
mod const_closure;
|
|
||||||
|
|
||||||
#[stable(feature = "core_primitive", since = "1.43.0")]
|
#[stable(feature = "core_primitive", since = "1.43.0")]
|
||||||
pub mod primitive;
|
pub mod primitive;
|
||||||
|
|
||||||
|
|
|
@ -379,13 +379,18 @@ pub(crate) type ChangeOutputType<T, V> = <<T as Try>::Residual as Residual<V>>::
|
||||||
pub(crate) struct NeverShortCircuit<T>(pub T);
|
pub(crate) struct NeverShortCircuit<T>(pub T);
|
||||||
|
|
||||||
impl<T> NeverShortCircuit<T> {
|
impl<T> NeverShortCircuit<T> {
|
||||||
/// Implementation for building `ConstFnMutClosure` for wrapping the output of a ~const FnMut in a `NeverShortCircuit`.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn wrap_mut_2_imp<A, B, F: ~const FnMut(A, B) -> T>(
|
pub fn wrap_mut_2<A, B>(
|
||||||
f: &mut F,
|
mut f: impl ~const FnMut(A, B) -> T,
|
||||||
(a, b): (A, B),
|
) -> impl ~const FnMut(A, B) -> Self {
|
||||||
) -> NeverShortCircuit<T> {
|
cfg_if! {
|
||||||
NeverShortCircuit(f(a, b))
|
if #[cfg(bootstrap)] {
|
||||||
|
#[allow(unused_parens)]
|
||||||
|
(const move |a, b| NeverShortCircuit(f(a, b)))
|
||||||
|
} else {
|
||||||
|
const move |a, b| NeverShortCircuit(f(a, b))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,6 @@ fn main() {
|
||||||
enum Foo { Bar }
|
enum Foo { Bar }
|
||||||
fn foo(x: impl Iterator<Item = Foo>) {
|
fn foo(x: impl Iterator<Item = Foo>) {
|
||||||
for <Foo>::Bar in x {}
|
for <Foo>::Bar in x {}
|
||||||
//~^ ERROR expected one of `const`, `move`, `static`, `|`
|
//~^ ERROR expected one of `move`, `static`, `|`
|
||||||
//~^^ ERROR `for<...>` binders for closures are experimental
|
//~^^ ERROR `for<...>` binders for closures are experimental
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `const`, `move`, `static`, `|`, or `||`, found `::`
|
error: expected one of `move`, `static`, `|`, or `||`, found `::`
|
||||||
--> $DIR/recover-quantified-closure.rs:9:14
|
--> $DIR/recover-quantified-closure.rs:9:14
|
||||||
|
|
|
|
||||||
LL | for <Foo>::Bar in x {}
|
LL | for <Foo>::Bar in x {}
|
||||||
| ^^ expected one of `const`, `move`, `static`, `|`, or `||`
|
| ^^ expected one of `move`, `static`, `|`, or `||`
|
||||||
|
|
||||||
error[E0658]: `for<...>` binders for closures are experimental
|
error[E0658]: `for<...>` binders for closures are experimental
|
||||||
--> $DIR/recover-quantified-closure.rs:2:5
|
--> $DIR/recover-quantified-closure.rs:2:5
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![feature(const_trait_impl, const_closures)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
const fn test() -> impl ~const Fn() {
|
||||||
|
const move || {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue