Skip to content

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

Merged
merged 3 commits into from
Jan 27, 2018

Conversation

estebank
Copy link
Contributor

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.

@rust-highfive
Copy link
Contributor

r? @eddyb

(rust_highfive has picked a reviewer for you, use r? to override)

@estebank estebank added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jan 23, 2018
@eddyb
Copy link
Member

eddyb commented Jan 23, 2018

r? @nikomatsakis

@rust-highfive rust-highfive assigned nikomatsakis and unassigned eddyb Jan 23, 2018
@@ -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 ") => {
Copy link
Member

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)

Copy link
Contributor Author

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.

Copy link
Member

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.
Copy link
Contributor

@nikomatsakis nikomatsakis left a 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
Copy link
Contributor

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:

// `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]))
};

Copy link
Contributor Author

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?

Copy link
Contributor

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?

Copy link
Contributor Author

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

Copy link
Contributor

Choose a reason for hiding this comment

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

oooh, that's nice

Copy link
Contributor Author

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.

@nikomatsakis nikomatsakis 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 Jan 25, 2018
@estebank estebank 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 Jan 25, 2018
@estebank estebank changed the title For E0277 on for loops, point at first line For E0277 on for loops, point at the "head" expression Jan 26, 2018
@estebank estebank force-pushed the for-block-277 branch 2 times, most recently from db7be26 to 9fc426e Compare January 26, 2018 08:41
@@ -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![])
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Reverted.

17 | for i in 0..x { //~ ERROR calls in constant functions
| ^^^^
| |
| in this macro invocation
Copy link
Contributor

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?

Copy link
Contributor Author

@estebank estebank Jan 26, 2018

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
Copy link
Contributor

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.
Copy link
Contributor

@nikomatsakis nikomatsakis left a 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 `()`
Copy link
Contributor

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 🚗

Copy link
Contributor Author

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`
Copy link
Contributor

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 =)

Copy link
Contributor Author

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.

@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Collaborator

bors commented Jan 26, 2018

📌 Commit 106e5c5 has been approved by nikomatsakis

@nikomatsakis nikomatsakis added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 26, 2018
@bors
Copy link
Collaborator

bors commented Jan 27, 2018

⌛ Testing commit 106e5c5 with merge 6272b60...

bors added a commit that referenced this pull request Jan 27, 2018
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.
@bors
Copy link
Collaborator

bors commented Jan 27, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: nikomatsakis
Pushing 6272b60 to master...

@bors bors merged commit 106e5c5 into rust-lang:master Jan 27, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants