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

"the trait Clone is not implemented for the type fn(&mut Foo, …) #24000

Closed
SimonSapin opened this issue Apr 3, 2015 · 20 comments
Closed

"the trait Clone is not implemented for the type fn(&mut Foo, …) #24000

SimonSapin opened this issue Apr 3, 2015 · 20 comments
Labels
A-type-system Area: Type system C-bug Category: This is a bug.

Comments

@SimonSapin
Copy link
Contributor

Upgrading rust-encoding to Rust beta, I hit this error message:

/// A type of the bare function in `DecoderTrap` values.
#[unstable]
pub type DecoderTrapFunc =
    extern "Rust" fn(decoder: &mut RawDecoder, input: &[u8], output: &mut StringWriter) -> bool;

/// Trap, which handles decoder errors.
#[stable]
#[derive(Copy, Clone)]
pub enum DecoderTrap {
    /// Immediately fails on errors.
    /// Corresponds to WHATWG "fatal" error algorithm.
    Strict,
    /// Replaces an error with a U+FFFD (decoder).
    /// Corresponds to WHATWG "replacement" error algorithm.
    Replace,
    /// Silently ignores an error, effectively replacing it with an empty sequence.
    Ignore,
    /// Calls given function to handle decoder errors.
    /// The function is given the current decoder, input and output writer,
    /// and should return true only when it is fine to keep going.
    #[unstable] Call(DecoderTrapFunc),
}
src/types.rs:380:22: 380:37 error: the trait `core::clone::Clone` is not implemented for the type `fn(&'a mut types::RawDecoder, &'b [u8], &'c mut types::StringWriter + 'c) -> bool` [E0277]
src/types.rs:380     #[unstable] Call(DecoderTrapFunc),
                                      ^~~~~~~~~~~~~~~
src/types.rs:367:16: 367:21 note: in expansion of #[derive_Clone]
src/types.rs:367:16: 367:21 note: expansion site

Shouldn’t this fn type implement Clone? It seems to implement Copy.

@nikomatsakis
Copy link
Contributor

I think the best plan for fixing this is specialization, which would allow us to add a low-priority, overridable impl like:

impl<T:Copy> Clone for T { .. }

@Florob
Copy link
Contributor

Florob commented Apr 3, 2015

This is likely a more general problem for types where the compiler itself determines they are Copy. I.e. I have also run into this with [T; N] where T: Copy.

@steveklabnik steveklabnik added the A-type-system Area: Type system label Apr 3, 2015
@nikomatsakis
Copy link
Contributor

@Florob more accurately, it is a problem for those cases where we don't (and can't, atm) have complete Clone impls.

@nikomatsakis
Copy link
Contributor

(but I guess that's more or less the same thing as what you wrote, on second thought.)

@dgrunwald
Copy link
Contributor

Note that the lack of Clone impls for Copy types can cause internal compiler errors:

fn test<T: Copy>(x: T) { x.clone(); }
fn main() { test(main); }

error: internal compiler error: Encountered error Unimplemented selecting Binder(core::clone::Clone) during trans

@nikomatsakis
Copy link
Contributor

@dgrunwald oh, that's... not very good at all! that kind of ups the urgency of finding a good fix for this.

@nikomatsakis
Copy link
Contributor

(though if we have to hack up something to fix the ICE, we could.)

@huonw
Copy link
Member

huonw commented May 6, 2015

This problem also applies to fixed sized arrays, e.g. @dgrunwald's example

fn test<T: Copy>(x: T) { x.clone(); }
fn main() { test([0; 1000]); }
<anon>:2:6: 2:15 error: internal compiler error: Encountered error `Unimplemented` selecting `Binder(core::clone::Clone)` during trans
<anon>:2      x.clone();
              ^~~~~~~~~

@DanielKeep
Copy link
Contributor

Ran into this just now helping someone with cloneable iterators. Turns out that you can't clone a Filter due to fns not being cloneable. Also, just to be clear, functions definitely implement Copy, but don't implement Clone.

@SimonSapin
Copy link
Contributor Author

I ran into this again with code like this:

let runs: Vec<Range<usize>> = /* ... */;
let mut iter = runs.iter().flat_map(Clone::clone);

When trying to clone iter later in the same function, I got this error message:

error: no method named `clone` found for type `core::iter::FlatMap<core::slice::Iter<'_, core::ops::Range<usize>>, core::ops::Range<usize>, fn(&core::ops::Range<usize>) -> core::ops::Range<usize> {core::clone::Clone::clone}>` in the current scope

FlatMap does implement Clone, but it’s derived and requires all type parameters to be Clone as well. I tried .flat_map(|x| x.clone()) but closures are apparently not Clone. With @eddyb’s help on IRC, the only way we found to have both FnMut and Clone on stable Rust with as fn(...):

let runs: Vec<Range<usize>> = /* ... */;
fn id(x: Range<usize>) -> Range<usize> { x }
let mut iter = runs.iter().cloned().flat_map(id as fn(x: Range<usize>) -> Range<usize>);

It’d be helpful if closure types were Clone whenever possible. (So, I think, for move closures when all captured values are Clone as well, for non-move closures when they implement Fn.)

@bluss
Copy link
Member

bluss commented Jul 13, 2015

@DanielKeep @SimonSapin You can clone a Map iterator with a fn pointer, but not a Filter.. :-( This since fn(T) -> R is Clone but not fn<'a>(&'a T) -> R

Best solution is probably @nikomatsakis idea of somehow providing Clone for everything that's Copy.

@steveklabnik
Copy link
Member

steveklabnik commented Jan 3, 2017

Minimal reproduction here:

fn foo() {}

fn main() {
    Clone::clone(&foo);
}

@Mark-Simulacrum Mark-Simulacrum added the C-bug Category: This is a bug. label Jul 22, 2017
bors added a commit that referenced this issue Aug 22, 2017
Generate builtin impls for `Clone`

This fixes a long-standing ICE and limitation where some builtin types implement `Copy` but not `Clone` (whereas `Clone` is a super trait of `Copy`).

However, this PR has a few side-effects:
* `Clone` is now marked as a lang item.
* `[T; N]` is now `Clone` if `T: Clone` (currently, only if `T: Copy` and for `N <= 32`).
* `fn foo<'a>() where &'a mut (): Clone { }` won't compile anymore because of how bounds for builtin traits are handled (e.g. same thing currently if you replace `Clone` by `Copy` in this example). Of course this function is unusable anyway, an error would pop as soon as it is called.

Hence, I'm wondering wether this PR would need an RFC...
Also, cc-ing @nikomatsakis, @arielb1.

Related issues: #28229, #24000.
@bors bors closed this as completed in 0c3ac64 Aug 22, 2017
@TheZoq2
Copy link
Contributor

TheZoq2 commented Sep 21, 2017

Correct me if im wrong, but shouldn't this being fixed mean that the following code should compile?

type Function = Fn(i32) -> i32;

#[derive(Clone)]
struct FunctionContainer {
    function: Box<Function>
}

fn main() {
}

As you can see here, the code does not compile on the latest nightly version https://play.rust-lang.org/?gist=dd13b37b72d2a3a9cc48229654c18036&version=nightly

@SimonSapin
Copy link
Contributor Author

SimonSapin commented Sep 21, 2017

@TheZoq2 This is about fn() (lower-case) function pointer types. #44490 is about Fn() (upper-case) trait object dynamically-sized types.

@bluss
Copy link
Member

bluss commented Sep 21, 2017

@TheZoq2, note the difference between lowercase fn and Fn in Rust. The latter is a closure trait. Cloning trait objects is by the way a much trickier subject.

@TheZoq2
Copy link
Contributor

TheZoq2 commented Sep 21, 2017

Ah, that makes sense, thank you for the clarification

@SimonSapin
Copy link
Contributor Author

Wait no, #44490 is about closure types (which are anonymous). For your code to compile with trait objects I think it’d also need to mention a Clone bound explicitly, but trait Function: Fn(i32) -> i32 + Clone {} with Box<Function> gives another error message.

@eddyb
Copy link
Member

eddyb commented Sep 21, 2017

@SimonSapin This is a relatively common Rust question and the solutions are typically more involved than that - you basically need to have a -> Box<Function> method, and Clone can't give you that.

@SimonSapin
Copy link
Contributor Author

@RogueGod What do you mean by “this”? This issue is about function pointer types specifically. A reduced test case is:

#[derive(Clone)]
struct Foo(fn(&mut u32));

Or:

fn foo(function_pointer: fn(&mut u32)) {
    Clone::clone(&function_pointer);
}

Both of these examples would cause error: the trait `core::clone::Clone` is not implemented for the type `fn(&'a mut u32)` in old rustc versions. This was fixed year ago.

@KamilaBorowska
Copy link
Contributor

KamilaBorowska commented Apr 3, 2019

@TheZoq2 This does compile.

#[derive(Clone)]
struct FunctionContainer {
    function: Box<dyn Function>,
}

trait Function: Fn(i32) -> i32 {
    fn clone_boxed(&self) -> Box<dyn Function>;
}

impl<T> Function for T
where
    T: 'static + Clone + Fn(i32) -> i32,
{
    fn clone_boxed(&self) -> Box<dyn Function> {
        Box::new(self.clone())
    }
}

impl Clone for Box<dyn Function> {
    fn clone(&self) -> Self {
        self.clone_boxed()
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-type-system Area: Type system C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests