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

test: Add a test for variance in trait matching. #15191

Closed

Conversation

pcwalton
Copy link
Contributor

I believe that #5781 got fixed by the DST work. It duplicated the
variance inference work in #12828. Therefore, all that is left in #5781
is adding a test.

Closes #5781.

r? @huonw


impl Make for &'static mut uint {
fn make() -> &'static mut uint {
&mut CONST
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't need unsafe because the effect pass runs after the type checker?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right.

@huonw
Copy link
Member

huonw commented Jun 26, 2014

Also, is this test case correct w.r.t. to the original issue? It was originally *uint <: *const uint while this one is &'static mut uint <: &'a mut uint. That is, it seem like the implemented type here is the subtype, not the supertype. (I could very well have this all backwards.)

I removed my r+ temporarily.

@pcwalton
Copy link
Contributor Author

@huonw Yeah, you're right, it's broken and this is still a bug. Looking into it.

@pcwalton
Copy link
Contributor Author

@huonw Should be fixed now for real. r?

@huonw
Copy link
Member

huonw commented Jun 26, 2014

Travis failed.

@edwardw
Copy link
Contributor

edwardw commented Jun 26, 2014

I think this patch may have only addressed the vtable part of #5781. There is another half, namely in librustc/middle/typeck/infer/combine.rs#L92, it is still contravariant only for self type. IIRC, if we do fix it, then bivariant weirdness starts to creep in. That's what rfc#12 is for, but now that rfc hasn't made progress for a while.

As for the new compile-fail/variance-trait-matching-2.rs, I believe it is the same as #12470 and has been fixed as a side effect of #14869. And the #12470 itself has been closed by my #15120 and your #15154, twice :D

@pcwalton
Copy link
Contributor Author

@edwardw Thanks for the heads up! Looks like fixing combine.rs to do the conservative thing and make Self as well as all type parameters invariant didn't have any impact on successful bootstrapping. So I'll do that.

@pcwalton
Copy link
Contributor Author

r? @huonw

@pcwalton
Copy link
Contributor Author

I have removed all FIXME's about that issue and made the changes suggested.

}).unwrap()
1i
});
if r.is_err() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be assert!(r.is_ok()).

@pcwalton
Copy link
Contributor Author

It's unfortunate, yes, but I think that being able to return arbitrary references in safe code is much more unfortunate. I believe that this bug allows you to transmute arbitrary values to any other arbitrary value in safe code. Let's lock it down for now and see how we can address the usability problem later.

re-r? @huonw

This can break code that looked like:

    impl Foo for Box<Any> {
        fn f(&self) { ... }
    }

    let x: Box<Any + Send> = ...;
    x.f();

Change such code to:

    impl Foo for Box<Any> {
        fn f(&self) { ... }
    }

    let x: Box<Any> = ...;
    x.f();

That is, upcast before calling methods.

This is a conservative solution to rust-lang#5781. A more proper treatment (see
the xfail'd `trait-contravariant-self.rs`) would take variance into
account. This change fixes the soundness hole.

Some library changes had to be made to make this work. In particular,
`Box<Any>` is no longer showable, and only `Box<Any+Send>` is showable.
Eventually, this restriction can be lifted; for now, it does not prove
too onerous, because `Any` is only used for propagating the result of
task failure.

This patch also adds a test for the variance inference work in rust-lang#12828,
which accidentally landed as part of DST.

Closes rust-lang#5781.

[breaking-change]
bors added a commit that referenced this pull request Jun 28, 2014
I believe that #5781 got fixed by the DST work. It duplicated the
variance inference work in #12828. Therefore, all that is left in #5781
is adding a test.

Closes #5781.

r? @huonw
@bors bors closed this Jun 28, 2014
@pcwalton pcwalton deleted the variance-in-trait-matching branch June 28, 2014 20:07
@huonw
Copy link
Member

huonw commented Jun 30, 2014

This has had a few "surprising" consequences. Consider the following code

