-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Preserve substitutions when making trait obligations for suggestions #71618
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.
The code changes themselves look ok, but I am hesitant to erasing the original cause.
trait_ref.def_id, | ||
trait_type, | ||
ObligationCause::dummy(), | ||
let new_obligation = self.mk_trait_obligation_with_new_self_ty( | ||
obligation.param_env, | ||
trait_ref, | ||
suggested_ty, |
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.
ignoring the previous obligation entirely? We used to use the same cause, right?
Is this what causes the "note: std::convert::From<std::string::String>
is implemented for &mut str
, but not for &str
" to go away?
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.
No. That comes from propagating substitutions correctly. From<String>
is not implemented for any of &mut str
or &str
.
My impression was that the cause for an obligation is where it originates from in the source. There is no underlying cause for the new obligation we create, since we're just trying various "self" types for diagnostic hints. From this POV, obligations that are only for speculation should have no cause code.
@ecstatic-morse in answer to your question, I think this call to
really, the only correct way to use rust/src/librustc_trait_selection/traits/error_reporting/suggestions.rs Lines 560 to 564 in 46ec74e
so that seems wrong. Probably better would be to do something like invoking |
Should I review this PR? |
@nikomatsakis That would be great! I considered implementing a |
271acc1
to
eb28214
Compare
☔ The latest upstream changes (presumably #72120) made this pull request unmergeable. Please resolve the merge conflicts. |
eb28214
to
91b52e7
Compare
ping @nikomatsakis |
let new_trait_ref = | ||
ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) }; | ||
Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate()) | ||
assert!(!new_self_ty.has_escaping_bound_vars()); |
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 think we should comment this function and clarify that new_self_ty
cannot have escaping bound variables
obligation.param_env, | ||
trait_ref, | ||
output_ty.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.
Is there a reason that we think output_ty
cannot reference bound variables? (The assertion suggests we do, but I don't immediately see it.)
I'd prefer to see output_ty.no_bound_vars().unwrap()
if we believe this to be true (no_bound_vars
docs)
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 think a function return type can indeed have late bound variables. fn<'a>() -> &'a dyn Any
is late bound, correct? Perhaps we should just bail out if it does? Alternatively, is there a way to preserve binding levels within mk_trait_obligation_with_new_self_ty
?
@@ -671,17 +669,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | |||
return; | |||
} | |||
|
|||
let mut trait_type = trait_ref.self_ty(); | |||
let mut suggested_ty = trait_ref.self_ty(); |
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'm a bit confused how the types work out here. This is a Binders<Ty>
, right?
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.
It's a plain Ty
if that helps.
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.
Yes, I noticed that recently. Hiding the skip_binder
call like that is...just so wrong. But it explains how this code type-checks, anyway.
|
||
for refs_remaining in 0..refs_number { | ||
if let ty::Ref(_, t_type, _) = trait_type.kind { | ||
trait_type = t_type; | ||
if let ty::Ref(_, inner_ty, _) = suggested_ty.kind { |
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.
...but I must be wrong, because how do we access the suggested_ty.kind
then?
obligation.param_env, | ||
&trait_ref, | ||
suggested_ty, |
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.
as above I don't 100% understand where this type is coming from or how we can be sure that it has no bound references in it -- doesn't it come from the trait_ref
?
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.
PolyTraitRef::self_ty
is equivalent to self.skip_binder().substs.type_at(0)
. It seems we are assuming that the self type has no escaping bound variables. Is this assumption correct?
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.
One other thing that I found confusing: According to the docs for TraitRef
,
[it] introduces a level of region binding, to account for higher-ranked trait bounds like
T: for<'a> Foo<&'a U>
or higher-ranked object types.
If that's true, why do we use PolyTraitRef
in so many places? Is it just for higher-ranked self types? If so, why is PolyTraitRef::self_ty
, which calls skip_binder
, correct?
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.
These docs are wrong. Binders are always represented explicitly by a Binder
-- so TraitRef
alone cannot account for for<'a>
, only a PolyTraitRef
can.
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.
Is this assumption correct?
I think this is sort of what I was asking. I doubt it's correct. I think a reasonable thing to do might be to test the assumption by using no_bound_vars
instead of relying on skip_binder
(and, if the assumption is false, not generating the suggestions).
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.
It seems like we want to change PolyTraitRef::self_ty
to return a Binder<Ty>
. Is this correct? This will have a significant amount of fallout I think. Do you want me to open an issue to track this? I could check the result of self_ty
for no_bound_vars
in this PR, but we need to be doing this across all diagnostics code, not just here.
@ecstatic-morse left some questions! |
91b52e7
to
955000c
Compare
This comment has been minimized.
This comment has been minimized.
OK, so, I think these changes are definitely going in the right direction. I'd probably be happy to merge as-is, seems like an improvement, though I suspect we could do a bit more refactoring to avoid some potential ICEs with higher-ranked regions down the line (along the lines of using |
☔ The latest upstream changes (presumably #72433) made this pull request unmergeable. Please resolve the merge conflicts. |
`mk_obligation_for_def_id` is only correct if the trait and self type do not have any substitutions. Use a different method, `mk_trait_obligation_with_new_self_ty` that is more clear about what is happening.
Otherwise inserting it to the `Binder` used by `trait_ref` would cause problems. This is just to be extra carefult: we aren't going to start recommending that the user start using HKTs anytime soon.
Rebased to fix merge conflict. Can I r+ this? The original intent was to fix a rather embarrassing diagnostics bug. I will open an issue for removing |
47c539a
to
1fad3b7
Compare
@bors r+ |
📌 Commit 1fad3b7 has been approved by |
🌲 The tree is currently closed for pull requests below priority 1000, this pull request will be tested once the tree is reopened |
@bors rollup |
…atsakis Preserve substitutions when making trait obligations for suggestions Resolves rust-lang#71394. I *think* `map_bound_ref` is correct here. In any case, I think a lot of the diagnostic code is using `skip_binder` more aggressively than it should be, so I doubt that this is worse than the status quo. The assertion that `new_self_ty` has no escaping bound vars should be enough. r? @estebank cc @nikomatsakis Is the call to `skip_binder` on line 551 (and elsewhere in this file) appropriate? https://github.com/rust-lang/rust/blob/46ec74e60f238f694b46c976d6217e7cf8d4cf1a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs#L537-L565
…atsakis Preserve substitutions when making trait obligations for suggestions Resolves rust-lang#71394. I *think* `map_bound_ref` is correct here. In any case, I think a lot of the diagnostic code is using `skip_binder` more aggressively than it should be, so I doubt that this is worse than the status quo. The assertion that `new_self_ty` has no escaping bound vars should be enough. r? @estebank cc @nikomatsakis Is the call to `skip_binder` on line 551 (and elsewhere in this file) appropriate? https://github.com/rust-lang/rust/blob/46ec74e60f238f694b46c976d6217e7cf8d4cf1a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs#L537-L565
Rollup of 5 pull requests Successful merges: - rust-lang#71618 (Preserve substitutions when making trait obligations for suggestions) - rust-lang#72092 (Unblock font loading in rustdoc.css) - rust-lang#72400 (Add missing ASM arena declarations to librustc_middle) - rust-lang#72489 (Fix ice-72487) - rust-lang#72502 (fix discriminant type in generator transform) Failed merges: r? @ghost
…matsakis Make `PolyTraitRef::self_ty` return `Binder<Ty>` This came up during review of rust-lang#71618. The current implementation is the same as a call to `skip_binder` but harder to audit. Make it preserve binding levels and add a call to `skip_binder` at all use sites so they can be audited as part of rust-lang#72507.
…matsakis Make `PolyTraitRef::self_ty` return `Binder<Ty>` This came up during review of rust-lang#71618. The current implementation is the same as a call to `skip_binder` but harder to audit. Make it preserve binding levels and add a call to `skip_binder` at all use sites so they can be audited as part of rust-lang#72507.
…matsakis Make `PolyTraitRef::self_ty` return `Binder<Ty>` This came up during review of rust-lang#71618. The current implementation is the same as a call to `skip_binder` but harder to audit. Make it preserve binding levels and add a call to `skip_binder` at all use sites so they can be audited as part of rust-lang#72507.
…matsakis Make `PolyTraitRef::self_ty` return `Binder<Ty>` This came up during review of rust-lang#71618. The current implementation is the same as a call to `skip_binder` but harder to audit. Make it preserve binding levels and add a call to `skip_binder` at all use sites so they can be audited as part of rust-lang#72507.
…matsakis Make `PolyTraitRef::self_ty` return `Binder<Ty>` This came up during review of rust-lang#71618. The current implementation is the same as a call to `skip_binder` but harder to audit. Make it preserve binding levels and add a call to `skip_binder` at all use sites so they can be audited as part of rust-lang#72507.
…matsakis Make `PolyTraitRef::self_ty` return `Binder<Ty>` This came up during review of rust-lang#71618. The current implementation is the same as a call to `skip_binder` but harder to audit. Make it preserve binding levels and add a call to `skip_binder` at all use sites so they can be audited as part of rust-lang#72507.
…matsakis Make `PolyTraitRef::self_ty` return `Binder<Ty>` This came up during review of rust-lang#71618. The current implementation is the same as a call to `skip_binder` but harder to audit. Make it preserve binding levels and add a call to `skip_binder` at all use sites so they can be audited as part of rust-lang#72507.
Resolves #71394.
I think
map_bound_ref
is correct here. In any case, I think a lot of the diagnostic code is usingskip_binder
more aggressively than it should be, so I doubt that this is worse than the status quo. The assertion thatnew_self_ty
has no escaping bound vars should be enough.r? @estebank
cc @nikomatsakis Is the call to
skip_binder
on line 551 (and elsewhere in this file) appropriate?rust/src/librustc_trait_selection/traits/error_reporting/suggestions.rs
Lines 537 to 565 in 46ec74e