Skip to content

Commit 4fc0ba1

Browse files
committed
Add a lint (currently "allow") for lets and matches which don't actually do anything (irrefutable, no bindings).
Will be useful once the semantics of _ in patterns changes to "ignore" instead of "drop" (rust-lang#10488). Closes rust-lang#11088.
1 parent 9e00272 commit 4fc0ba1

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

src/librustc/middle/lint.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub enum lint {
7070
unnecessary_qualification,
7171
while_true,
7272
path_statement,
73+
irrefutable_match_without_binding,
7374
unrecognized_lint,
7475
non_camel_case_types,
7576
non_uppercase_statics,
@@ -167,6 +168,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[
167168
default: warn
168169
}),
169170

171+
("irrefutable_match_without_binding",
172+
LintSpec {
173+
lint: irrefutable_match_without_binding,
174+
desc: "irrefutable let or match without any bindings (equivalent to inner expression)",
175+
default: allow
176+
}),
177+
170178
("unrecognized_lint",
171179
LintSpec {
172180
lint: unrecognized_lint,
@@ -921,6 +929,18 @@ fn check_path_statement(cx: &Context, s: &ast::Stmt) {
921929
}
922930
}
923931

932+
fn check_irrefutable_match_without_binding(cx: &Context, sp: Span, pats: &[@ast::Pat]) {
933+
// `pats` is one or more pattern-alternatives (i.e. pat1|pat2|pat3), *not* match arms
934+
let mut any_bindings = false;
935+
for pat in pats.iter() {
936+
pat_util::pat_bindings(cx.tcx.def_map, *pat, |_,_,_,_| any_bindings = true)
937+
}
938+
if !any_bindings {
939+
cx.span_lint(irrefutable_match_without_binding, sp,
940+
"irrefutable let or match without any bindings (equivalent to inner expression)")
941+
}
942+
}
943+
924944
fn check_item_non_camel_case_types(cx: &Context, it: &ast::item) {
925945
fn is_camel_case(cx: ty::ctxt, ident: ast::Ident) -> bool {
926946
let ident = cx.sess.str_of(ident);
@@ -1319,6 +1339,9 @@ impl<'a> Visitor<()> for Context<'a> {
13191339
ast::ExprParen(expr) => if self.negated_expr_id == e.id {
13201340
self.negated_expr_id = expr.id
13211341
},
1342+
ast::ExprMatch(_, [ast::Arm { ref pats, .. }]) => {
1343+
check_irrefutable_match_without_binding(self, e.span, *pats)
1344+
},
13221345
_ => ()
13231346
};
13241347

@@ -1334,6 +1357,11 @@ impl<'a> Visitor<()> for Context<'a> {
13341357
visit::walk_expr(self, e, ());
13351358
}
13361359

1360+
fn visit_local(&mut self, l: @ast::Local, _: ()) {
1361+
check_irrefutable_match_without_binding(self, l.span, &[l.pat]);
1362+
visit::walk_local(self, l, ())
1363+
}
1364+
13371365
fn visit_stmt(&mut self, s: @ast::Stmt, _: ()) {
13381366
check_path_statement(self, s);
13391367

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2013 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+
#[deny(irrefutable_match_without_binding)];
12+
#[allow(unused_variable)];
13+
14+
fn main() {
15+
let a = 8;
16+
let _ = a; //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression)
17+
let _ = 99; //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression)
18+
let (_, _) = (1, 2); //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression)
19+
let ((_, _), ()) = (((), ()), ()); //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression)
20+
let () = (); //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression)
21+
match 23 { //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression)
22+
_ => { }
23+
}
24+
match (1, 2) { //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression)
25+
(_, _) => { }
26+
}
27+
match false { //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression)
28+
false|true => { }
29+
}
30+
match [1, 2] { //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression)
31+
[..] => { }
32+
}
33+
match [1, 2] { //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression)
34+
[_, _] => { }
35+
}
36+
match ~666 { //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression)
37+
~_ => { }
38+
}
39+
40+
match false { // okay: more than one arm
41+
false => { },
42+
_ => { }
43+
}
44+
match [1, 2] {
45+
[..v] => { }
46+
}
47+
let ((_, (_, a)), ()) = ((1, (2, 3)), ()); // okay: has a binding
48+
let ((_, (_, ref a)), ()) = ((1, (2, 3)), ()); // okay: has a binding
49+
let ~ref x = ~789;
50+
}

0 commit comments

Comments
 (0)