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

Permit impl methods whose bounds cannot be satisfied to have no body #20021

Open
nikomatsakis opened this Issue Dec 19, 2014 · 12 comments

Comments

Projects
None yet
@nikomatsakis
Copy link
Contributor

nikomatsakis commented Dec 19, 2014

There is a curious case with where clauses where sometimes we can show that a method in an impl could not possibly be called. This is because the impl has more precise information than the trait. Here is an example:

    trait MyTrait<T> {
        fn method(&self, t: &T) where T : Eq;
    }

    struct Foo;
    struct Bar; // note that `Bar` does not derive `Eq`

    impl MyTrait<Bar> for Foo {
        fn method(&self, t: &T) where Bar : Eq { // <-- `Bar : Eq` cannot be satisfied!
        }
    }

We should permit the method body to be omitted in such a case. As a workaround, once #20020 is fixed, I imagine it would be possible to write an impl like this:

impl MyTrait<Bar> for Foo {
    fn method(&self, t: &T) { // no where clause at all
        panic!("Bar : Eq could not be satisfied");
    }
}

However, it is unfortunate to require that of the user. For one thing, perhaps it happens later that an impl of Eq is added for Bar -- now we have this method hanging around that will panic. It'd be nice to detect that statically.

The plan then would be to permit:

impl MyTrait<Bar> for Foo {
    fn method(&self, t: &T); // <-- no body or where clauses needed
}

This serves as a declaration that you believe this method could never be called. At trans time, we will generate a body that simply does the equivalent of panic!("unsatisfiable methodmethodinvoked").

I plan to open an amendment to the where clause RFC describing this particular case.

@brson brson referenced this issue Dec 19, 2014

Open

Implement where clauses #17657

5 of 7 tasks complete
@tomjakubowski

This comment has been minimized.

Copy link
Contributor

tomjakubowski commented Dec 19, 2014

It would be helpful to mark (or even erase) these uncallable methods in the "Trait Implementations" section of the rustdocs for the type implementing the trait.

@jroesch

This comment has been minimized.

Copy link
Member

jroesch commented Dec 20, 2014

@tomjakubowski I think I am the one who will be working #20020 and most likely this issue unless @nikomatsakis beats me to it. I will try to keep that in mind :).

@bltavares

This comment has been minimized.

Copy link
Contributor

bltavares commented Dec 28, 2015

Triaging this issue.

#20020 has already been closed, but yet we can't use unimplemented methods without where.

This is the code I used to see if it was still an issue:

trait MyTrait<T> {
    fn method(&self, t: &T) where T : Eq;
}

struct Foo;
struct Bar; // note that `Bar` does not derive `Eq`

impl MyTrait<Bar> for Foo {
    fn method(&self, t: &Bar);
}
fn main() {}

Rust version

rustc 1.7.0-nightly (b4707ebca 2015-12-27)
@apasel422

This comment has been minimized.

Copy link
Member

apasel422 commented Jan 10, 2016

In a similar situation, despite being object-safe, the following trait cannot be implemented for [T]:

trait Foo {
    fn foo(self);
}

impl<T> Foo for [T] {
    fn foo(self) { unimplemented!() }
    //~^ ERROR the trait `core::marker::Sized` is not implemented for the type `[T]`
}

The foo method has an implicit where Self: Sized as a result of taking self by value. Adding an explicit where Self: Sized bound would help if this issue is fixed, but the fix has to be more general than method-level where clauses.

As an unsatisfactory workaround, one can default foo as follows:

trait Foo {
    fn foo(self) where Self: Sized { unimplemented!() }
}

impl<T> Foo for [T] {}

This allows the impl to compile, but is nonsensical because it is exactly the Sized types that we want to provide a foo method.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor Author

nikomatsakis commented Jan 11, 2016

On Sun, Jan 10, 2016 at 09:10:54AM -0800, Andrew Paseltiner wrote:

In a similar situation, despite being object-safe, the following trait cannot be implemented for [T]:

FWIW, this is intentional, as we still aim to allow DST moves at some
point (or at least I do). So I would not want to make it possible to
implement that trait with [T] until that point is settled.

@apasel422

This comment has been minimized.

Copy link
Member

apasel422 commented Jan 13, 2016

@nikomatsakis Ah, I hadn't considered that. Are you still planning to amend the where clause RFC for this issue?

@nikomatsakis

This comment has been minimized.

Copy link
Contributor Author

nikomatsakis commented Aug 10, 2016

This is also arising in the context of rust-lang/rfcs#1216. Recent PR rust-lang/rfcs#1699 is also relevant.

The specific issue is that the ! type allows us to identify cases where methods could not ever really be called (e.g., because the type of one of their parameters is !, and there can never be an instance of such a type). It'd be nice to omit such methods.

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Aug 25, 2016

Nominating for triage. Add some tags please. Last work item in #17657

@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Aug 25, 2016

@nikomatsakis These two are qualitatively different things though. In the case that this issue is about, no call to the method could ever type-check. In the case that rust-lang/rfcs#1699 is about, a call would type-check just fine, it's just that the method body would never actually be entered at runtime.

@nrc nrc added T-lang and removed T-compiler labels Aug 25, 2016

@nikomatsakis

This comment has been minimized.

Copy link
Contributor Author

nikomatsakis commented Aug 25, 2016

Discussed in @rust-lang/lang meeting. A couple of notes:

  • We should be careful here -- this is a form of negative reasoning, so we have to apply the "coherence criteria" to avoid subtle breakage where people get to elide methods because a trait is unimplemented, but then a trait is added in the future.
  • Agreed, @glaebhoerl, there is a distinction between this and rust-lang/rfcs#1699.

triage: P-medium

@nikomatsakis

This comment has been minimized.

Copy link
Contributor Author

nikomatsakis commented Aug 25, 2016

Ah, reviewing this though -- I'm not sure we ever settled on a syntax. It may be that we need an RFC here? Should review the existing RFC :)

EDIT: Just did, it offers no guidance here.

@steveklabnik

This comment has been minimized.

Copy link
Member

steveklabnik commented Mar 11, 2019

Triage: not aware of any specific updates here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.