-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Refactor const_eval diagnostics #113297
Conversation
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 (
|
@fee1-dead weren't you planning on refactoring some of this code? or was it a different set of const-eval diagnostics? |
I opened the linked issue. |
i can't read |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Marking as waiting on author. When you are done use @rustbot author |
@rustbot ready |
☔ The latest upstream changes (presumably #113166) made this pull request unmergeable. Please resolve the merge conflicts. |
4ebf1e6
to
4a1770c
Compare
☔ The latest upstream changes (presumably #114011) made this pull request unmergeable. Please resolve the merge conflicts. |
@rustbot author |
4a1770c
to
8c8e300
Compare
@rustbot ready |
} | ||
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,) | ||
} |
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.
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:
rust/src/tools/miri/src/diagnostics.rs
Lines 339 to 347 in b08dd92
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 | |
}; |
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.
Are you saying this because of the *Ext
and *Ext2
variants both existing? *Ext
is the old implementation which I will remove.
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.. 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.
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.
*Ext
types are no longer needed, they are an IntoDiagnostic
implementation and can be completely removed since the current implementation doesn't use IntoDiagnostic
.
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.
Ah okay I see. Go ahead and remove it.
impl AddToDiagnostic for ValidationErrorInfoExt2<'_> { | ||
fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) | ||
where |
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.
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.
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.
Would you like all *Ext2
variants to be renamed in a similar fashion?
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
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'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?
@rustbot ready |
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{ |
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.
let e = InterpErrorExt{ | |
let e = InterpErrorExt { |
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 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 |
[ | ||
$(($key.into(), $value.into_diagnostic_arg()),)* | ||
].iter() | ||
.map(|(a, b)| (a, b)) |
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.
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.
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'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?
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! |
Hi @davidtwco, @RalfJung thanks a lot for the review I'll try experimenting a more with the derivable @RalfJung no worries, I understand your point of view. 😃 I'm also still learning how the |
@@ -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 |
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.
@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
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.
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.
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.
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.
cc #115089 r? @davidtwco |
☔ The latest upstream changes (presumably #115370) made this pull request unmergeable. Please resolve the merge conflicts. |
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 Still this wouldn't save us from having to manually implement
|
👍
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 :)
That's fine, you don't need a |
Think I can switch to waiting on author (if I understand correctly). @victor-timofei Feel free to request a review with @rustbot author |
@victor-timofei: friendly ping :) are you still working on this? |
@victor-timofei @rustbot label: +S-inactive |
Implement
IntoDiagnostic
for const_eval newtypes.Fixes #113117