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

Add shorter and more direct error for dyn AsyncFn #133267

Closed
wants to merge 1 commit into from

Conversation

cramertj
Copy link
Member

Fix #132713
cc #62290

@rustbot
Copy link
Collaborator

rustbot commented Nov 20, 2024

r? @wesleywiser

rustbot has assigned @wesleywiser.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 20, 2024
@rustbot
Copy link
Collaborator

rustbot commented Nov 20, 2024

HIR ty lowering was modified

cc @fmease

Some changes occurred in diagnostic error codes

cc @GuillaumeGomez

@cramertj cramertj added the F-async_closure `#![feature(async_closure)]` label Nov 20, 2024
@rust-log-analyzer

This comment has been minimized.

compiler/rustc_type_ir/src/interner.rs Outdated Show resolved Hide resolved
@@ -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
Copy link
Member

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);
Copy link
Member

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.

Copy link
Member

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.

Copy link
Member Author

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) {
Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member

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)

Copy link
Member Author

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.

Copy link
Member

@compiler-errors compiler-errors Nov 21, 2024

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_middle/src/ty/mod.rs Outdated Show resolved Hide resolved
@rustbot rustbot added the WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver) label Nov 21, 2024
@rustbot
Copy link
Collaborator

rustbot commented Nov 21, 2024

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

@rust-log-analyzer

This comment has been minimized.

@compiler-errors compiler-errors 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 Nov 21, 2024
@cramertj cramertj force-pushed the async-fn-dyn-err branch 2 times, most recently from 0718a49 to b73794d Compare November 21, 2024 17:57
@rust-log-analyzer

This comment has been minimized.

@compiler-errors
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented Nov 21, 2024

📌 Commit 306702e has been approved by compiler-errors

It is now in the queue for this repository.

@bors bors removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Nov 21, 2024
@bors bors added the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Nov 21, 2024
@compiler-errors
Copy link
Member

Sorry, but I actually have some thoughts here after some experimentation on a local branch

@bors r-

@bors bors 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-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Nov 21, 2024
Copy link
Member

@compiler-errors compiler-errors left a 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:

  1. You're not actually using the fn_trait item in the DynCompatibilityViolation 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 the DynCompatibilityViolation).

  2. 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".

  3. Also, if you want to be cool and remove the sorting and PartialOrd/Ord implementation from DynCompatibilityViolation, 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
Copy link
Member

@compiler-errors compiler-errors Nov 21, 2024

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.

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member

@compiler-errors compiler-errors Nov 22, 2024

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,
Copy link
Member

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?

cramertj added a commit to cramertj/rust that referenced this pull request Nov 23, 2024
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
cramertj added a commit to cramertj/rust that referenced this pull request Nov 23, 2024
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
cramertj added a commit to cramertj/rust that referenced this pull request Nov 26, 2024
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
@cramertj
Copy link
Member Author

Closing this in favor of some more general fixes in #133372

@cramertj cramertj closed this Nov 26, 2024
cramertj added a commit to cramertj/rust that referenced this pull request Nov 26, 2024
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
cramertj added a commit to cramertj/rust that referenced this pull request Nov 27, 2024
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
cramertj added a commit to cramertj/rust that referenced this pull request Dec 2, 2024
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-async_closure `#![feature(async_closure)]` S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. WG-trait-system-refactor The Rustc Trait System Refactor Initiative (-Znext-solver)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

dyn AsyncFn generates many independent errors
9 participants