Auto merge of #47690 - estebank:for-block-277, r=nikomatsakis
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.
This commit is contained in:
commit
6272b60dca
9 changed files with 69 additions and 54 deletions
|
@ -3033,7 +3033,7 @@ impl<'a> LoweringContext<'a> {
|
||||||
|
|
||||||
// `match <sub_expr> { ... }`
|
// `match <sub_expr> { ... }`
|
||||||
let arms = hir_vec![pat_arm, break_arm];
|
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,
|
hir::ExprMatch(sub_expr,
|
||||||
arms,
|
arms,
|
||||||
hir::MatchSource::WhileLetDesugar),
|
hir::MatchSource::WhileLetDesugar),
|
||||||
|
@ -3071,24 +3071,25 @@ impl<'a> LoweringContext<'a> {
|
||||||
|
|
||||||
// expand <head>
|
// expand <head>
|
||||||
let head = self.lower_expr(head);
|
let head = self.lower_expr(head);
|
||||||
|
let head_sp = head.span;
|
||||||
|
|
||||||
let iter = self.str_to_ident("iter");
|
let iter = self.str_to_ident("iter");
|
||||||
|
|
||||||
let next_ident = self.str_to_ident("__next");
|
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,
|
next_ident,
|
||||||
hir::BindingAnnotation::Mutable);
|
hir::BindingAnnotation::Mutable);
|
||||||
|
|
||||||
// `::std::option::Option::Some(val) => next = val`
|
// `::std::option::Option::Some(val) => next = val`
|
||||||
let pat_arm = {
|
let pat_arm = {
|
||||||
let val_ident = self.str_to_ident("val");
|
let val_ident = self.str_to_ident("val");
|
||||||
let val_pat = self.pat_ident(e.span, val_ident);
|
let val_pat = self.pat_ident(pat.span, val_ident);
|
||||||
let val_expr = P(self.expr_ident(e.span, val_ident, val_pat.id));
|
let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat.id));
|
||||||
let next_expr = P(self.expr_ident(e.span, next_ident, next_pat.id));
|
let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat.id));
|
||||||
let assign = P(self.expr(e.span,
|
let assign = P(self.expr(pat.span,
|
||||||
hir::ExprAssign(next_expr, val_expr),
|
hir::ExprAssign(next_expr, val_expr),
|
||||||
ThinVec::new()));
|
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)
|
self.arm(hir_vec![some_pat], assign)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3101,46 +3102,45 @@ impl<'a> LoweringContext<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// `mut iter`
|
// `mut iter`
|
||||||
let iter_pat = self.pat_ident_binding_mode(e.span,
|
let iter_pat = self.pat_ident_binding_mode(head_sp,
|
||||||
iter,
|
iter,
|
||||||
hir::BindingAnnotation::Mutable);
|
hir::BindingAnnotation::Mutable);
|
||||||
|
|
||||||
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
|
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
|
||||||
let match_expr = {
|
let match_expr = {
|
||||||
let iter = P(self.expr_ident(e.span, iter, iter_pat.id));
|
let iter = P(self.expr_ident(head_sp, iter, iter_pat.id));
|
||||||
let ref_mut_iter = self.expr_mut_addr_of(e.span, iter);
|
let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
|
||||||
let next_path = &["iter", "Iterator", "next"];
|
let next_path = &["iter", "Iterator", "next"];
|
||||||
let next_path = P(self.expr_std_path(e.span, next_path, ThinVec::new()));
|
let next_path = P(self.expr_std_path(head_sp, next_path, ThinVec::new()));
|
||||||
let next_expr = P(self.expr_call(e.span, next_path,
|
let next_expr = P(self.expr_call(head_sp, next_path,
|
||||||
hir_vec![ref_mut_iter]));
|
hir_vec![ref_mut_iter]));
|
||||||
let arms = hir_vec![pat_arm, break_arm];
|
let arms = hir_vec![pat_arm, break_arm];
|
||||||
|
|
||||||
P(self.expr(e.span,
|
P(self.expr(head_sp,
|
||||||
hir::ExprMatch(next_expr, arms,
|
hir::ExprMatch(next_expr, arms,
|
||||||
hir::MatchSource::ForLoopDesugar),
|
hir::MatchSource::ForLoopDesugar),
|
||||||
ThinVec::new()))
|
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 mut __next`
|
||||||
let next_let = self.stmt_let_pat(e.span,
|
let next_let = self.stmt_let_pat(head_sp,
|
||||||
None,
|
None,
|
||||||
next_pat,
|
next_pat,
|
||||||
hir::LocalSource::ForLoopDesugar);
|
hir::LocalSource::ForLoopDesugar);
|
||||||
|
|
||||||
// `let <pat> = __next`
|
// `let <pat> = __next`
|
||||||
let pat = self.lower_pat(pat);
|
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),
|
Some(next_expr),
|
||||||
pat,
|
pat,
|
||||||
hir::LocalSource::ForLoopDesugar);
|
hir::LocalSource::ForLoopDesugar);
|
||||||
|
|
||||||
let body_block = self.with_loop_scope(e.id,
|
let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
|
||||||
|this| this.lower_block(body, false));
|
|
||||||
let body_expr = P(self.expr_block(body_block, ThinVec::new()));
|
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,
|
let loop_block = P(self.block_all(e.span,
|
||||||
hir_vec![next_let,
|
hir_vec![next_let,
|
||||||
|
@ -3167,12 +3167,12 @@ impl<'a> LoweringContext<'a> {
|
||||||
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
|
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
|
||||||
let into_iter_expr = {
|
let into_iter_expr = {
|
||||||
let into_iter_path = &["iter", "IntoIterator", "into_iter"];
|
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()));
|
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,
|
into_iter_expr,
|
||||||
hir_vec![iter_arm],
|
hir_vec![iter_arm],
|
||||||
hir::MatchSource::ForLoopDesugar));
|
hir::MatchSource::ForLoopDesugar));
|
||||||
|
|
|
@ -767,6 +767,7 @@ impl EmitterWriter {
|
||||||
}
|
}
|
||||||
// Check to make sure we're not in any <*macros>
|
// Check to make sure we're not in any <*macros>
|
||||||
if !cm.span_to_filename(def_site).is_macros() &&
|
if !cm.span_to_filename(def_site).is_macros() &&
|
||||||
|
!trace.macro_decl_name.starts_with("desugaring of ") &&
|
||||||
!trace.macro_decl_name.starts_with("#[") ||
|
!trace.macro_decl_name.starts_with("#[") ||
|
||||||
always_backtrace {
|
always_backtrace {
|
||||||
new_labels.push((trace.call_site,
|
new_labels.push((trace.call_site,
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
fn changer<'a>(mut things: Box<Iterator<Item=&'a mut u8>>) {
|
fn changer<'a>(mut things: Box<Iterator<Item=&'a mut u8>>) {
|
||||||
for item in *things { *item = 0 }
|
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() {}
|
fn main() {}
|
||||||
|
|
|
@ -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
|
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
|
17 | for i in 0..x { //~ ERROR calls in constant functions
|
||||||
18 | | //~| ERROR constant function contains unimplemented
|
| ^^^^
|
||||||
19 | | sum += i;
|
|
||||||
20 | | }
|
|
||||||
| |_____^
|
|
||||||
|
|
||||||
error[E0019]: constant function contains unimplemented expression type
|
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
|
17 | for i in 0..x { //~ ERROR calls in constant functions
|
||||||
18 | | //~| ERROR constant function contains unimplemented
|
| ^^^^
|
||||||
19 | | sum += i;
|
|
||||||
20 | | }
|
|
||||||
| |_____^
|
|
||||||
|
|
||||||
error[E0080]: constant evaluation error
|
error[E0080]: constant evaluation error
|
||||||
--> $DIR/const-fn-error.rs:21:5
|
--> $DIR/const-fn-error.rs:21:5
|
||||||
|
|
|
@ -8,10 +8,10 @@ error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _,
|
||||||
found type `&_`
|
found type `&_`
|
||||||
|
|
||||||
error[E0271]: type mismatch resolving `<std::collections::hash_map::Iter<'_, _, _> as std::iter::Iterator>::Item == &_`
|
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
|
14 | for _ in HashMap::new().iter().cloned() {} //~ ERROR type mismatch
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected tuple, found reference
|
||||||
|
|
|
|
||||||
= note: expected type `(&_, &_)`
|
= note: expected type `(&_, &_)`
|
||||||
found type `&_`
|
found type `&_`
|
||||||
|
|
21
src/test/ui/suggestions/for-c-in-str.rs
Normal file
21
src/test/ui/suggestions/for-c-in-str.rs
Normal file
|
@ -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
|
||||||
|
|
||||||
|
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
src/test/ui/suggestions/for-c-in-str.stderr
Normal file
11
src/test/ui/suggestions/for-c-in-str.stderr
Normal file
|
@ -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`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -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
|
--> $DIR/try-on-option.rs:23:5
|
||||||
|
|
|
|
||||||
23 | x?; //~ the `?` operator
|
23 | x?; //~ the `?` operator
|
||||||
| --
|
| ^^ cannot use the `?` operator in a function that returns `u32`
|
||||||
| |
|
|
||||||
| cannot use the `?` operator in a function that returns `u32`
|
|
||||||
| in this macro invocation
|
|
||||||
|
|
|
|
||||||
= help: the trait `std::ops::Try` is not implemented for `u32`
|
= help: the trait `std::ops::Try` is not implemented for `u32`
|
||||||
= note: required by `std::ops::Try::from_error`
|
= note: required by `std::ops::Try::from_error`
|
||||||
|
|
|
@ -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
|
--> $DIR/try-operator-on-main.rs:19:5
|
||||||
|
|
|
|
||||||
19 | std::fs::File::open("foo")?; //~ ERROR the `?` operator can only
|
19 | std::fs::File::open("foo")?; //~ ERROR the `?` operator can only
|
||||||
| ---------------------------
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
||||||
| |
|
|
||||||
| cannot use the `?` operator in a function that returns `()`
|
|
||||||
| in this macro invocation
|
|
||||||
|
|
|
|
||||||
= help: the trait `std::ops::Try` is not implemented for `()`
|
= help: the trait `std::ops::Try` is not implemented for `()`
|
||||||
= note: required by `std::ops::Try::from_error`
|
= note: required by `std::ops::Try::from_error`
|
||||||
|
@ -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
|
--> $DIR/try-operator-on-main.rs:22:5
|
||||||
|
|
|
|
||||||
22 | ()?; //~ ERROR the `?` operator can only
|
22 | ()?; //~ ERROR the `?` operator can only
|
||||||
| ---
|
| ^^^ the `?` operator cannot be applied to type `()`
|
||||||
| |
|
|
||||||
| the `?` operator cannot be applied to type `()`
|
|
||||||
| in this macro invocation
|
|
||||||
|
|
|
|
||||||
= help: the trait `std::ops::Try` is not implemented for `()`
|
= help: the trait `std::ops::Try` is not implemented for `()`
|
||||||
= note: required by `std::ops::Try::into_result`
|
= note: required by `std::ops::Try::into_result`
|
||||||
|
@ -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
|
--> $DIR/try-operator-on-main.rs:32:5
|
||||||
|
|
|
|
||||||
32 | ()?; //~ ERROR the `?` operator can only
|
32 | ()?; //~ ERROR the `?` operator can only
|
||||||
| ---
|
| ^^^ the `?` operator cannot be applied to type `()`
|
||||||
| |
|
|
||||||
| the `?` operator cannot be applied to type `()`
|
|
||||||
| in this macro invocation
|
|
||||||
|
|
|
|
||||||
= help: the trait `std::ops::Try` is not implemented for `()`
|
= help: the trait `std::ops::Try` is not implemented for `()`
|
||||||
= note: required by `std::ops::Try::into_result`
|
= note: required by `std::ops::Try::into_result`
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue