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

Refactor const_eval diagnostics #113297

Conversation

victor-timofei
Copy link

@victor-timofei victor-timofei commented Jul 3, 2023

Implement IntoDiagnostic for const_eval newtypes.

Fixes #113117

@rustbot
Copy link
Collaborator

rustbot commented Jul 3, 2023

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @compiler-errors (or someone else) soon.

Please see the contribution instructions for more information. Namely, in order to ensure the minimum review times lag, PR authors and assigned reviewers should ensure that the review label (S-waiting-on-review and S-waiting-on-author) stays updated, invoking these commands when appropriate:

  • @rustbot author: the review is finished, PR author should check the comments and take action accordingly
  • @rustbot review: the author is ready for a review, this PR will be queued again in the reviewer's queue

@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 Jul 3, 2023
@compiler-errors
Copy link
Member

@fee1-dead weren't you planning on refactoring some of this code? or was it a different set of const-eval diagnostics?

@fee1-dead
Copy link
Member

I opened the linked issue.

@compiler-errors
Copy link
Member

i can't read

compiler/rustc_const_eval/src/errors.rs Outdated Show resolved Hide resolved
compiler/rustc_const_eval/src/errors.rs Outdated Show resolved Hide resolved
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@fee1-dead
Copy link
Member

Marking as waiting on author. When you are done use @rustbot ready.

@rustbot 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 Jul 18, 2023
@victor-timofei
Copy link
Author

@rustbot ready

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

bors commented Jul 21, 2023

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

@victor-timofei victor-timofei force-pushed the refactor-const-eval-diagnostics branch from 4ebf1e6 to 4a1770c Compare July 22, 2023 22:12
@bors
Copy link
Contributor

bors commented Jul 25, 2023

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

@fee1-dead
Copy link
Member

@rustbot 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 Jul 26, 2023
@victor-timofei victor-timofei force-pushed the refactor-const-eval-diagnostics branch from 4a1770c to 8c8e300 Compare July 27, 2023 09:19
@victor-timofei
Copy link
Author

@rustbot ready

@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jul 27, 2023
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 11, 2023
Comment on lines 495 to 508
}
BoundsCheckFailed { len, index } => {
eagerly_translate_with_args!(
handler,
const_eval_bounds_check_failed,
"len",
len,
"index",
index,
)
}
DivisionByZero => {
eagerly_translate_with_args!(handler, const_eval_division_by_zero,)
}
Copy link
Member

Choose a reason for hiding this comment

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

There's a lot of code duplication and I think we should avoid that. Perhaps this should be an associated function in UndefinedBehaviorInfoExt that uses a hack similar to what I have done in miri:

let e = {
let handler = &ecx.tcx.sess.parse_sess.span_diagnostic;
let mut diag = ecx.tcx.sess.struct_allow("");
let msg = e.diagnostic_message();
e.add_args(handler, &mut diag);
let s = handler.eagerly_translate_to_string(msg, diag.args());
diag.cancel();
s
};

Copy link
Author

Choose a reason for hiding this comment

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

Are you saying this because of the *Ext and *Ext2 variants both existing? *Ext is the old implementation which I will remove.

Copy link
Member

Choose a reason for hiding this comment

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

I.. don't think that will work out? But feel free to try. I'm mostly thinking that what *Ext2 is renamed to should mostly use *Ext's code.

Copy link
Author

Choose a reason for hiding this comment

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

*Ext types are no longer needed, they are an IntoDiagnostic implementation and can be completely removed since the current implementation doesn't use IntoDiagnostic.

Copy link
Member

Choose a reason for hiding this comment

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

Ah okay I see. Go ahead and remove it.

Comment on lines 1388 to 1390
impl AddToDiagnostic for ValidationErrorInfoExt2<'_> {
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
where
Copy link
Member

Choose a reason for hiding this comment

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

ValidationErrorInfoExt2 is an unhelpful name. I think this should be an associated function for ValidationErrorInfoExt named as_subdiagnostic and this type can be called ValidationErrorInfoAsSubdiagnosticExt. Because the type name would be so long, I think you should seal it in a private module so that no one except rustc_const_eval::errors can refer to it.

Copy link
Author

