-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Allow instantiating object trait binder when upcasting #130866
Allow instantiating object trait binder when upcasting #130866
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nvm, just needed to move an arg lol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
r=me after nits
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 inUnsize
goals.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
&T
is covariant overT
, but&mut T
is invariant, that's where the discrepancy between these two examples crops up.r? lcnr or reassign :D