]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/pipes/check.rs
libsyntax: Explicit-self-ify pipes compiler.
[rust.git] / src / libsyntax / ext / pipes / check.rs
1 // Copyright 2012 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 /// Correctness for protocols
12
13 /*
14
15 This section of code makes sure the protocol is likely to generate
16 correct code. The correctness criteria include:
17
18   * No protocols transition to states that don't exist.
19   * Messages step to states with the right number of type parameters.
20
21 In addition, this serves as a lint pass. Lint warns for the following
22 things.
23
24   * States with no messages, it's better to step to !.
25
26 It would also be nice to warn about unreachable states, but the
27 visitor infrastructure for protocols doesn't currently work well for
28 that.
29
30 */
31
32 use core::prelude::*;
33
34 use ast;
35 use codemap::span;
36 use ext::base::ext_ctxt;
37 use ext::pipes::proto::{state, protocol, next_state};
38 use ext::pipes::proto;
39
40 pub impl proto::visitor<(), (), ()> for ext_ctxt {
41     fn visit_proto(&self, _proto: protocol,
42                    _states: &[()]) { }
43
44     fn visit_state(&self, state: state, _m: &[()]) {
45         if state.messages.len() == 0 {
46             self.span_warn(
47                 state.span, // use a real span!
48                 fmt!("state %s contains no messages, \
49                       consider stepping to a terminal state instead",
50                       state.name))
51         }
52     }
53
54     fn visit_message(&self, name: ~str, _span: span, _tys: &[@ast::Ty],
55                      this: state, next: Option<next_state>) {
56         match next {
57           Some(next_state { state: ref next, tys: next_tys }) => {
58             let proto = this.proto;
59             if !proto.has_state((*next)) {
60                 // This should be a span fatal, but then we need to
61                 // track span information.
62                 self.span_err(
63                     proto.get_state((*next)).span,
64                     fmt!("message %s steps to undefined state, %s",
65                          name, (*next)));
66             }
67             else {
68                 let next = proto.get_state((*next));
69
70                 if next.ty_params.len() != next_tys.len() {
71                     self.span_err(
72                         next.span, // use a real span
73                         fmt!("message %s target (%s) \
74                               needs %u type parameters, but got %u",
75                              name, next.name,
76                              next.ty_params.len(),
77                              next_tys.len()));
78                 }
79             }
80           }
81           None => ()
82         }
83     }
84 }
85