Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recursive closure combinator no longer allowed in nightly #46277

Closed
bluss opened this issue Nov 26, 2017 · 4 comments
Closed

Recursive closure combinator no longer allowed in nightly #46277

bluss opened this issue Nov 26, 2017 · 4 comments
Labels
A-typesystem Area: The type system regression-from-stable-to-nightly Performance or correctness regression from stable to nightly.

Comments

@bluss
Copy link
Member

bluss commented Nov 26, 2017

The following code (published in odds 0.3) compiles and works(?) in stable but not nightly.

The combinator is using a closure where the first argument contains a reference to its own type.

(playground link)

use std::marker::PhantomData;

fn main() {
    let data = [true, false];
    assert!(!fix(&data[..], |f, x| {
       x.len() == 0 || x[0] && f.call(&x[1..])
    }));
}

pub struct Fix<'a, F: 'a, T: 'a, R: 'a = T>(&'a F, PhantomData<fn(T) -> R>);

impl<'a, F, T, R> Fix<'a, F, T, R>
    where F: Fn(Fix<F, T, R>, T) -> R,
{
    /// Create a new fix from the reference to closure `f`
    pub fn new(f: &'a F) -> Self {
        Fix(f, PhantomData)
    }
}

/// Fixpoint combinator for rust closures, generalized over the return type.
///
/// This is a wrapper function that uses the `Fix` type. The recursive closure
/// has two arguments, `Fix` and the argument type `T`.
///
/// In **Fix\<T, R\>**, **T** is the argument type, and **R** is the return type,
/// **R** defaults to **T**.
///
/// Calling the `Fix` value only supports function call notation with the nightly
/// channel and the crate feature ‘unstable’ enabled; use the .call() method otherwise.
///
/// This helper function makes the type inference work out well.
///
/// ```
/// use odds::fix;
/// 
/// assert_eq!(120, fix(5, |f, x| if x == 0 { 1 } else { x * f.call(x - 1) }));
///
/// let data = [true, false];
/// assert!(!fix(&data[..], |f, x| {
///     x.len() == 0 || x[0] && f.call(&x[1..])
/// }));
///
/// ```

pub fn fix<T, R, F>(init: T, closure: F) -> R
    where F: Fn(Fix<F, T, R>, T) -> R
{
    Fix(&closure, PhantomData).call(init)
}

impl<'a, F, T, R> Fix<'a, F, T, R>
    where F: Fn(Fix<F, T, R>, T) -> R,
{
    /// Call the fix using the argument `arg`
    pub fn call(&self, arg: T) -> R {
        let f = *self;
        f.0(f, arg)
    }
}

impl<'a, F, T, R> Clone for Fix<'a, F, T, R> {
    fn clone(&self) -> Self { *self }
}

impl<'a, F, T, R> Copy for Fix<'a, F, T, R> { }
@bluss bluss added A-typesystem Area: The type system regression-from-stable-to-nightly Performance or correctness regression from stable to nightly. labels Nov 26, 2017
@petrochenkov
Copy link
Contributor

#46062?

@bluss
Copy link
Member Author

bluss commented Nov 26, 2017

I guess odds 0.3 must have been published after the crater run but before the nightly change. It's a change we had implemented back in May 2017. It would be great if it could be allowed in static dispatch, but odds could go back to the old &Fn version of fix.

@arielb1 arielb1 closed this as completed Nov 26, 2017
@arielb1
Copy link
Contributor

arielb1 commented Nov 26, 2017

According to @nikomatsakis, recursive closures were a pirate feature that was never supposed to be implemented, and they make lifetime inference much more fragile. Therefore, we have decided to stop supporting them for the new more-robust closure lifetime inference scheme that comes with NLL.

@bluss
Copy link
Member Author

bluss commented Nov 26, 2017

pirate feature

🛥 ☠️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-typesystem Area: The type system regression-from-stable-to-nightly Performance or correctness regression from stable to nightly.
Projects
None yet
Development

No branches or pull requests

3 participants