1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use self::Context::*;
use session::Session;
use syntax::ast;
use syntax::codemap::Span;
use syntax::visit::Visitor;
use syntax::visit;
#[derive(Clone, Copy, PartialEq)]
enum Context {
Normal, Loop, Closure
}
#[derive(Copy, Clone)]
struct CheckLoopVisitor<'a> {
sess: &'a Session,
cx: Context
}
pub fn check_crate(sess: &Session, krate: &ast::Crate) {
visit::walk_crate(&mut CheckLoopVisitor { sess: sess, cx: Normal }, krate)
}
impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
fn visit_item(&mut self, i: &ast::Item) {
self.with_context(Normal, |v| visit::walk_item(v, i));
}
fn visit_expr(&mut self, e: &ast::Expr) {
match e.node {
ast::ExprWhile(ref e, ref b, _) => {
self.visit_expr(&**e);
self.with_context(Loop, |v| v.visit_block(&**b));
}
ast::ExprLoop(ref b, _) => {
self.with_context(Loop, |v| v.visit_block(&**b));
}
ast::ExprClosure(_, _, ref b) => {
self.with_context(Closure, |v| v.visit_block(&**b));
}
ast::ExprBreak(_) => self.require_loop("break", e.span),
ast::ExprAgain(_) => self.require_loop("continue", e.span),
_ => visit::walk_expr(self, e)
}
}
}
impl<'a> CheckLoopVisitor<'a> {
fn with_context<F>(&mut self, cx: Context, f: F) where
F: FnOnce(&mut CheckLoopVisitor<'a>),
{
let old_cx = self.cx;
self.cx = cx;
f(self);
self.cx = old_cx;
}
fn require_loop(&self, name: &str, span: Span) {
match self.cx {
Loop => {}
Closure => {
span_err!(self.sess, span, E0267,
"`{}` inside of a closure", name);
}
Normal => {
span_err!(self.sess, span, E0268,
"`{}` outside of loop", name);
}
}
}
}