]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/check_loop.rs
rollup merge of #17306 : scialex/fix-zsh
[rust.git] / src / librustc / middle / check_loop.rs
1 // Copyright 2012-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 use driver::session::Session;
12
13 use syntax::ast;
14 use syntax::codemap::Span;
15 use syntax::visit::Visitor;
16 use syntax::visit;
17
18 #[deriving(Clone, PartialEq)]
19 enum Context {
20     Normal, Loop, Closure
21 }
22
23 struct CheckLoopVisitor<'a> {
24     sess: &'a Session,
25     cx: Context
26 }
27
28 pub fn check_crate(sess: &Session, krate: &ast::Crate) {
29     visit::walk_crate(&mut CheckLoopVisitor { sess: sess, cx: Normal }, krate)
30 }
31
32 impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
33     fn visit_item(&mut self, i: &ast::Item) {
34         self.with_context(Normal, |v| visit::walk_item(v, i));
35     }
36
37     fn visit_expr(&mut self, e: &ast::Expr) {
38         match e.node {
39             ast::ExprWhile(ref e, ref b, _) => {
40                 self.visit_expr(&**e);
41                 self.with_context(Loop, |v| v.visit_block(&**b));
42             }
43             ast::ExprLoop(ref b, _) => {
44                 self.with_context(Loop, |v| v.visit_block(&**b));
45             }
46             ast::ExprForLoop(_, ref e, ref b, _) => {
47                 self.visit_expr(&**e);
48                 self.with_context(Loop, |v| v.visit_block(&**b));
49             }
50             ast::ExprFnBlock(_, _, ref b) |
51             ast::ExprProc(_, ref b) |
52             ast::ExprUnboxedFn(_, _, _, ref b) => {
53                 self.with_context(Closure, |v| v.visit_block(&**b));
54             }
55             ast::ExprBreak(_) => self.require_loop("break", e.span),
56             ast::ExprAgain(_) => self.require_loop("continue", e.span),
57             _ => visit::walk_expr(self, e)
58         }
59     }
60 }
61
62 impl<'a> CheckLoopVisitor<'a> {
63     fn with_context(&mut self, cx: Context, f: |&mut CheckLoopVisitor<'a>|) {
64         let old_cx = self.cx;
65         self.cx = cx;
66         f(self);
67         self.cx = old_cx;
68     }
69
70     fn require_loop(&self, name: &str, span: Span) {
71         match self.cx {
72             Loop => {}
73             Closure => {
74                 self.sess.span_err(span,
75                                    format!("`{}` inside of a closure",
76                                            name).as_slice());
77             }
78             Normal => {
79                 self.sess.span_err(span,
80                                    format!("`{}` outside of loop",
81                                            name).as_slice());
82             }
83         }
84     }
85 }