-
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
Add shorter and more direct error for dyn AsyncFn #133267
Conversation
r? @wesleywiser rustbot has assigned @wesleywiser. Use |
HIR ty lowering was modified cc @fmease Some changes occurred in diagnostic error codes |
1e17c14
to
55d16b9
Compare
This comment has been minimized.
This comment has been minimized.
@@ -39,6 +39,16 @@ pub fn hir_ty_lowering_dyn_compatibility_violations( | |||
trait_def_id: DefId, | |||
) -> Vec<DynCompatibilityViolation> { | |||
debug_assert!(tcx.generics_of(trait_def_id).has_self); | |||
|
|||
// Check for `AsyncFn` traits first to avoid reporting various other |
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 isn't necessary, is it? I would suppose removing this doesn't actually affect anything.
// errors about the details of why these traits aren't object-safe. | ||
for supertrait in tcx.supertrait_def_ids(trait_def_id) { | ||
if tcx.trait_is_async_fn(supertrait) { | ||
let fn_trait = tcx.item_name(supertrait); |
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.
defer this call to item_name
to the error reporting.
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.
Oh, lol, you can't. If you want, you could probably remove the PartialOrd
implementation from DynCompatibilityViolation
, and change the one(?) sort call in error reporting to stop doing that.
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, I did try that initially! Hence the comments about my annoyance that I couldn't put a DefId
in the DynCompatibilityViolation
. I don't think I want to extend this PR to removing the PartialOrd
impl + sorting, as I anticipate that'll affect a number of other error outputs as well.
let hir::Node::Ty(ty) = tcx.hir_node(hir_id) else { return }; | ||
let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind else { return }; | ||
let mut hir_id = hir_id; | ||
while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) { |
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 you can use parent_iter
and take_while
rather than redoing it here.
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.
Something like this?
- let mut hir_id = hir_id;
- while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) {
- hir_id = ty.hir_id;
- }
- if tcx.parent_hir_node(hir_id).fn_sig().is_none() {
+ let parent_ty_hir_id = tcx
+ .parent_iter(hir_id)
+ .take_while(|_id, node| if let hir::Node::Ty(_) = node { true } else { false })
+ .last()
+ .unwrap_or(hir_id);
+ if tcx.parent_hir_node(parent_ty_hir_id).fn_sig().is_none() {
IMO that's harder to read. I also don't have access to parent_iter
since it's a method on Map
, though I'm probably just missing how to access that 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.
You can access Map
through tcx.hir()
.
Also, I'd probably write it a bit shorter like:
if tcx
.hir()
.parent_iter(hir_id)
.take_while(|_, node| matches!(node, hir::Node::Ty(_)))
Or actually, maybe just using skip_while
to get the next node.
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.
parent_iter
should always be preferred over repeated calls of parent_hir_node
/parent_hir_id
for performance reasons (see also docs of https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.parent_hir_id)
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.
Or actually, maybe just using skip_while to get the next node.
nit: I don't quite see how skip_while
would work here since the goal is to get the last element that matches a predicate. I think take_while
+ last
seems the most straightforward.
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, and we're immediately calling parent_hir_node
on it. So what we really want is the first node that isn't a Node::Ty
. But whatever, not worth fixing here.
compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
Outdated
Show resolved
Hide resolved
Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri Some changes occurred to the CTFE machinery cc @rust-lang/wg-const-eval |
This comment has been minimized.
This comment has been minimized.
0718a49
to
b73794d
Compare
This comment has been minimized.
This comment has been minimized.
b73794d
to
166484c
Compare
166484c
to
306702e
Compare
@bors r+ |
Sorry, but I actually have some thoughts here after some experimentation on a local branch @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.
Sorry for the churn, but actually, I looked into this a bit further on my own local checkout since I wanted to make a quick follow-up, and I think this still needs some tweaks:
-
You're not actually using the
fn_trait
item in theDynCompatibilityViolation
anywhere? Not sure if it was intentional, but I also think that's fine -- I don't think it helps with the messaging anyways (and we can always elaborate the trait def id if we want to find it later, rather than storing it into theDynCompatibilityViolation
). -
I'm gonna re-raise the question that I asked that didn't get an answer, which is why this needs a separate error code? I think that error code is kinda bespoke and unnecessary when we have a general error code E0038 for dyn compatibility violations, especially b/c we're already noting that "the trait cannot be made into an object because
async
function traits are not yet dyn-compatible". -
Also, if you want to be cool and remove the sorting and
PartialOrd
/Ord
implementation fromDynCompatibilityViolation
, it's actually totally unnecessary for sorting. If you look at the one callsite in the compiler, it sorts the list and then maps that list then sorts it again 😆. If you don't want to fix that, then that's fine too 👍
LL | fn takes_async_fn_once_implicit_dyn(_: Box<impl AsyncFnOnce()>) {} | ||
| ++++ | ||
|
||
error[E0038]: the trait `SubAsyncFn` cannot be made into an object |
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 already have an error code for object safety, why add another one? Also, I am a bit unsatisfied with the inconsistency in the error messaging between the error message above and this one. If we want to have a separate error message, it should probably read somewhat parallel to the E0038 error message.
I don't believe users really need an in-depth explanation of the implementation details for why AsyncFn*
is not dyn-compatible, and especially b/c it's something that I expect for us to fix in the medium-term future with my introduction of general AFIDT support.
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 didn't use the language "cannot be made into an object" in the new error message because my understanding was that "object-safety" is the deprecated term, and "dyn-compatibility" is the new one. I also didn't change both to use "dyn-compatibility" because that would have affected significantly more code, though I can send a separate PR for that if it is desired.
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 just making this say the same thing as what E0038 says by default is fine, and if you'd like to reword the general error message in a separate PR it should be done separately.
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.
IMO the net effect of this PR should be to deduplicate the many different dyn compatibility violations, and to add a note explaining that AsyncFn* is not object safe.
Adding a totally different error message and a new error code seem unnecessary on top of that I feel?
// in the error reporting stage, but sadly this isn't possible because | ||
// DefIds cannot be stored at this stage. Is there a better way to handle | ||
// catching the supertrait case than string comparison? | ||
fn_trait: Symbol, |
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 don't actually use this anywhere?
This CL makes a number of small changes to dyn compatibility errors: - "object safety" has been renamed to "dyn-compatibility" throughout - "Convert to enum" suggestions are no longer generated when there exists a type-generic impl of the trait or an impl for `dyn OtherTrait` - Several error messages are reorganized for user readability Additionally, the dyn compatibility error creation code has been split out into functions. cc rust-lang#132713 cc rust-lang#133267
This CL makes a number of small changes to dyn compatibility errors: - "object safety" has been renamed to "dyn-compatibility" throughout - "Convert to enum" suggestions are no longer generated when there exists a type-generic impl of the trait or an impl for `dyn OtherTrait` - Several error messages are reorganized for user readability Additionally, the dyn compatibility error creation code has been split out into functions. cc rust-lang#132713 cc rust-lang#133267
This CL makes a number of small changes to dyn compatibility errors: - "object safety" has been renamed to "dyn-compatibility" throughout - "Convert to enum" suggestions are no longer generated when there exists a type-generic impl of the trait or an impl for `dyn OtherTrait` - Several error messages are reorganized for user readability Additionally, the dyn compatibility error creation code has been split out into functions. cc rust-lang#132713 cc rust-lang#133267
Closing this in favor of some more general fixes in #133372 |
This CL makes a number of small changes to dyn compatibility errors: - "object safety" has been renamed to "dyn-compatibility" throughout - "Convert to enum" suggestions are no longer generated when there exists a type-generic impl of the trait or an impl for `dyn OtherTrait` - Several error messages are reorganized for user readability Additionally, the dyn compatibility error creation code has been split out into functions. cc rust-lang#132713 cc rust-lang#133267
This CL makes a number of small changes to dyn compatibility errors: - "object safety" has been renamed to "dyn-compatibility" throughout - "Convert to enum" suggestions are no longer generated when there exists a type-generic impl of the trait or an impl for `dyn OtherTrait` - Several error messages are reorganized for user readability Additionally, the dyn compatibility error creation code has been split out into functions. cc rust-lang#132713 cc rust-lang#133267
Fix #132713
cc #62290