Skip to content

where clause seems ignored when attached to narrower scope than binding point #17086

Closed
@pnkfelix

Description

@pnkfelix

Consider the following code (example 1):

trait Foo { fn foo(&self) -> int; }
struct B<X>;
impl<X> B<X> {
    fn bar(&self, _x: X) -> int where X : Foo {
        // _x.foo()
        16
    }
    fn baz(&self) -> int {
        17
    }
}

// impl Foo for int { fn foo(&self) -> int { *self } }

fn main() {
    let b = B::<int>;
    let i = b.bar(3i);
    let j = b.baz();
    println!("Hello, world! {:d} {:d}", i, j)
}

Note that the impl of Foo for int is commented out. The where clause is meant to bound X for the method bar; we are not achieving that goal. I believe this is a bug, and a backwards-compatibility hazard for us to take note of (see further explanation below).


If I move the where-clause up so that its attached to the whole impl block, then we see the code get rejected, as expected. Illustrated here (example 2):

trait Foo { fn foo(&self) -> int; }
struct B<X>;
impl<X> B<X> where X : Foo {
    fn bar(&self, _x: X) -> int {
        // _x.foo()
        16
    }
    fn baz(&self) -> int {
        17
    }
}

// impl Foo for int { fn foo(&self) -> int { *self } }

fn main() {
    let b = B::<int>;
    let i = b.bar(3i);
    let j = b.baz();
    println!("Hello, world! {:d} {:d}", i, j)
}

(This is not an illustration of a bug. I just wanted to show that the code overall should indeed be rejected if the where clause is not ignored.)


Finally, we also need to make sure that we use the information from the where clause when checking the bodies of methods to which the where-clause is attached. This is also failing for us, causing a compile-failure that should be succeeding, as shown below (example 3):

trait Foo { fn foo(&self) -> int; }
struct B<X>;
impl<X> B<X> {
    fn bar(&self, _x: X) -> int where X : Foo {
        _x.foo()
    }
    fn baz(&self) -> int {
        17
    }
}

impl Foo for int { fn foo(&self) -> int { *self } }

fn main() {
    let b = B::<int>;
    let i = b.bar(3i);
    let j = b.baz();
    println!("Hello, world! {:d} {:d}", i, j)
}

Note that I have made several modifications in this example; mostly importantly, I have uncommented the impl of Foo for int and then used foo within the method bar. This currently causes the following compiler error:

<anon>:5:12: 5:17 error: type `X` does not implement any method in scope named `foo`
<anon>:5         _x.foo()
                    ^~~~~
error: aborting due to previous error
playpen: application terminated with error code 101
Program ended.

As noted in example 1, the ignoring of where clauses is a backwards compatibility hazard. While one might expect code that is using where clauses would also have code that is using methods of those triats (as in example 3), and thus would hit compilation failures before code could come to rely on the where clauses being ignored, example 1 is meant to concretely illustrate code that is building now but absolutely should be rejected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions