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

where clause not honored in trait impl body #20414

Closed
Twisol opened this issue Jan 2, 2015 · 15 comments
Closed

where clause not honored in trait impl body #20414

Twisol opened this issue Jan 2, 2015 · 15 comments
Labels
A-type-system Area: Type system E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.

Comments

@Twisol
Copy link

Twisol commented Jan 2, 2015

Even though I've stipulated in the where clause that Newtype<'a, T> must implement Foo for this impl to apply, I can't call answer on a Newtype<'a, T> within the impl body.

Workaround

Per @jroesch below, this can be worked around by using Foo::answer(&mut newtype) instead of newtype.answer().

Test case

rustc 0.13.0-nightly (7608dbad6 2014-12-31 10:06:21 -0800)
binary: rustc
commit-hash: 7608dbad651f02e837ed05eef3d74a6662a6e928
commit-date: 2014-12-31 10:06:21 -0800
host: x86_64-apple-darwin
release: 0.13.0-nightly
trait Foo {
  fn answer(&mut self) -> u8;
}

trait Bar<'a> {
  fn stuff(&'a mut self) -> u8;
}

struct Newtype<'a, T: 'a> {
  value: &'a mut T,
}


impl<'a, T> Bar<'a> for T
where Newtype<'a, T>: Foo {
  fn stuff(&'a mut self) -> u8 {
    let mut newtype: Newtype<'a, T> = Newtype{value: self};
    newtype.answer()
  }
}


fn main() {}
foo.rs:18:13: 18:21 error: type `Newtype<'a, T>` does not implement any method in scope named `answer`
foo.rs:18     newtype.answer()
                      ^~~~~~~~
error: aborting due to previous error
@Twisol
Copy link
Author

Twisol commented Jan 2, 2015

Per theme in #rust, here is a shorter program which exhibits the same problem, where the where information can't be used in the impl body.

trait Foo {
    fn foo_fn(self);
}

struct NoData;

impl NoData where NoData: Foo {
    fn any_fn(self) {
        self.foo_fn()
    }
}

fn main() { }
foo.rs:9:14: 9:22 error: type `NoData` does not implement any method in scope named `foo_fn`
foo.rs:9         self.foo_fn()
                      ^~~~~~~~
error: aborting due to previous error

@theemathas
Copy link
Contributor

A variant that uses a function instead of a method.

trait Foo {
    fn foo_fn(self);
}

struct NoData;

fn any_fn(val: NoData) where NoData: Foo {
    val.foo_fn();
}

fn main() { }

Error:

compiler_bug3.rs:8:9: 8:17 error: type `NoData` does not implement any method in scope named `foo_fn`
compiler_bug3.rs:8     val.foo_fn();
                           ^~~~~~~~
error: aborting due to previous error

@nikomatsakis
Copy link
Contributor

cc @jroesch

@huonw
Copy link
Member

huonw commented Jan 2, 2015

It seems to me that the bug with the NoData: Foo examples is the compiler doesn't recognise that NoData does not implement Foo. IIRC, it's out-of-scope to support bounding types that don't mention a generic parameter in where clauses, meaning those two are actually fundamentally "invalid" atm anyway.

In fact, it seems the original is falling into the same hole since Newtype<'a, T> doesn't implement Foo for any 'a or T. This simpler version of the original suffers the same problem:

trait Foo {
  fn answer(&mut self) -> u8;
}

struct Newtype<'a, T: 'a> {
  value: &'a mut T,
}

// impl<'a, T> Foo for Newtype<'a, T> { fn answer(&mut self) -> u8 { 0 } }

fn stuff<'a, T>(this: &'a mut T) -> u8 where Newtype<'a, T>: Foo {
    let newtype: Newtype<'a, T> = Newtype{value: this};
    newtype.answer()
}

fn main() {}

Uncommenting the impl Foo for Newtype (which should then compile?) dives deep into winter, with an ICE:

<anon>:12:9: 12:16 error: internal compiler error: coherence failed to report ambiguity: cannot locate the impl of the trait `core::kinds::Sized` for the type `Newtype<'a, T>`
<anon>:12     let newtype: Newtype<'a, T> = Newtype{value: this};
                  ^~~~~~~

which is #20413.

@jroesch
Copy link
Member

jroesch commented Jan 2, 2015

