-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Make EarlyBinder
's inner value private
#112006
Conversation
Some changes occurred in src/tools/clippy cc @rust-lang/clippy Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 Some changes occurred to the core trait solver cc @rust-lang/initiative-trait-system-refactor Some changes occurred to the CTFE / Miri engine cc @rust-lang/miri Some changes occurred to MIR optimizations cc @rust-lang/wg-mir-opt Some changes occurred in cc @BoxyUwU |
☔ The latest upstream changes (presumably #112016) made this pull request unmergeable. Please resolve the merge conflicts. |
r=me with rebase :) @bors p=1 |
a69c002
to
c29c212
Compare
@bors r+ |
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.
some places probably could've been subst_identity rather than skip_binder, but i guess it doesn't matter
let mut sig = if let Some(sig_substs) = sig_substs { | ||
sig.subst(tcx, &sig_substs) | ||
} else { | ||
sig.skip_binder() |
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.
subst_identity i feel
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 would expect this to be no_bound_vars()
🤔 though that may break with polymorphization rn?
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.
This type of pattern was always sketchy to me. Adding the EarlyBinder type makes it clear why.
I'm not sure how polymorphization works; seems like this could be a byproduct of it.
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.
Yeah, this panics with no_bound_vars().unwrap()
unfortunately.
From reading the polymorphization section in the rustc_dev_guide, it looks like polymorphization uses ty::Param
to represent unused generics. So after polymorphization sig
may appear to needs_subst()
because of the presence of ty::Param
s. I'm sure it's more complicated than that in practice, but is that sort of the right way to think about 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.
Yeah, this panics with
no_bound_vars().unwrap()
unfortunately.From reading the polymorphization section in the rustc_dev_guide, it looks like polymorphization uses
ty::Param
to represent unused generics. So after polymorphizationsig
may appear toneeds_subst()
because of the presence ofty::Param
s. I'm sure it's more complicated than that in practice, but is that sort of the right way to think about this?
yeah, it is exactly that, I want to move polymorphization to bound vars by changing instances to use ty::Binder
and then using bound vars of params (as params are conceptionally just a different representation of bound vars or placeholders, depending on context 😁)
I think using ty::Param
for polymorphization will end up causing issues like the above in the future.
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.
that would be an option, I don't like it too much because ty::Erased
should be equal to itself and for<T, U> my_function<T, U>
should be different from for<T> my_function<T, T>
. While we may not necessarily end up with these cases in practice it still feels a bit dangerous
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.
Both for<T, U> my_function<T, U>
and for<T> my_function<T, T>
should be equal to be able to codegen a single instance, right? Polymorphization already makes sure that it won't erase types that actually matter for codegen.
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.
Both
for<T, U> my_function<T, U>
andfor<T> my_function<T, T>
should be equal to be able to codegen a single instance, right?
yes, the issue is that if you polymorphize to bound vars, these two are different, but if you polymorphize to erased, then both end up as my_function<erased, erased>
which should be equal to itself
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.
You can't observe the difference at runtime, right? If you did, polymorphization should reject the candidates. Rustc passes unnamed_addr
to LLVM, so just comparing the function pointers can return true already if after optimizations the function bodies are identical.
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.
for<T, U> my_function<T, U>
and for<T> my_function<T, T>
probably won't happen in practice but you could imagine
fn check_type_ids<T, U, V>() -> u8 {
if TypeId::of::<T>() == TypeId::of::<U>() {
0
} else if TypeId::of::<T>() == TypeId::of::<U>() {
1
} else {
2
}
}
we end up with for<Eq, DontCare> check_type_ids<Eq, DontCare, Eq>
and for<DontCare, Eq> check_type_ids<DontCare, Eq, Eq>
fn check_type_ids<Eq, DontCare, Eq>() -> u8 {
0
}
fn check_type_ids<DontCare, Eq, Eq>() -> u8 {
if TypeId::of::<T>() == TypeId::of::<U>() {
0
} else {
1
}
}
this isn't a great example which is why I said "While we may not necessarily end up with these cases in practice it still feels a bit dangerous". I am worried about having yet another global invariant which is difficult to sensibly check
☀️ Test successful - checks-actions |
Finished benchmarking commit (1c53407): comparison URL. Overall result: ✅ improvements - no action needed@rustbot label: -perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 646.98s -> 646.44s (-0.08%) |
…piler-errors Cleanup some `EarlyBinder::skip_binder()` -> `EarlyBinder::subst_identity()` fix some incorrect `skip_binder()`'s as identified in rust-lang#112006 (review) r? `@compiler-errors` `@lcnr` `@jackh726` (hope it's alright to just tag everyone who commented 😅)
…piler-errors Cleanup some `EarlyBinder::skip_binder()` -> `EarlyBinder::subst_identity()` fix some incorrect `skip_binder()`'s as identified in rust-lang#112006 (review) r? ``@compiler-errors`` ``@lcnr`` ``@jackh726`` (hope it's alright to just tag everyone who commented 😅)
Currently,
EarlyBinder(T)
's inner value is public, which allows implicitly skipping the binder by indexing into the tuple struct (i.e.,x.0
). @lcnr suggested makingEarlyBinder
's inner value private so users are required to explicitly callskip_binder
(#105779 (comment)) .This PR makes the inner value private, adds
EarlyBinder::new
for constructing a new instance, and replaces uses ofx.0
withx.skip_binder()
(or similar). It also adds some documentation toEarlyBinder::skip_binder
explaining how to skip the binder of&EarlyBinder<T>
to get&T
now that the inner value is private (since previously we could just do&x.0
).r? @lcnr