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

Allow method resolution to work on reference receiver types with Self : Sized bounds with reference trait implementations #83205

Closed

Conversation

b-naber
Copy link
Contributor

@b-naber b-naber commented Mar 16, 2021

Fixes #82825

In situations in which we have a trait method that takes a reference receiver type, a Self : Sized bound and a trait implementation for a reference type, the adjustments that the compiler applies are insufficient to fulfill the Sized bound on Self. To allow the compiler to resolve the correct method we autoref during method probing, after a sized bound violation was found, try to confirm the new method candidate and check if all resulting obligations can be fulfilled.

@rust-highfive
Copy link
Collaborator

r? @davidtwco

(rust-highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Mar 16, 2021
@b-naber
Copy link
Contributor Author

b-naber commented Mar 16, 2021

r? @eddyb maybe?

@rust-highfive rust-highfive assigned eddyb and unassigned davidtwco Mar 16, 2021
@b-naber b-naber force-pushed the method_resolution_sized_bound branch from 42284f8 to b3ac42b Compare March 16, 2021 16:19
@b-naber b-naber changed the title Allow method resolution to work on reference receiver types with Self : Sized bounds Allow method resolution to work on reference receiver types with Self : Sized bounds with reference trait implementations Mar 16, 2021
@rust-log-analyzer

This comment has been minimized.

@eddyb
Copy link
Member

eddyb commented Mar 16, 2021

I don't think special-casing "a Self: Sized bound" is the necessary thing here, sorry I didn't explain this better.

What Self: Sized does separately of type-checking is that it causes the method to be treated as not "object safe".

So in my mind, once you found that the method comes from a dyn Trait (something like "object candidate" IIRC), you can then easily discard that candidate based on whether it's "object safe" or not.

Oh... looking at the diff, there's already a hack for a different situation involving non-object-safe methods, that special-cases Self: Sized - I feel like that special-casing should maybe be cleaned up before new behavior should be added?

But maybe I'm misunderstanding the existing code, so maybe ignore me until you get a proper review.

r? @nikomatsakis

@rust-highfive rust-highfive assigned nikomatsakis and unassigned eddyb Mar 16, 2021
@b-naber
Copy link
Contributor Author

b-naber commented Mar 16, 2021

So in my mind, once you found that the method comes from a dyn Trait (something like "object candidate" IIRC), you can then easily discard that candidate based on whether it's "object safe" or not.

@eddyb That's what the compiler currently does. The existing hack you refer to is for diagnostics purposes.

It's very much possible that I misunderstood the intent of the issue. The way I understood it is that @guswynn wanted the compiler to autoref here to make Self correspond to the &T of the trait implementation and the receiver to have type &&dyn Trait therefore, so that a <&dyn Trait as Trait> predicate is created and the Self bound holds, whereas currently the compiler doesn't include an autoref and uses <dyn Trait as Trait> and <dyn Trait as Sized>. Is that different from the way you understood the issue?

Maybe @guswynn can also weigh in on this?

@b-naber
Copy link
Contributor Author

b-naber commented Mar 16, 2021

@eddyb I think I understand what you meant now. Instead of using the hack to test whether an illegal sized bound was encountered, we could test whether the sized bound holds (or object safety in general) during method probing. If that fails (during the pick_by_value_method call), the compiler will then try to autoref anyway. Is that what you meant?

@guswynn
Copy link
Contributor

guswynn commented Mar 16, 2021

@b-naber I believe your most recently comment is how I think of this problem

@b-naber
Copy link
Contributor Author

b-naber commented Mar 17, 2021

One problem I see with ignoring non object-safe methods during method probing is that the resulting diagnostics would be less informative. Instead of being given information on what bounds aren't satisfied we would only give out a 'method not found' error. But keeping track of potential candidates, which have unfulfilled obligations, during method probing for diagnostics purposes would probably affect performance negatively. Not sure what's the right trade-off here.

@guswynn
Copy link
Contributor

guswynn commented Mar 17, 2021

@b-naber is it possible in the event of a diagnostic to backtrack and recollect the methods that were tried? As far as I can tell, the diagnostic path in rustc prefers accuracy/helpfulness over performance

@b-naber
Copy link
Contributor Author

b-naber commented Mar 17, 2021

I think we would need to re-run method probing and add an option to collect method candidates. But you're right, once we're not on the hot path anymore because of an error, performance matters a lot less. I can try that approach, thanks.

Comment on lines +16 to +18
fn foo(x: &dyn Trait) {
x.static_call();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@b-naber can we add a &mut test here? that was the motivating usecase

also, is there a way we can test that this has actually regressed diagnostics? ci appears to pass just fine

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added the test, but we have to declare x as mutable in order for the mutable autoref to work, which might be confusing given that the autoref is implicit.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't have diagnostics problems in this version (using the existing illegal_sized_bound hack.

Copy link
Contributor

Choose a reason for hiding this comment

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

@b-naber oh thats very confusing...is the diagnostic around that good? as in, does it explicitly tell you to add the mut before the parameter?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm not really great, the borrow part is confusing, I don't think we should expect the user to know that an autoref occurs here:

error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
  --> src/test/ui/resolve/issue-82825-mut.rs:17:5
   |
17 |     x.static_call();
   |     ^
   |     |
   |     cannot borrow as mutable
   |     try removing `&mut` here

error: aborting due to previous error

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

oh hmm, yeah we would likely need to improve this diagnostic

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh also we should make sure we can still call it with (x).static_call() so that this is backwards compatible

@b-naber
Copy link
Contributor Author

b-naber commented Mar 21, 2021

Trying to solve this without the existing illegal_sized_bound hack is problematic and I haven't got this to work yet. The problem is that rejecting an ObjectCandidate once we find a Self: Sized bound is not sufficient, since the compiler also creates a TraitCandidate. I tried to reject these as well if the receiver on those methods either is a trait object itself or is a reference to a trait object and the receiver type of the method is a reference, in both cases having tested for a Self: Sized bound, but unfortunately this results in method probing not working correctly anymore. I'm not sure whether I just used the wrong conditions for deciding whether to reject a TraitCandidate and whether there is a way to get this to work.

@rust-log-analyzer

This comment has been minimized.

@b-naber b-naber force-pushed the method_resolution_sized_bound branch from c88ad1e to 84c371d Compare March 21, 2021 20:37
@bors
Copy link
Contributor

bors commented Mar 27, 2021

☔ The latest upstream changes (presumably #83580) made this pull request unmergeable. Please resolve the merge conflicts.

@JohnCSimon
Copy link
Member

Ping from triage:
@b-naber can you please resolve the merge conflicts?

@rustbot label: -S-waiting-on-review +S-waiting-on-author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 18, 2021
@nikomatsakis
Copy link
Contributor

I owe a review here, I know

@crlf0710 crlf0710 added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels May 8, 2021
@JohnCSimon
Copy link
Member

Ping again from triage:
@b-naber can you please resolve the merge conflicts?

@crlf0710 crlf0710 added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 11, 2021
@JohnCSimon JohnCSimon removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jun 27, 2021
@JohnCSimon JohnCSimon added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 12, 2021
@JohnCSimon
Copy link
Member

Triage:
@b-naber I'm closing this as inactive as it hasn't seen any movement in months. Please feel free to reopen if you're going to continue.

@bstrie bstrie closed this Jul 28, 2021
@Rua
Copy link
Contributor

Rua commented Feb 27, 2022

Any progress on this fix?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Method resolution fails when through a reference to a trait object on Self: Sized methods