@huonw: I agree. There is currently an issue to remove the ability to bound non-parameter types and is detailed in the meta bug related to where-clauses (see: #17657).

@Twisol
Copy link
Author

Twisol commented Jan 2, 2015

In fact, it seems the original is falling into the same hole since Newtype<'a, T> doesn't implement Foo for any 'a or T

My particular use-case is cross-crate: I have one crate defining Newtype, Foo, and Bar, and another crate defining several X and implementing Foo for each Newtype<X>. I want the first crate to impl Bar for all T with Newtype<T>: Foo. At the time of building the first crate, there shouldn't be an error - there isn't enough information at the time to say that no Newtype<'a, T> implements Foo.

The two non-generic examples don't have this possibility, because the type has no generic parameters and thus there is no opportunity for impls from another crate.

Also, a modified version of your example, which only implements Foo for T=(), results in the same error as in the original report.

trait Foo {
  fn answer(&mut self) -> u8;
}

struct Newtype<'a, T: 'a> {
  value: &'a mut T,
}

impl<'a> Foo for Newtype<'a, ()> { fn answer(&mut self) -> u8 { 0 } }

fn stuff<'a, T>(this: &'a mut T) -> u8 where Newtype<'a, T>: Foo {
    let newtype: Newtype<'a, T> = Newtype{value: this};
    newtype.answer()
}

fn main() {}

Twisol added a commit to Twisol/rust-telnet that referenced this issue Jan 3, 2015
…n event context.

The code right now is super nasty, since it is not currently possible to implement
  TelnetChannel for all T where Carrier<T> implements ChannelHandler. This is an
  explicit feature of the `where` clause, and a Rust issue is open for this.
  (rust-lang/rust#20414)
@sellibitze
Copy link
Contributor

I ran into an issue which is very similar (I believe). Here it goes:

trait Trait {
    fn method(self) -> int;
}
struct Wrapper<T> {
    field: T
}
impl<'a, T> Trait for &'a Wrapper<T> where &'a T: Trait {
    fn method(self) -> int {
        let r: &'a T = &self.field;
        r.method()
    }
}
fn main() {}

This is rejected but I think it should compile. The error message is:

<anon>:10:15: 10:23 error: type `&'a T` does not implement any method in scope named `method`
<anon>:10             r.method()
                        ^~~~~~~~
error: aborting due to previous error
playpen: application terminated with error code 101

@jroesch
Copy link
Member

jroesch commented Jan 5, 2015

@sellibitze There is currently a bug with method call style syntax. You can rewrite this code to use UFCS:

trait Trait {
    fn method(self) -> int;
}
struct Wrapper<T> {
    field: T
}
impl<'a, T> Trait for &'a Wrapper<T> where &'a T: Trait {
    fn method(self) -> int {
        let r: &'a T = &self.field;
        Trait::method(r)
    }
}
fn main() {}

That worked for me here: http://is.gd/hqeprS.

@Twisol
Copy link
Author

Twisol commented Jan 5, 2015

@jroesch: Hey, that worked for my use-case too. Weird! I'll add this workaround to the OP for now.

@kmcallister kmcallister added A-type-system Area: Type system I-wrong labels Jan 6, 2015
@Twisol
Copy link
Author

Twisol commented Jan 8, 2015

My original example and @sellibitze's now compile successfully under the latest nightly.

rustc 1.0.0-nightly (ea6f65c5f 2015-01-06 19:47:08 +0000)
binary: rustc
commit-hash: ea6f65c5f1a3f84e010d2cef02a0160804e9567a
commit-date: 2015-01-06 19:47:08 +0000
host: x86_64-apple-darwin
release: 1.0.0-nightly

Probably fixed by #20608?

@jroesch
Copy link
Member

jroesch commented Jan 8, 2015

@Twisol yeah method resolution uses slightly different code then function calls, and there was a bug lurking in the method call code that had been resolved for function calls. Glad everything it is working. I think we can close this one out, but we need someone with repository rights to do so.

@bstrie bstrie closed this as completed Jan 8, 2015
@bstrie bstrie reopened this Jan 8, 2015
@bstrie
Copy link
Contributor

bstrie commented Jan 8, 2015

Temporarily reopened while awaiting a test case PR.

jroesch added a commit to jroesch/rust that referenced this issue Jan 9, 2015
bors added a commit that referenced this issue Jan 9, 2015
Add test for issue #20414

Reviewed-by: alexcrichton
@nikomatsakis nikomatsakis added the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Jan 11, 2015
@nikomatsakis
Copy link
Contributor

Labeling as E-needstest per @bstrie's comment

@jroesch
Copy link
Member

jroesch commented Jan 14, 2015

@nikomatsakis We should have a regression now as per: #20800. I should of marked it as closes this issue.

@nikomatsakis
Copy link
Contributor

k

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 E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.
Projects
None yet
Development

No branches or pull requests

8 participants