Prefer inherent methods in trait object method resolution#158320
Prefer inherent methods in trait object method resolution#158320Jules-Bertholet wants to merge 3 commits into
Conversation
b4baa8f to
4b8693c
Compare
| let x: &(dyn T + Send) = &0i32; | ||
| assert_eq!(x.foo(), 0); |
There was a problem hiding this comment.
This part is not so nice… ideally this would use the inherent impl too.
There was a problem hiding this comment.
I looked into making this work, but it seems non-trivial. The inherent_impls query is based on DefIds, so information about auto traits is lost
|
@bors try @rust-timer queue and cratering it when the try job finishes, impl lgtm |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Prefer inherent methods in trait object method resolution
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (8a2f6fe): comparison URL. Overall result: no relevant changes - no action neededBenchmarking means the PR may be perf-sensitive. Consider adding rollup=never if this change is not fit for rolling up. @rustbot label: -S-waiting-on-perf -perf-regression Instruction countThis perf run didn't have relevant results for this metric. Max RSS (memory usage)Results (primary -5.9%, secondary -6.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (secondary 3.9%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 510.446s -> 505.256s (-1.02%) |
|
@craterbot check |
|
👌 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
|
🚧 Experiment ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more |
|
🎉 Experiment
Footnotes
|
|
The reference has a warning about this that needs to be corrected if this PR were to go through. |
Stabilization reportThis PR allows calling an inherent method on a trait object that shares a name with the method's primary trait. Up to now, this has always failed with an ambiguity error; after this PR, the inherent method shadows the trait method. Reference PR: rust-lang/reference#2308 What is stabilizedtrait Trait {
fn foo(&self) -> i32 {
1
}
}
impl Trait for i32 {}
impl<'a> dyn Trait + 'a {
fn foo(&self) -> i32 {
2
}
}
fn main() {
let a: &i32 = &3;
assert_eq!(a.foo(), 1);
let obj: &(dyn Trait) = a;
assert_eq!(obj.foo(), 2); // would previously give ambiguity error
assert_eq!(Trait::foo(obj), 1);
}What isn't stabilizedInherent method lookup continues to not peel off auto traits on trait objects. Continuing our previous example: let obj2: &(dyn Trait + Send) = a;
assert_eq!(obj2.foo(), 1); // uses trait methodThere is a risk that merging this PR now could make this more difficult to fix in the future, because doing so would change the behavior of code like the example above. |
|
@rfcbot fcp merge types |
|
@oli-obk has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
|
Was there any specific reason you've working on this. I agree this feels vaguely desirable, but don't have a concrete use case in mind right now. There are a few interesting cases here 🤔 Which method to use already depends on the self type trait Trait<T> {
fn func(&mut self) {
println!("trait");
}
}
impl<T> Trait<T> for i32 {}
impl dyn Trait<u32> {
fn func(&self) {
println!("inherent");
}
}
fn foo(mut x: Box<dyn Trait<u32>>) {
x.func(); // inherent
(&mut *x).func(); // trait
}
fn main() {
foo(Box::new(1));
}This candidate preference guides inference trait Trait<T> {
fn func(&self) {
println!("trait");
}
}
impl<T> Trait<T> for i32 {}
impl dyn Trait<u32> {
fn func(&self) {
println!("inherent");
}
}
fn foo() {
let x: Box<dyn Trait<_>> = Box::new(1);
x.func(); // ambiguity error -> now constrains the infer var to `u32`
}
fn main() {
foo();
}Both of these feel acceptable to me and aren't really new issues @rfcbot reviewed Also, while I consider this (and want it to be) a bit more Types than Lang, this has definitely a stronger Lang overlap @rust-lang/lang |
Fixes #51402. Inherent methods on trait objects now take precedence over methods from the trait object's trait, but these last continue to take precedence over other trait impls as before.
I don't know whether this should be feature gated or insta-stable FCP, will let T-types decide that.
r? types
@rustbot label T-types A-dyn-trait