Skip to content

Commit f2a1378

Browse files
committed
syntax: desugar a for loop to a let binding to get better error
messages when the pattern is refutable. This means the compiler points directly to the pattern and said that the problem is the pattern being refutable (rather than just saying that some value isn't covered in the `match` as it did previously). Fixes #14390.
1 parent 6ddd40d commit f2a1378

File tree

3 files changed

+54
-5
lines changed

3 files changed

+54
-5
lines changed

src/librustc/middle/check_match.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -864,8 +864,13 @@ fn default(cx: &MatchCheckCtxt, r: &[@Pat]) -> Option<Vec<@Pat> > {
864864
fn check_local(cx: &mut MatchCheckCtxt, loc: &Local) {
865865
visit::walk_local(cx, loc, ());
866866
if is_refutable(cx, loc.pat) {
867+
let name = match loc.source {
868+
LocalLet => "local",
869+
LocalFor => "`for` loop"
870+
};
871+
867872
cx.tcx.sess.span_err(loc.pat.span,
868-
"refutable pattern in local binding");
873+
format!("refutable pattern in {} binding", name).as_slice());
869874
}
870875

871876
// Check legality of move bindings.

src/libsyntax/ext/expand.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,17 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
147147
// ['<ident>:] loop {
148148
// match i.next() {
149149
// None => break,
150-
// Some(<src_pat>) => <src_loop_block>
150+
// Some(mut value) => {
151+
// let <src_pat> = value;
152+
// <src_loop_block>
153+
// }
151154
// }
152155
// }
153156
// }
154157
// }
158+
//
159+
// (The use of the `let` is to give better error messages
160+
// when the pattern is refutable.)
155161

156162
let local_ident = token::gensym_ident("__i"); // FIXME #13573
157163
let next_ident = fld.cx.ident_of("next");
@@ -167,11 +173,33 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr {
167173
fld.cx.arm(span, vec!(none_pat), break_expr)
168174
};
169175

170-
// `Some(<src_pat>) => <src_loop_block>`
176+
// let <src_pat> = value;
177+
let value_ident = token::gensym_ident("__value");
178+
// this is careful to use src_pat.span so that error
179+
// messages point exact at that.
180+
let local = @ast::Local {
181+
ty: fld.cx.ty_infer(src_pat.span),
182+
pat: src_pat,
183+
init: Some(fld.cx.expr_ident(src_pat.span, value_ident)),
184+
id: ast::DUMMY_NODE_ID,
185+
span: src_pat.span,
186+
source: ast::LocalFor
187+
};
188+
let local = codemap::respan(src_pat.span, ast::DeclLocal(local));
189+
let local = @codemap::respan(span, ast::StmtDecl(@local, ast::DUMMY_NODE_ID));
190+
191+
// { let ...; <src_loop_block> }
192+
let block = fld.cx.block(span, vec![local],
193+
Some(fld.cx.expr_block(src_loop_block)));
194+
195+
// `Some(mut value) => { ... }`
196+
// Note the _'s in the name will stop any unused mutability warnings.
197+
let value_pat = fld.cx.pat_ident_binding_mode(span, value_ident,
198+
ast::BindByValue(ast::MutMutable));
171199
let some_arm =
172200
fld.cx.arm(span,
173-
vec!(fld.cx.pat_enum(span, some_path, vec!(src_pat))),
174-
fld.cx.expr_block(src_loop_block));
201+
vec!(fld.cx.pat_enum(span, some_path, vec!(value_pat))),
202+
fld.cx.expr_block(block));
175203

176204
// `match i.next() { ... }`
177205
let match_expr = {
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
fn main() {
13+
for
14+
&1 //~ ERROR refutable pattern in `for` loop binding
15+
in [1].iter() {}
16+
}

0 commit comments

Comments
 (0)