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

functions implement Copy but not Clone #28229

Closed
fuchsnj opened this issue Sep 4, 2015 · 25 comments
Closed

functions implement Copy but not Clone #28229

fuchsnj opened this issue Sep 4, 2015 · 25 comments
Labels
A-typesystem Area: The type system C-bug Category: This is a bug. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-low Low priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@fuchsnj
Copy link

fuchsnj commented Sep 4, 2015

This compiles

fn func(){}

fn main(){
    run(func);
    run(func);
}

fn run<T>(f: T)
where T: Fn() + Copy{
    f();
}

but this does not (playground)

fn func(){}

fn main(){
    run(func);
    run(func);
}

fn run<T>(f: T)
where T: Fn() + Clone{
    f();
}

The only difference is the bounds on T. The Copy trait requires that the Clone trait is also implemented, so I believe both of these should compile.

@jonas-schievink
Copy link
Contributor

Even worse, because Copy usually implies Clone, this ICE's:

fn c<T: Copy>(t: T) -> (T, T) { (t.clone(), t) }

fn f() {}

fn main() {
    c(0);
    c(f);
}
<anon>:1:34: 1:43 error: internal compiler error: Encountered error `Unimplemented` selecting `Binder(<fn() {f} as core::clone::Clone>)` during trans
<anon>:1 fn c<T: Copy>(t: T) -> (T, T) { (t.clone(), t) }
                                          ^~~~~~~~~

This (including the ICE) was already reported in #24000, so this looks like a duplicate

@alexcrichton
Copy link
Member

Nominating as this seems relatively serious, but the failure mode is just an ICE then it doesn't seem super super pressing.

@alexcrichton alexcrichton added I-nominated T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Sep 4, 2015
@arielb1
Copy link
Contributor

arielb1 commented Sep 4, 2015

@nikomatsakis: should we make Clone a lang-item? I think it being a supertrait of Copy forces our hand.

@eefriedman
Copy link
Contributor

We could just add something like the following to the libcore, I think:

impl<R> Clone for fn() -> R {
    fn clone(&self) -> Self { self }
}
impl<R, A1> Clone for fn(A1) -> R {
    fn clone(&self) -> Self { self }
}
impl<R, A1, A2> Clone for fn(A1, A2) -> R {
    fn clone(&self) -> Self { self }
}
impl<R, A1, A2, A3> Clone for fn(A1, A2, A3) -> R {
    fn clone(&self) -> Self { self }
}

We do exactly the same thing for arrays.

@eefriedman
Copy link
Contributor

Err, nevermind, that doesn't really do the right thing: that only works for function pointers, not function definitions.

@nagisa
Copy link
Member

nagisa commented Sep 4, 2015

impl<T: Copy> Clone for T?

I’m pretty sure this cannot be done backwards compatibly because such impl would conflict with all the explicit impl Clones, but still had to mention it 😊

@huonw
Copy link
Member

huonw commented Sep 4, 2015

@nagisa it should be fine with specialisation.

@arielb1
Copy link
Contributor

arielb1 commented Sep 5, 2015

@huonw

It would be fine with lattice impls. Which is a different feature from specialization. Actually, even that wouldn't be backwards-compatible, given that you would need to provide the meet impls (e.g. impl<T: Copy> Clone for Option<T>) or to have some sort of priority mechanism.

@huonw
Copy link
Member

huonw commented Sep 6, 2015

I don't understand what you mean, allowing more specialised impls (i.e. this) is exactly what specialisation is. Anyway nitpicking the exact terminology probably doesn't matter so much here...

@arielb1
Copy link
Contributor

arielb1 commented Sep 6, 2015

@huonw

@aturon's specialization RFC - rust-lang/rfcs#1210 - does not allow for overlapping impls in any case. There are also proposals for "lattice impls", which allow overlapping impls as long as there is a meet between every 2 impls. This is not part of the RFC.

@huonw
Copy link
Member

huonw commented Sep 6, 2015

Ah, I was speaking more abstractly, but in fact, @aturon has realised a modification to the RFC that allows cases like this, just hasn't had time to publish.

@nikomatsakis
Copy link
Contributor

On Fri, Sep 04, 2015 at 01:33:13PM -0700, arielb1 wrote:

@nikomatsakis: should we make Clone a lang-item? I think it being a supertrait of Copy forces our hand.

Possibly. My preferred strategy here would be to leverage
specialization, such that we have a blanket impl of Clone for all T: Copy. I know that some variants of specialization cannot accommodate
this, though.

@arielb1
Copy link
Contributor

arielb1 commented Sep 7, 2015

@nikomatsakis

Variants which include all these proposed in the RFC.

@nikomatsakis nikomatsakis added the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Sep 17, 2015
@nikomatsakis
Copy link
Contributor

triage: P-medium

We're still working out the preferred way to solve this problem. I tagged T-lang because of the interaction w/ specialization.

@rust-highfive rust-highfive added P-medium Medium priority and removed I-nominated labels Sep 17, 2015
@brson brson added A-typesystem Area: The type system I-wishlist P-low Low priority I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ and removed I-wishlist labels Jul 14, 2016
@brson
Copy link
Contributor

brson commented Jul 14, 2016

Triage: P-low. ICE is problematic though would be great to fix it. Can anybody mentor?

@nikomatsakis
Copy link
Contributor

@brson fixing this is no small thing, sadly. I had hoped we could address it through specialization but that does not seem to be the case. @arielb1 has been advocating for building the clone impls into the compiler, that might be the most prudent short-term path at least, particularly given that Clone is a lang-item anyway. I could mentor this.

@nikomatsakis nikomatsakis added E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. and removed P-medium Medium priority labels Jul 28, 2016
@brson
Copy link
Contributor

brson commented Jul 28, 2016

@nikomatsakis oh, that would be great. I was only hoping to stop the ICE!

@retep998
Copy link
Member

If Copy is implemented by the compiler automatically for certain types, then I don't see why the compiler wouldn't also implement Clone, and seems like the obvious solution to me. Using blanket impls and specialization just feels like the standard library covering up a deficiency in the compiler.

@cseale
Copy link
Contributor

cseale commented Jan 11, 2017

@nikomatsakis If this is still an issue and you have the time, I would like to look at this. I would be pretty new to Rust and the Compiler though

@nikomatsakis
Copy link
Contributor

@cseale Great! Since writing my last comment, I now have greater hope for being able to fix this through specialization (and hence without modifying the compiler), but those plans remain a bit in flux, so I think it's probably best to close this hole in the compiler for the time being. I will try to write up some instructions tomorrow!

@cseale
Copy link
Contributor

cseale commented Jan 22, 2017

Hi @nikomatsakis, any chance we could take a look at this? 😃

@nikomatsakis
Copy link
Contributor

@cseale argh, sorry, added to my to-do list for tomorrow =)

I think part of my hesitation is that it's going to be potentially a bit messy to hack this in, and if specialization can solve it that will be much nicer (and of course it's been this long...). But let me glance over code tomorrow to try and decide just how invasive it will be.

@cseale
Copy link
Contributor

cseale commented Jan 25, 2017

@nikomatsakis no problem! if there is another outstanding E-mentor issue involving that compiler maybe I would be better spending my time there? I am just trying to get involved in that part of the codebase

ketralnis pushed a commit to ketralnis/pipelines-rs that referenced this issue Jun 12, 2017
This makes multiplexers slightly more ergonomic.

Due to rust-lang/rust#28229 (functions implement Copy
but not Clone) it's not currently possible to do with closures yet but it's
better than nothing
@Mark-Simulacrum Mark-Simulacrum added C-bug Category: This is a bug. and removed C-bug Category: This is a bug. I-wrong labels Jul 22, 2017
@scalexm
Copy link
Member

scalexm commented Aug 5, 2017

I've written a fix for this locally, however I wonder how it would be integrated in the compiler (if it is).
Basically I had to do two steps:

  • Add a lang item for Clone and let the compiler generate implementations for relevant types (i.e. every type which has builtin support for Copy, + tuples and arrays of types which implement Clone). Then build the compiler.
  • Change libcore so that the Clone trait is marked as the corresponding lang item and remove manual implementations of Clone for the types described above. Then build the compiler using the previously built compiler.

I cannot merge the two steps since the compiler would not understand the attribute #[lang = "clone"] and would anyway not be able to compile with the Clone implementations being removed.

@kennytm
Copy link
Member

kennytm commented Aug 5, 2017

@scalexm Use #[cfg_attr(not(stage0), lang = "clone")] so only the new compiler will recognize the lang item.

Basically you slap a #[cfg(not(stage0))] on anything that only the new compiler understands, and put #[cfg(stage0)] on anything only required by the old compiler.

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
sinkuu added a commit to sinkuu/rust that referenced this issue Jan 8, 2019
manual impl was a workaround for rust-lang#28229.
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 C-bug Category: This is a bug. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-low Low priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests