-
Notifications
You must be signed in to change notification settings - Fork 13.3k
For E0277 on for
loops, point at the "head" expression
#47690
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
Conversation
r? @eddyb (rust_highfive has picked a reviewer for you, use r? to override) |
@@ -551,6 +551,24 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { | |||
let OnUnimplementedNote { message, label } | |||
= self.on_unimplemented_note(trait_ref, obligation); | |||
let have_alt_message = message.is_some() || label.is_some(); | |||
let span = match self.tcx.sess.codemap().span_to_snippet(span) { | |||
Ok(ref _s) if _s.starts_with("for ") => { |
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.
style nit: Ok(ref s) if s.starts_with("for ")
(pretty sure the unused-variables lint is in fact smart enough to count the if
guard as a use)
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.
For some reason I was convinced that there was a lint that complained at patterns that where only used in match guards... Must have been a different case.
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 might be thinking of how the dead-code lint complains about enum variants that are never constructed, even if they're matched on?
When E0277's span points at a `for` loop, the actual issue is in the element being iterated. Instead of pointing at the entire loop, point only at the first line (when possible) so that the span ends in the element for which E0277 was triggered.
1bf1a76
to
3a530ba
Compare
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 like the span but feel like we could do it in a more elegant way...
Also, what if people do something like
for x in
something
{
...
}
I do that from time to time...
@@ -551,6 +551,24 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { | |||
let OnUnimplementedNote { message, label } | |||
= self.on_unimplemented_note(trait_ref, obligation); | |||
let have_alt_message = message.is_some() || label.is_some(); | |||
let span = match self.tcx.sess.codemap().span_to_snippet(span) { | |||
Ok(ref s) if s.starts_with("for ") => { | |||
// On for loops, this error is caused by the element being iterated |
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.
Hmm, I like this span a lot, but I wonder if this is the right way to do this. Maybe we should adjust the span in HIR lowering instead? Roughly here:
rust/src/librustc/hir/lowering.rs
Lines 3167 to 3173 in a0dcecf
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }` | |
let into_iter_expr = { | |
let into_iter_path = &["iter", "IntoIterator", "into_iter"]; | |
let into_iter = P(self.expr_std_path(e.span, into_iter_path, | |
ThinVec::new())); | |
P(self.expr_call(e.span, into_iter, hir_vec![head])) | |
}; |
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.
Reasonable, it's definitely an overuse of span_until_char
, it was just slightly faster to figure how to do this than the proper way. Should it point at only the iterator expression or at the entire for _ in iterator_expr
?
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.
@estebank good question, I don't know the answer. Just pointing at the span of the iterator expression is obviously easier... and maybe better? I guess that showing the for
may help convey that it's "because of the for
" that IntoIterator
is needed... but that seems sort of obvious...
If we do it in lowering, we can also introduce a "synthetic" span, right, that would let us give a very tailored message if we wanted?
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.
If we do it in lowering, we can also introduce a "synthetic" span, right, that would let us give a very tailored message if we wanted?
I think so. If we want to point at the for
, we could just do that, which would look better ni the case where for
and expr
are not in the same line:
X | for _ in expr {
| --- ^^^^ `&str` is not an iterator
| |
| needed because of this `for` loop
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.
oooh, that's nice
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.
Modified the expansion code to use the appropriate span, but that makes it harder to add the appropriate span under for
.
for
loops, point at first linefor
loops, point at the "head" expression
db7be26
to
9fc426e
Compare
src/librustc/hir/lowering.rs
Outdated
@@ -2969,7 +2969,7 @@ impl<'a> LoweringContext<'a> { | |||
let body = if let Some(else_expr) = wildcard_arm { | |||
P(self.lower_expr(else_expr)) | |||
} else { | |||
self.expr_tuple(e.span, hir_vec![]) | |||
self.expr_tuple(body.span, hir_vec![]) |
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 the change to body.span here? It's not entirely intuitive to me that the (synthetic) "else clause" should get the span of the code that executes when else
does not apply. =) At minimum, a comment seems good.
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.
Reverted.
src/test/ui/const-fn-error.stderr
Outdated
17 | for i in 0..x { //~ ERROR calls in constant functions | ||
| ^^^^ | ||
| | | ||
| in this macro invocation |
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.
macro invocation? what macro? =)
Is this referring to the for loop desugaring?
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.
Fixed, it was macro desugaring been confused with macro invocations in emitter.rs
.
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
// E0277 should point exclusively at line 14, not the entire for loop 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.
nice
Modify the spans used for `for`-loop expression expansion, instead of creating a new span during error creation.
9fc426e
to
f90c445
Compare
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 turned out really good
| | | ||
| cannot use the `?` operator in a function that returns `()` | ||
| in this macro invocation | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` |
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.
nice drive-by fix 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.
😎
| ^^^^^^ `&str` is not an iterator; maybe try calling `.iter()` or a similar method | ||
| | ||
= help: the trait `std::iter::Iterator` is not implemented for `&str` | ||
= note: required by `std::iter::IntoIterator::into_iter` |
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.
it'd be cool if we could highlight the for
, but this is indeed pretty good still =)
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 agree. That will require some extra changes to report_selection_error
in order to figure out that this is part of a for
-loop desugaring in order to find the leading for
. For now I think this is enough of an improvement.
@bors r+ |
📌 Commit 106e5c5 has been approved by |
For E0277 on `for` loops, point at the "head" expression When E0277's span points at a `for` loop, the actual issue is in the element being iterated. Instead of pointing at the entire loop, point only at the first line (when possible) so that the span ends in the element for which E0277 was triggered.
☀️ Test successful - status-appveyor, status-travis |
When E0277's span points at a
for
loop, the actual issue is in theelement being iterated. Instead of pointing at the entire loop, point
only at the first line (when possible) so that the span ends in the
element for which E0277 was triggered.