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
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 23 additions & 23 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3021,7 +3021,7 @@ impl<'a> LoweringContext<'a> {

// `match <sub_expr> { ... }`
let arms = hir_vec![pat_arm, break_arm];
let match_expr = self.expr(e.span,
let match_expr = self.expr(sub_expr.span,
hir::ExprMatch(sub_expr,
arms,
hir::MatchSource::WhileLetDesugar),
Expand Down Expand Up @@ -3059,24 +3059,25 @@ impl<'a> LoweringContext<'a> {

// expand <head>
let head = self.lower_expr(head);
let head_sp = head.span;

let iter = self.str_to_ident("iter");

let next_ident = self.str_to_ident("__next");
let next_pat = self.pat_ident_binding_mode(e.span,
let next_pat = self.pat_ident_binding_mode(pat.span,
next_ident,
hir::BindingAnnotation::Mutable);

// `::std::option::Option::Some(val) => next = val`
let pat_arm = {
let val_ident = self.str_to_ident("val");
let val_pat = self.pat_ident(e.span, val_ident);
let val_expr = P(self.expr_ident(e.span, val_ident, val_pat.id));
let next_expr = P(self.expr_ident(e.span, next_ident, next_pat.id));
let assign = P(self.expr(e.span,
let val_pat = self.pat_ident(pat.span, val_ident);
let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat.id));
let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat.id));
let assign = P(self.expr(pat.span,
hir::ExprAssign(next_expr, val_expr),
ThinVec::new()));
let some_pat = self.pat_some(e.span, val_pat);
let some_pat = self.pat_some(pat.span, val_pat);
self.arm(hir_vec![some_pat], assign)
};

Expand All @@ -3089,46 +3090,45 @@ impl<'a> LoweringContext<'a> {
};

// `mut iter`
let iter_pat = self.pat_ident_binding_mode(e.span,
let iter_pat = self.pat_ident_binding_mode(head_sp,
iter,
hir::BindingAnnotation::Mutable);

// `match ::std::iter::Iterator::next(&mut iter) { ... }`
let match_expr = {
let iter = P(self.expr_ident(e.span, iter, iter_pat.id));
let ref_mut_iter = self.expr_mut_addr_of(e.span, iter);
let iter = P(self.expr_ident(head_sp, iter, iter_pat.id));
let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
let next_path = &["iter", "Iterator", "next"];
let next_path = P(self.expr_std_path(e.span, next_path, ThinVec::new()));
let next_expr = P(self.expr_call(e.span, next_path,
let next_path = P(self.expr_std_path(head_sp, next_path, ThinVec::new()));
let next_expr = P(self.expr_call(head_sp, next_path,
hir_vec![ref_mut_iter]));
let arms = hir_vec![pat_arm, break_arm];

P(self.expr(e.span,
P(self.expr(head_sp,
hir::ExprMatch(next_expr, arms,
hir::MatchSource::ForLoopDesugar),
ThinVec::new()))
};
let match_stmt = respan(e.span, hir::StmtExpr(match_expr, self.next_id().node_id));
let match_stmt = respan(head_sp, hir::StmtExpr(match_expr, self.next_id().node_id));

let next_expr = P(self.expr_ident(e.span, next_ident, next_pat.id));
let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat.id));

// `let mut __next`
let next_let = self.stmt_let_pat(e.span,
let next_let = self.stmt_let_pat(head_sp,
None,
next_pat,
hir::LocalSource::ForLoopDesugar);

// `let <pat> = __next`
let pat = self.lower_pat(pat);
let pat_let = self.stmt_let_pat(e.span,
let pat_let = self.stmt_let_pat(head_sp,
Some(next_expr),
pat,
hir::LocalSource::ForLoopDesugar);

let body_block = self.with_loop_scope(e.id,
|this| this.lower_block(body, false));
let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
let body_expr = P(self.expr_block(body_block, ThinVec::new()));
let body_stmt = respan(e.span, hir::StmtExpr(body_expr, self.next_id().node_id));
let body_stmt = respan(body.span, hir::StmtExpr(body_expr, self.next_id().node_id));

let loop_block = P(self.block_all(e.span,
hir_vec![next_let,
Expand All @@ -3155,12 +3155,12 @@ impl<'a> LoweringContext<'a> {
// `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,
let into_iter = P(self.expr_std_path(head_sp, into_iter_path,
ThinVec::new()));
P(self.expr_call(e.span, into_iter, hir_vec![head]))
P(self.expr_call(head_sp, into_iter, hir_vec![head]))
};

let match_expr = P(self.expr_match(e.span,
let match_expr = P(self.expr_match(head_sp,
into_iter_expr,
hir_vec![iter_arm],
hir::MatchSource::ForLoopDesugar));
Expand Down
1 change: 1 addition & 0 deletions src/librustc_errors/emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,7 @@ impl EmitterWriter {
}
// Check to make sure we're not in any <*macros>
if !cm.span_to_filename(def_site).is_macros() &&
!trace.macro_decl_name.starts_with("desugaring of ") &&
!trace.macro_decl_name.starts_with("#[") ||
always_backtrace {
new_labels.push((trace.call_site,
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-20605.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

fn changer<'a>(mut things: Box<Iterator<Item=&'a mut u8>>) {
for item in *things { *item = 0 }
//~^ ERROR `std::iter::Iterator<Item=&mut u8>: std::marker::Sized` is not satisfied
//~^ ERROR the trait bound `std::iter::Iterator<Item=&mut u8>: std::marker::Sized` is not satisfied
}

fn main() {}
18 changes: 6 additions & 12 deletions src/test/ui/const-fn-error.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,16 @@ error[E0016]: blocks in constant functions are limited to items and tail express
| ^

error[E0015]: calls in constant functions are limited to constant functions, struct and enum constructors
--> $DIR/const-fn-error.rs:17:5
--> $DIR/const-fn-error.rs:17:14
|
17 | / for i in 0..x { //~ ERROR calls in constant functions
18 | | //~| ERROR constant function contains unimplemented
19 | | sum += i;
20 | | }
| |_____^
17 | for i in 0..x { //~ ERROR calls in constant functions
| ^^^^

error[E0019]: constant function contains unimplemented expression type
--> $DIR/const-fn-error.rs:17:5
--> $DIR/const-fn-error.rs:17:14
|
17 | / for i in 0..x { //~ ERROR calls in constant functions
18 | | //~| ERROR constant function contains unimplemented
19 | | sum += i;
20 | | }
| |_____^
17 | for i in 0..x { //~ ERROR calls in constant functions
| ^^^^

error[E0080]: constant evaluation error
--> $DIR/const-fn-error.rs:21:5
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issue-33941.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _,
found type `&_`

error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as std::iter::Iterator>::Item == &_`
--> $DIR/issue-33941.rs:14:5
--> $DIR/issue-33941.rs:14:14
|
14 | for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
|
= note: expected type `(&_, &_)`
found type `&_`
Expand Down
21 changes: 21 additions & 0 deletions src/test/ui/suggestions/for-c-in-str.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// 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


fn main() {
for c in "asdf" {
//~^ ERROR the trait bound `&str: std::iter::Iterator` is not satisfied
//~| NOTE `&str` is not an iterator
//~| HELP the trait `std::iter::Iterator` is not implemented for `&str`
//~| NOTE required by `std::iter::IntoIterator::into_iter`
println!("");
}
}
11 changes: 11 additions & 0 deletions src/test/ui/suggestions/for-c-in-str.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0277]: the trait bound `&str: std::iter::Iterator` is not satisfied
--> $DIR/for-c-in-str.rs:14:14
|
14 | for c in "asdf" {
| ^^^^^^ `&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.


error: aborting due to previous error

5 changes: 1 addition & 4 deletions src/test/ui/suggestions/try-on-option.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ error[E0277]: the `?` operator can only be used in a function that returns `Resu
--> $DIR/try-on-option.rs:23:5
|
23 | x?; //~ the `?` operator
| --
| |
| cannot use the `?` operator in a function that returns `u32`
| in this macro invocation
| ^^ cannot use the `?` operator in a function that returns `u32`
|
= help: the trait `std::ops::Try` is not implemented for `u32`
= note: required by `std::ops::Try::from_error`
Expand Down
15 changes: 3 additions & 12 deletions src/test/ui/suggestions/try-operator-on-main.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ error[E0277]: the `?` operator can only be used in a function that returns `Resu
--> $DIR/try-operator-on-main.rs:19:5
|
19 | std::fs::File::open("foo")?; //~ ERROR the `?` operator can only
| ---------------------------
| |
| 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.

😎

|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
Expand All @@ -14,10 +11,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `std
--> $DIR/try-operator-on-main.rs:22:5
|
22 | ()?; //~ ERROR the `?` operator can only
| ---
| |
| the `?` operator cannot be applied to type `()`
| in this macro invocation
| ^^^ the `?` operator cannot be applied to type `()`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::into_result`
Expand All @@ -38,10 +32,7 @@ error[E0277]: the `?` operator can only be applied to values that implement `std
--> $DIR/try-operator-on-main.rs:32:5
|
32 | ()?; //~ ERROR the `?` operator can only
| ---
| |
| the `?` operator cannot be applied to type `()`
| in this macro invocation
| ^^^ the `?` operator cannot be applied to type `()`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::into_result`
Expand Down