Choose a reason for hiding this comment

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

Would you like all *Ext2 variants to be renamed in a similar fashion?

Copy link
Member

Choose a reason for hiding this comment

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

Yes

Copy link
Author

Choose a reason for hiding this comment

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

I've gotten rid of the *Ext and *Ext2 confusion and merged it into *Ext. Would you still like proceed with the renaming of the types?

@victor-timofei
Copy link
Author

@rustbot ready

@Dylan-DPC Dylan-DPC marked this pull request as ready for review August 18, 2023 06:46
@rustbot
Copy link
Collaborator

rustbot commented Aug 18, 2023

The Miri subtree was changed

cc @rust-lang/miri

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

diag.cancel();
s
};
let e = InterpErrorExt{
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
let e = InterpErrorExt{
let e = InterpErrorExt {

@RalfJung
Copy link
Member

RalfJung commented Aug 19, 2023

I was hoping this would simplify error handling, but a +600 line diff (!!) sounds like this is even more complicated than before? Wasn't the point that we should be able to derive a whole bunch of things?

Does this PR even further increases the number of places where I have to change things when an error message changes? I first thought so due to all the new struct types, but now I'm now sure any more. The entire thing became so messy it's hard to say what happens.^^

[
$(($key.into(), $value.into_diagnostic_arg()),)*
].iter()
.map(|(a, b)| (a, b))
Copy link
Member

Choose a reason for hiding this comment

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

What does this do? Seems to be an identity map which doesn't do anything?
Please either remove or add a comment explaining its purpose.

Copy link
Member

@davidtwco davidtwco left a comment

Choose a reason for hiding this comment

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

I'd really like to avoid making diagnostics a lot more complicated for maintainers of various parts of the compiler just for translation/diagnostic structs - we've not done a great job of that so far and it's something I'm going to be focusing on.

That said, I really appreciate the work you've put into this @victor-timofei and I've got a few ideas of how we might go about doing this in a way which is less invasive for the const_eval folks.

I'm curious about the use of eager translation. I added eager translation to support a very specific circumstance - when we had a Vec<Subdiagnostic> and that meant the same argument would be getting set multiple times - unless we translate after doing the set_arg for each element, we'd only have the final values when translating at emission time. I intended that eager translation would otherwise be unnecessary. If it's required here, then I'd be curious to learn why that is :)

I think what I'd like to see, is that we use the diagnostic macros on types like InterpError or ValidationErrorInfo. These wouldn't be sufficient, because they're missing the Span, so we'd still have InterpErrorExt or ValidationErrorInfoExt that contains the original type and the Span. We'd implement IntoDiagnostic for these types, and they would basically just do:

fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, T> {
    let diag = self.err.into_diagnostic(handler);
    diag.set_span(self.span);
    diag
}

I think this would avoid a lot of the boilerplate that you have right now. We could go a little bit further though, and add support to the macros for this type of pattern, because it's not the first time I've seen it.

#[derive(Diagnostic)]
struct SpannedInterpError {
    #[primary_span]
    span: Span
    #[original]
    error: InterpError,
}

Do you think this would work?

@RalfJung
Copy link
Member

I should also add, thanks to @victor-timofei for helping us explore this! I didn't mean to discourage you with my comment, I was just hoping that there'd be a better solution with less boilerplate. :)

The original const_eval translation PR had a +1200 line diff, so with this one we are at a total of almost +2000, which to me indicates the approach might be flawed -- but I don't understand the approach enough to suggest better ways, unfortunately. Thanks @davidtwco for chiming in!

@victor-timofei
Copy link
Author

Hi @davidtwco, @RalfJung thanks a lot for the review I'll try experimenting a more with the derivable Diagnostic now that we added the Spans. Hopefully it will reduce some of the code.

@RalfJung no worries, I understand your point of view. 😃 I'm also still learning how the Diagnostic works so I don't mind it. 😛

@@ -336,15 +336,11 @@ pub fn report_error<'tcx, 'mir>(

// FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the
Copy link
Author

Choose a reason for hiding this comment

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

@davidtwco const_eval errors are used here as titles, that is why we need to eagerly translate.

We are also doing it to avoid args "pollution" in the DiagnosticBuilder.

cc: @fee1-dead

Copy link
Member

@fee1-dead fee1-dead Aug 22, 2023

Choose a reason for hiding this comment

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

Even if you use the derive macro, the hack that worked before still works:

    let e = {
        let handler = &ecx.tcx.sess.parse_sess.span_diagnostic;
        let mut diag = ecx.tcx.sess.struct_allow("");
        let msg = e.diagnostic_message();
        e.add_args(handler, &mut diag);
        // ^^ NOTE that these two functions above don't exist for `IntoDiagnostic`,
        // but we can use `create_diagnostic` for this
        let s = handler.eagerly_translate_to_string(msg, diag.args());
        diag.cancel();
        s
    };

the FIXME is just there to encourage someone to find a better way than creating a dummy diagnostic to extract the title, and doesn't have to be fixed by this PR.

Copy link
Member

Choose a reason for hiding this comment

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

Unless I'm still misunderstanding something, the approach I've suggested should work for this - because the InterpErrorExt will call IntoDiagnostic on InterpError, it'll get the InterpError's primary message, and if it is the opposite of that which you want, then you can always change it in InterpErrorExt's implementation.

@fee1-dead
Copy link
Member

cc #115089

r? @davidtwco

@bors
Copy link
Contributor

bors commented Aug 30, 2023

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

@victor-timofei
Copy link
Author

Hi @davidtwco sorry for the delayed response. I needed some time to process this, and also was busy with other stuff 😝

So implementing the following for the spanned newtypes:

#[derive(Diagnostic)]
struct SpannedInterpError {
    #[primary_span]
    span: Span
    #[original]
    error: InterpError,
}

Would still require to implement the IntoDiagnostic trait for the "original" types, which would require moving the trait implementations and fluent messages to rustc-middle.

Still this wouldn't save us from having to manually implement IntoDiagnostic since:

  1. some enum variants (i.e.: UndefinedBehaviorInfo here, UnsupportedOpInfo here) emit custom fluent slugs.
  2. for <dyn MachineStopType> we need to iterate over a Vec<args> (although this MachineStopType does not cause the majority of the boilerplate code)
  3. and the "original" types would still be missing Span.

@davidtwco
Copy link
Member

Would still require to implement the IntoDiagnostic trait for the "original" types, which would require moving the trait implementations and fluent messages to rustc-middle.

👍

Still this wouldn't save us from having to manually implement IntoDiagnostic since:

  1. some enum variants (i.e.: UndefinedBehaviorInfo here, UnsupportedOpInfo here) emit custom fluent slugs.
  2. for <dyn MachineStopType> we need to iterate over a Vec<args> (although this MachineStopType does not cause the majority of the boilerplate code)

Without looking too closely, you would probably still need manual implementations in these cases. I'll look more closely once you've implemented the rest :)

  1. and the "original" types would still be missing Span.

That's fine, you don't need a Span to use the derive. #[primary_span] is optional.

@RalfJung
Copy link
Member

RalfJung commented Sep 6, 2023

some enum variants (i.e.: UndefinedBehaviorInfo here, UnsupportedOpInfo here) emit custom fluent slugs.

For these two, can't we have a float diagnostic that is just const_eval_custom_ub = {$message}? Then they should behave like all other diagnostics.

@apiraino
Copy link
Contributor

apiraino commented Oct 5, 2023

Think I can switch to waiting on author (if I understand correctly). @victor-timofei Feel free to request a review with @rustbot ready, thanks!

@rustbot 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 Oct 5, 2023
@fee1-dead
Copy link
Member

@victor-timofei: friendly ping :) are you still working on this?

@JohnCSimon
Copy link
Member

@victor-timofei
Ping from triage: I'm closing this due to inactivity, Please reopen when you are ready to continue with this.
Note: if you are going to continue please open the PR BEFORE you push to it, else you won't be able to reopen - this is a quirk of github.
Thanks for your contribution.

@rustbot label: +S-inactive

@JohnCSimon JohnCSimon closed this Feb 11, 2024
@rustbot rustbot added the S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. label Feb 11, 2024
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. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

finish and clean up rustc_const_eval's translatable diagnostics.
10 participants