Allow instantiating object trait binder when upcasting#130866
Allow instantiating object trait binder when upcasting#130866bors merged 3 commits intorust-lang:masterfrom
Conversation
lcnr
left a comment
There was a problem hiding this comment.
we previously incorrectly used sub there in the wrong order, resulting in an unsoundness fixed by #119849, cc https://github.com/rust-lang/rust/pull/119849/files#r1525200073
I fully agree that not requiring the binders to be equal is desirable here.
I would like to manually instantiate the binders here instead of relying on sub. This is easier to read imo and makes it far clearer what's going on.
r=me after FCP
|
Wait, why would this need an FCP? trait upcasting is still unstable, is it not? |
|
Oh yeah, I guess it's double unstable: new solver and/or feature gate. |
|
alright, so r=me after manually instantiating the binders :3 unless you're strongly opposed to doing that |
|
No, instantiating the binder is a bit more verbose but I agree it makes it much clearer who is the placeholders and who is the infer vars. |
8de3078 to
2ed14f3
Compare
|
Could use another review. The implementation is less than beautiful in both the new and old solvers:
|
| value: ty::Binder<I, T>, | ||
| f: impl FnOnce(&mut Self, T) -> U, | ||
| ) -> U { | ||
| self.delegate.enter_forall(value, |value| f(self, value)) |
There was a problem hiding this comment.
given that enter_forall is only used once, maybe it's easier to always use enter_forall_mut by modifying the signature of neter_forall.
While you're at it, change fn compute_goal to use self.enter_forall from self.delegate.enter_forall 😁
There was a problem hiding this comment.
I remember there being a specific problem where we had an infectious &mut self that ended up changing quite a lot if we did this
There was a problem hiding this comment.
nvm, just needed to move an arg lol
2ed14f3 to
d753aba
Compare
|
@bors r=lcnr |
…iaskrgr Rollup of 8 pull requests Successful merges: - rust-lang#125404 (Fix `read_buf` uses in `std`) - rust-lang#130866 (Allow instantiating object trait binder when upcasting) - rust-lang#130922 (Reference UNSPECIFIED instead of INADDR_ANY in join_multicast_v4) - rust-lang#130924 (Make clashing_extern_declarations considering generic args for ADT field) - rust-lang#130939 (rustdoc: update `ProcMacro` docs section on helper attributes) - rust-lang#130940 (Revert space-saving operations) - rust-lang#130944 (Allow instantiating trait object binder in ptr-to-ptr casts) - rust-lang#130953 (Rename a few tests to make tidy happier) r? `@ghost` `@rustbot` modify labels: rollup
Rollup merge of rust-lang#130866 - compiler-errors:dyn-instantiate-binder, r=lcnr Allow instantiating object trait binder when upcasting This PR fixes two bugs (that probably need an FCP). ### We use equality rather than subtyping for upcasting dyn conversions This code should be valid: ```rust #![feature(trait_upcasting)] trait Foo: for<'h> Bar<'h> {} trait Bar<'a> {} fn foo(x: &dyn Foo) { let y: &dyn Bar<'static> = x; } ``` But instead: ``` error[E0308]: mismatched types --> src/lib.rs:7:32 | 7 | let y: &dyn Bar<'static> = x; | ^ one type is more general than the other | = note: expected existential trait ref `for<'h> Bar<'h>` found existential trait ref `Bar<'_>` ``` And so should this: ```rust #![feature(trait_upcasting)] fn foo(x: &dyn for<'h> Fn(&'h ())) { let y: &dyn FnOnce(&'static ()) = x; } ``` But instead: ``` error[E0308]: mismatched types --> src/lib.rs:4:39 | 4 | let y: &dyn FnOnce(&'static ()) = x; | ^ one type is more general than the other | = note: expected existential trait ref `for<'h> FnOnce<(&'h (),)>` found existential trait ref `FnOnce<(&(),)>` ``` Specifically, both of these fail because we use *equality* when comparing the supertrait to the *target* of the unsize goal. For the first example, since our supertrait is `for<'h> Bar<'h>` but our target is `Bar<'static>`, there's a higher-ranked type mismatch even though we *should* be able to instantiate that supertrait binder when upcasting. Similarly for the second example. ### New solver uses equality rather than subtyping for no-op (i.e. non-upcasting) dyn conversions This code should be valid in the new solver, like it is with the old solver: ```rust // -Znext-solver fn foo<'a>(x: &mut for<'h> dyn Fn(&'h ())) { let _: &mut dyn Fn(&'a ()) = x; } ``` But instead: ``` error: lifetime may not live long enough --> <source>:2:11 | 1 | fn foo<'a>(x: &mut dyn for<'h> Fn(&'h ())) { | -- lifetime `'a` defined here 2 | let _: &mut dyn Fn(&'a ()) = x; | ^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static` | = note: requirement occurs because of a mutable reference to `dyn Fn(&())` ``` Specifically, this fails because we try to coerce `&mut dyn for<'h> Fn(&'h ())` to `&mut dyn Fn(&'a ())`, which registers an `dyn for<'h> Fn(&'h ()): dyn Fn(&'a ())` goal. This fails because the new solver uses *equating* rather than *subtyping* in `Unsize` goals. This is *mostly* not a problem... You may wonder why the same code passes on the new solver for immutable references: ``` // -Znext-solver fn foo<'a>(x: &dyn Fn(&())) { let _: &dyn Fn(&'a ()) = x; // works } ``` That's because in this case, we first try to coerce via `Unsize`, but due to the leak check the goal fails. Then, later in coercion, we fall back to a simple subtyping operation, which *does* work. Since `&T` is covariant over `T`, but `&mut T` is invariant, that's where the discrepancy between these two examples crops up. --- r? lcnr or reassign :D
This PR fixes two bugs (that probably need an FCP).
We use equality rather than subtyping for upcasting dyn conversions
This code should be valid:
But instead:
And so should this:
But instead:
Specifically, both of these fail because we use equality when comparing the supertrait to the target of the unsize goal. For the first example, since our supertrait is
for<'h> Bar<'h>but our target isBar<'static>, there's a higher-ranked type mismatch even though we should be able to instantiate that supertrait binder when upcasting. Similarly for the second example.New solver uses equality rather than subtyping for no-op (i.e. non-upcasting) dyn conversions
This code should be valid in the new solver, like it is with the old solver:
But instead:
Specifically, this fails because we try to coerce
&mut dyn for<'h> Fn(&'h ())to&mut dyn Fn(&'a ()), which registers andyn for<'h> Fn(&'h ()): dyn Fn(&'a ())goal. This fails because the new solver uses equating rather than subtyping inUnsizegoals.This is mostly not a problem... You may wonder why the same code passes on the new solver for immutable references:
That's because in this case, we first try to coerce via
Unsize, but due to the leak check the goal fails. Then, later in coercion, we fall back to a simple subtyping operation, which does work.Since
&Tis covariant overT, but&mut Tis invariant, that's where the discrepancy between these two examples crops up.r? lcnr or reassign :D