-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Fix suggestion spans for expr from macro expansions #112043
Fix suggestion spans for expr from macro expansions #112043
Conversation
r? @davidtwco (rustbot has picked a reviewer for you, use r? to override) |
1b2b9ba
to
ad127e4
Compare
let parent_span = self.tcx.hir().span(parent); | ||
let span = expr.span.find_ancestor_inside(parent_span).unwrap_or(expr.span); | ||
span | ||
} |
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 happens if the function itself is generated by a macro?
What happens if a local macro generates non-trivial code? Should we suggest inside that macro?
Should we stop the parent walk when we stop seeing expressions?
To be clear: I think this heuristic is too strong, and should be refined a bit.
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 happens if the function itself is generated by a macro?
Hmm this doesn't work correctly, I need to fix it. Do you mean something like this?
macro_rules! entire_fn_outer {
() => {
entire_fn!();
}
}
macro_rules! entire_fn {
() => {
pub fn baz(x: &str) -> Result<(), Box<dyn std::error::Error>> {
Err(format!("error: {x}"))
//~^ ERROR mismatched types
}
}
}
entire_fn_outer!();
What happens if a local macro generates non-trivial code? Should we suggest inside that macro?
I'm having a hard time trying to come up with a test example for this, do you have an example in mind?
Should we stop the parent walk when we stop seeing expressions?
I'm not quite sure about this... I don't think it would be right if we stopped the parent walk when we stop seeing expressions? The parent could very well be items and not expressions?
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 having a hard time trying to come up with a test example for this, do you have an example in mind?
In your test, having the macro expand to Err(format!(...))
, instead of just the format!
.
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 unfortunately I don't think this can work...
Given something like
macro_rules! nontrivial {
($x: expr) => {
Err(format!("error: {}", $x))
//~^ ERROR mismatched types
}
}
pub fn qux(x: &str) -> Result<(), Box<dyn std::error::Error>> {
nontrivial!(x)
}
my current code will suggest nontrivial!(x).into()
which isn't correct. Should we just suppress Into::into
suggestion when expr
's span comes from a macro expansion...? Seems unfortunate but I can't think of anything that'd be correct when nontrivial macros are involved.
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 it's okay to continue making a suggestion for the macro code, perhaps only if it's a locally-defined macro (if that's easy to check here). I don't see much value in making that suggestion if the macro is defined in an external crate.
bc91f84
to
711f6b6
Compare
544f080
to
bcdffdb
Compare
bcdffdb
to
25d065b
Compare
Changes Since Last Force-PushWhereas previously I used incorrect parent node searching logic (I meant to have used parent callsites instead), the new changes differentiates treatment of finding a suitable span for suggesting For suggesting For suggesting Also made sure to have Note that I'm not 100% confident on the correctness of these two approaches. @rustbot ready |
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 seems good to me now, but I'm not 100% confident there aren't cases which wouldn't work. Does this resolve your previous concerns, @cjgillot?
Thanks. |
☀️ Test successful - checks-actions |
Finished benchmarking commit (c115ec1): comparison URL. Overall result: no relevant changes - no action needed@rustbot label: -perf-regression Instruction countThis benchmark run did not return any relevant results for this metric. Max RSS (memory usage)This benchmark run did not return any relevant results for this metric. CyclesThis benchmark run did not return any relevant results for this metric. Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 649.583s -> 649.925s (0.05%) |
@jieyouxu The test added here is causing some issues with updating Do you think you would be able to help look at trying to fix that? You can reproduce by changing The problem is that the diagnostic has a suggestion to add a
and it points to inserting the |
That's... unfortunate. I'll take a look. |
Am I understanding correctly that because rustfix got better at applying certain suggestions, it exposed another case of pointing into library code? |
Yea. |
Hm, thinking about it some more, just fixing the span of the I'm not sure how to fix that. |
That is extremely unfortunate. How would rustfix/rustc even handle conflict resolution here? It's not immediately obvious to me which suggestion is better... I would also think that it's not really a rustfix problem, but a rustc problem, since rustc is emitting conflicting machine applicable suggestions? |
It's not uncommon for rustc to suggest conflicting suggestions, which is fine as long as they are not marked MachineApplicable. Sometimes there really are several legitimate options, and it isn't feasible for rustc to know which one is the correct one. The user has to decide. On the UI tests are a little unusual in that they apply all applicabilities by default, even if they are "maybe incorrect" or "has placeholders". For example, |
Wait, I forgot this wasn't even machine applicable suggestions, both the |
Welp, one step at a time. I'll try to fix the |
Detecting conflicting suggestions seems like an interesting idea. Perhaps it could assume that all non-MachineApplicable sub-diagnostics are conflicting, and apply them separately. That would only work assuming there aren't any diagnostics where separate messages depend on one another, but I'm not aware of any offhand that are like that. Most should work like the |
BTW, thanks for responding so fast and taking a look! 😃 |
I could try to patch compiletest to make the assumption that each MaybeIncorrect (actually, it might need to assume all diagnostics) may conflict such that:
This might regress ui test suite time by quite a bit, definitely will have to do a perf run. I also need to patch up compiletest's error reporting when the fixed code doesn't compile so it actually reportings something that helps to debug... |
well the fix for diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index f09af999957..d349da95266 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1927,8 +1927,14 @@ pub(crate) fn suggest_missing_unwrap_expect(
None => sugg.to_string(),
};
+ let mut span = expr.span;
+ while expr.span.eq_ctxt(span) && let Some(parent_callsite) = span.parent_callsite()
+ {
+ span = parent_callsite;
+ }
+
err.span_suggestion_verbose(
- expr.span.shrink_to_hi(),
+ span.shrink_to_hi(),
msg,
sugg,
Applicability::HasPlaceholders,
|
and we're just left with problem of incompatible MaybeIncorrect suggestions: error[E0308]: `?` operator has incompatible types
--> /home/gh-jieyouxu/rust/tests/ui/typeck/question-mark-operator-suggestion-span.fixed:8:16
|
LL | return writeln!(w, "but not here")?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result<(), Error>`, found `()`
|
= note: `?` operator cannot convert from `()` to `Result<(), std::fmt::Error>`
= note: expected enum `Result<(), std::fmt::Error>`
found unit type `()`
help: try removing this `?`
|
LL - return writeln!(w, "but not here")?;
LL + return writeln!(w, "but not here");
|
help: try wrapping the expression in `Ok`
|
LL | return Ok(writeln!(w, "but not here")?);
| +++ +
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0308`. |
Ah actually this is more complicated than I expected: compiletest emits .fixed files, so we actually track the fixed files in version control. If I try to split solutions and apply each solution individually, i.e. one .fixed each, I am met with the problem of how do I guarantee that the .fixed files can be reproduced (as in, how do I encode their filename)?
|
Actually, we should just do the simplest and most correct thing here: delete This will definitely fix the issue. And since the suggestions are MaybeIncorrect anyway, it's okay if they conflict and don't cleanly apply together, we can verify that they don't leak stdlib implementation details already via stderr, we don't need .fixed! |
let mut span = expr.span; | ||
while expr.span.eq_ctxt(span) && let Some(parent_callsite) = span.parent_callsite() | ||
{ | ||
span = parent_callsite; | ||
} |
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.
Why is this different than Span::find_ancestor_in_same_ctxt
?
…rieril typeck: fix `?` suggestion span Noticed in <rust-lang#112043 (comment)>, if the ``` use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller ``` suggestion is applied to a macro that comes from a non-local crate (e.g. the stdlib), the suggestion span can become non-local, which will cause newer rustfix versions to fail. This PR tries to remedy the problem by recursively probing ancestors of the expression span, trying to identify the most ancestor span that is (1) still local, and (2) still shares the same syntax context as the expression. This is the same strategy used in rust-lang#112043. The test unfortunately cannot `//@ run-rustfix` because there are two conflicting MaybeIncorrect suggestions that when collectively applied, cause the fixed source file to become non-compilable. Also avoid running `//@ run-rustfix` for `tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs` because that also contains conflicting suggestions. cc `@ehuss` who noticed this. This question mark span fix + not running rustfix on the tests containing conflicting MaybeIncorrect suggestions should hopefully unblock rustfix from updating.
Rollup merge of rust-lang#123654 - jieyouxu:question-mark-span, r=Nadrieril typeck: fix `?` suggestion span Noticed in <rust-lang#112043 (comment)>, if the ``` use the `?` operator to extract the `Result<(), std::fmt::Error>` value, propagating a `Result::Err` value to the caller ``` suggestion is applied to a macro that comes from a non-local crate (e.g. the stdlib), the suggestion span can become non-local, which will cause newer rustfix versions to fail. This PR tries to remedy the problem by recursively probing ancestors of the expression span, trying to identify the most ancestor span that is (1) still local, and (2) still shares the same syntax context as the expression. This is the same strategy used in rust-lang#112043. The test unfortunately cannot `//@ run-rustfix` because there are two conflicting MaybeIncorrect suggestions that when collectively applied, cause the fixed source file to become non-compilable. Also avoid running `//@ run-rustfix` for `tests/ui/typeck/issue-112007-leaked-writeln-macro-internals.rs` because that also contains conflicting suggestions. cc `@ehuss` who noticed this. This question mark span fix + not running rustfix on the tests containing conflicting MaybeIncorrect suggestions should hopefully unblock rustfix from updating.
Issue #112007: rustc shows expanded
writeln!
macro in code suggestionBefore This PR
After This PR
Issue #110017:
format!
.into()
suggestion deletes theformat
macroBefore This PR
After This PR
Fixes #112007.
Fixes #110017.