trait Foo: Clone {}

impl Foo for fn(&int) {}

fn foo(_: &int) {}

fn main() {
    foo.clone();
}

This compiles fine with 9f8149e (before this landed), but fails with 1e6b699 (the version currently on the playpen): http://is.gd/qkFy3n

<anon>:3:1: 3:25 error: failed to find an implementation of trait core::clone::Clone for fn(&int)
<anon>:3 impl Foo for fn(&int) {}
         ^~~~~~~~~~~~~~~~~~~~~~~~

Of particular note is that commenting out the impl Foo line makes it compile, that is, the .clone() call is fine despite the compiler complaining that that type doesn't implement Clone!


There's another example where trait impls like

impl<
    'a,
    T: HasTransform<'a, Matrix2d>
        + CanTransform<'a, T, Matrix2d>
> RelativeTransform2d<'a> for T {
    fn trans(&'a self, x: Scalar, y: Scalar) -> T {

cannot be used like:

pub struct Context<'a> { ... }

fn foo() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let _d = d.trans(10.0, 10.0);
    }
}

because the d.trans call needs the &'a self lifetime to match that of the Context in c, but the scope of d is too small. Previously I guess the subtyping meant that c the lifetime could be restricted, but this patch disables that. (@bvssvni is working on narrowing down a smaller example.)

(I'm not suggesting at all that this patch should be reverted, just listing two corner-cases people have met due to this, for the record.)

@bvssvni
Copy link

bvssvni commented Jun 30, 2014

@huonw reduced my example down to: http://is.gd/Yl44ye

pub struct Context<'a> {
    pub view: Option<&'a int>,
}

pub trait RelativeTransform2d<'a> {
    fn trans(&'a self) -> Self;
}

/*
// WORKS WHEN IMPLEMENTING TRAIT DIRECTLY

impl<'a> RelativeTransform2d<'a> for Context<'a> {
    fn trans(&'a self) -> Context<'a> {
        *self
    }
}
*/

pub trait CanTransform<'a, T> {
    fn transform(&'a self) -> T;
}

impl<'a> CanTransform<'a, Context<'a>> for Context<'a> {
    fn transform(&'a self) -> Context<'a> {
        *self
    }
}

impl<'a, T:  CanTransform<'a, T>> RelativeTransform2d<'a> for T {
    fn trans(&'a self) -> T {
        self.transform()
    }
}

fn main() {
    let c = Context { view: None };
    {
        let d = c.trans();
        let _d = d.trans();
    }
}
<anon>:39:18: 39:19 error: `d` does not live long enough
<anon>:39         let _d = d.trans();
                           ^
<anon>:35:11: 41:2 note: reference must be valid for the block at 35:10...
<anon>:35 fn main() {
<anon>:36     let c = Context { view: None };
<anon>:37     {
<anon>:38         let d = c.trans();
<anon>:39         let _d = d.trans();
<anon>:40     }
          ...
<anon>:37:5: 40:6 note: ...but borrowed value is only valid for the block at 37:4
<anon>:37     {
<anon>:38         let d = c.trans();
<anon>:39         let _d = d.trans();
<anon>:40     }

@alexchandel
Copy link

According to @PistonDevelopers, a bug was introduced and mentioned above which breaks rust-graphics in Rust 0.11. @PistonDevelopers asked that 0.11's release is blocked until the bug fixed. It's very possible this is already taken care of, but just in case it wasn't mentioned in the repo...

@bvssvni
Copy link

bvssvni commented Jul 2, 2014

Rust-Graphics has now a work around: PistonDevelopers/graphics#559

bors added a commit to rust-lang-ci/rust that referenced this pull request Jul 17, 2023
…f, r=lowr

Disable remove unnecessary braces diagnotics for self imports

Disable `remove unnecessary braces` diagnostic if the there is a `self` inside the bracketed `use`

Fix rust-lang#15191
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

treatment of subtyping in trait matching is unsound
6 participants