Skip to content

Commit

Permalink
auto merge of #8539 : pnkfelix/rust/fsk-visitor-vpar-defaults-step2, …
Browse files Browse the repository at this point in the history
…r=graydon,nikomatsakis

r? @nikomatsakis

Follow up to #8527 (which was step 1 of 5).  See that for overall description 

Part of #7081
  • Loading branch information
bors committed Aug 19, 2013
2 parents 81a7816 + 6c15f21 commit d597f54
Show file tree
Hide file tree
Showing 8 changed files with 602 additions and 446 deletions.
96 changes: 60 additions & 36 deletions src/librustc/middle/check_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,47 +17,71 @@ use util::ppaux;

use syntax::ast::*;
use syntax::codemap;
use syntax::{oldvisit, ast_util, ast_map};
use syntax::{ast_util, ast_map};
use syntax::visit::Visitor;
use syntax::visit;

struct CheckCrateVisitor {
sess: Session,
ast_map: ast_map::map,
def_map: resolve::DefMap,
method_map: typeck::method_map,
tcx: ty::ctxt,
}

impl Visitor<bool> for CheckCrateVisitor {
fn visit_item(&mut self, i:@item, env:bool) {
check_item(self, self.sess, self.ast_map, self.def_map, i, env);
}
fn visit_pat(&mut self, p:@pat, env:bool) {
check_pat(self, p, env);
}
fn visit_expr(&mut self, ex:@expr, env:bool) {
check_expr(self, self.sess, self.def_map, self.method_map,
self.tcx, ex, env);
}
}

pub fn check_crate(sess: Session,
crate: &Crate,
ast_map: ast_map::map,
def_map: resolve::DefMap,
method_map: typeck::method_map,
tcx: ty::ctxt) {
oldvisit::visit_crate(crate, (false, oldvisit::mk_vt(@oldvisit::Visitor {
visit_item: |a,b| check_item(sess, ast_map, def_map, a, b),
visit_pat: check_pat,
visit_expr: |a,b|
check_expr(sess, def_map, method_map, tcx, a, b),
.. *oldvisit::default_visitor()
})));
let mut v = CheckCrateVisitor {
sess: sess,
ast_map: ast_map,
def_map: def_map,
method_map: method_map,
tcx: tcx,
};
visit::walk_crate(&mut v, crate, false);
sess.abort_if_errors();
}

pub fn check_item(sess: Session,
pub fn check_item(v: &mut CheckCrateVisitor,
sess: Session,
ast_map: ast_map::map,
def_map: resolve::DefMap,
it: @item,
(_is_const, v): (bool,
oldvisit::vt<bool>)) {
_is_const: bool) {
match it.node {
item_static(_, _, ex) => {
(v.visit_expr)(ex, (true, v));
v.visit_expr(ex, true);
check_item_recursion(sess, ast_map, def_map, it);
}
item_enum(ref enum_definition, _) => {
for var in (*enum_definition).variants.iter() {
for ex in var.node.disr_expr.iter() {
(v.visit_expr)(*ex, (true, v));
v.visit_expr(*ex, true);
}
}
}
_ => oldvisit::visit_item(it, (false, v))
_ => visit::walk_item(v, it, false)
}
}

pub fn check_pat(p: @pat, (_is_const, v): (bool, oldvisit::vt<bool>)) {
pub fn check_pat(v: &mut CheckCrateVisitor, p: @pat, _is_const: bool) {
fn is_str(e: @expr) -> bool {
match e.node {
expr_vstore(
Expand All @@ -72,22 +96,22 @@ pub fn check_pat(p: @pat, (_is_const, v): (bool, oldvisit::vt<bool>)) {
}
match p.node {
// Let through plain ~-string literals here
pat_lit(a) => if !is_str(a) { (v.visit_expr)(a, (true, v)); },
pat_lit(a) => if !is_str(a) { v.visit_expr(a, true); },
pat_range(a, b) => {
if !is_str(a) { (v.visit_expr)(a, (true, v)); }
if !is_str(b) { (v.visit_expr)(b, (true, v)); }
if !is_str(a) { v.visit_expr(a, true); }
if !is_str(b) { v.visit_expr(b, true); }
}
_ => oldvisit::visit_pat(p, (false, v))
_ => visit::walk_pat(v, p, false)
}
}

pub fn check_expr(sess: Session,
pub fn check_expr(v: &mut CheckCrateVisitor,
sess: Session,
def_map: resolve::DefMap,
method_map: typeck::method_map,
tcx: ty::ctxt,
e: @expr,
(is_const, v): (bool,
oldvisit::vt<bool>)) {
is_const: bool) {
if is_const {
match e.node {
expr_unary(_, deref, _) => { }
Expand Down Expand Up @@ -152,8 +176,8 @@ pub fn check_expr(sess: Session,
}
}
}
expr_paren(e) => { check_expr(sess, def_map, method_map,
tcx, e, (is_const, v)); }
expr_paren(e) => { check_expr(v, sess, def_map, method_map,
tcx, e, is_const); }
expr_vstore(_, expr_vstore_slice) |
expr_vec(_, m_imm) |
expr_addr_of(m_imm, _) |
Expand Down Expand Up @@ -192,7 +216,7 @@ pub fn check_expr(sess: Session,
}
_ => ()
}
oldvisit::visit_expr(e, (is_const, v));
visit::walk_expr(v, e, is_const);
}

#[deriving(Clone)]
Expand All @@ -204,6 +228,8 @@ struct env {
idstack: @mut ~[NodeId]
}

struct CheckItemRecursionVisitor;

// Make sure a const item doesn't recursively refer to itself
// FIXME: Should use the dependency graph when it's available (#1356)
pub fn check_item_recursion(sess: Session,
Expand All @@ -218,36 +244,34 @@ pub fn check_item_recursion(sess: Session,
idstack: @mut ~[]
};

let visitor = oldvisit::mk_vt(@oldvisit::Visitor {
visit_item: visit_item,
visit_expr: visit_expr,
.. *oldvisit::default_visitor()
});
(visitor.visit_item)(it, (env, visitor));
let mut visitor = CheckItemRecursionVisitor;
visitor.visit_item(it, env);
}

fn visit_item(it: @item, (env, v): (env, oldvisit::vt<env>)) {
impl Visitor<env> for CheckItemRecursionVisitor {
fn visit_item(&mut self, it: @item, env: env) {
if env.idstack.iter().any(|x| x == &(it.id)) {
env.sess.span_fatal(env.root_it.span, "recursive constant");
}
env.idstack.push(it.id);
oldvisit::visit_item(it, (env, v));
visit::walk_item(self, it, env);
env.idstack.pop();
}

fn visit_expr(e: @expr, (env, v): (env, oldvisit::vt<env>)) {
fn visit_expr(&mut self, e: @expr, env: env) {
match e.node {
expr_path(*) => match env.def_map.find(&e.id) {
Some(&def_static(def_id, _)) if ast_util::is_local(def_id) =>
match env.ast_map.get_copy(&def_id.node) {
ast_map::node_item(it, _) => {
(v.visit_item)(it, (env, v));
self.visit_item(it, env);
}
_ => fail!("const not bound to an item")
},
_ => ()
},
_ => ()
}
oldvisit::visit_expr(e, (env, v));
visit::walk_expr(self, e, env);
}
}
54 changes: 30 additions & 24 deletions src/librustc/middle/check_loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,58 +12,64 @@
use middle::ty;

use syntax::ast::*;
use syntax::oldvisit;
use syntax::visit;
use syntax::visit::Visitor;

#[deriving(Clone)]
pub struct Context {
in_loop: bool,
can_ret: bool
}

struct CheckLoopVisitor {
tcx: ty::ctxt,
}

pub fn check_crate(tcx: ty::ctxt, crate: &Crate) {
oldvisit::visit_crate(crate,
(Context { in_loop: false, can_ret: true },
oldvisit::mk_vt(@oldvisit::Visitor {
visit_item: |i, (_cx, v)| {
oldvisit::visit_item(i, (Context {
visit::walk_crate(&mut CheckLoopVisitor { tcx: tcx },
crate,
Context { in_loop: false, can_ret: true });
}

impl Visitor<Context> for CheckLoopVisitor {
fn visit_item(&mut self, i:@item, _cx:Context) {
visit::walk_item(self, i, Context {
in_loop: false,
can_ret: true
}, v));
},
visit_expr: |e: @expr, (cx, v): (Context, oldvisit::vt<Context>)| {
});
}

fn visit_expr(&mut self, e:@expr, cx:Context) {

match e.node {
expr_while(e, ref b) => {
(v.visit_expr)(e, (cx, v));
(v.visit_block)(b, (Context { in_loop: true,.. cx }, v));
self.visit_expr(e, cx);
self.visit_block(b, Context { in_loop: true,.. cx });
}
expr_loop(ref b, _) => {
(v.visit_block)(b, (Context { in_loop: true,.. cx }, v));
self.visit_block(b, Context { in_loop: true,.. cx });
}
expr_fn_block(_, ref b) => {
(v.visit_block)(b, (Context {
in_loop: false,
can_ret: false
}, v));
self.visit_block(b, Context { in_loop: false, can_ret: false });
}
expr_break(_) => {
if !cx.in_loop {
tcx.sess.span_err(e.span, "`break` outside of loop");
self.tcx.sess.span_err(e.span, "`break` outside of loop");
}
}
expr_again(_) => {
if !cx.in_loop {
tcx.sess.span_err(e.span, "`loop` outside of loop");
self.tcx.sess.span_err(e.span, "`loop` outside of loop");
}
}
expr_ret(oe) => {
if !cx.can_ret {
tcx.sess.span_err(e.span, "`return` in block function");
self.tcx.sess.span_err(e.span, "`return` in block function");
}
oldvisit::visit_expr_opt(oe, (cx, v));
visit::walk_expr_opt(self, oe, cx);
}
_ => oldvisit::visit_expr(e, (cx, v))
_ => visit::walk_expr(self, e, cx)
}
},
.. *oldvisit::default_visitor()
})));

}
}
54 changes: 35 additions & 19 deletions src/librustc/middle/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,50 @@ use extra::sort;
use syntax::ast::*;
use syntax::ast_util::{unguarded_pat, walk_pat};
use syntax::codemap::{span, dummy_sp, spanned};
use syntax::oldvisit;
use syntax::visit;
use syntax::visit::{Visitor,fn_kind};

pub struct MatchCheckCtxt {
tcx: ty::ctxt,
method_map: method_map,
moves_map: moves::MovesMap
}

struct CheckMatchVisitor {
cx: @MatchCheckCtxt
}

impl Visitor<()> for CheckMatchVisitor {
fn visit_expr(&mut self, ex:@expr, e:()) {
check_expr(self, self.cx, ex, e);
}
fn visit_local(&mut self, l:@Local, e:()) {
check_local(self, self.cx, l, e);
}
fn visit_fn(&mut self, fk:&fn_kind, fd:&fn_decl, b:&Block, s:span, n:NodeId, e:()) {
check_fn(self, self.cx, fk, fd, b, s, n, e);
}
}

pub fn check_crate(tcx: ty::ctxt,
method_map: method_map,
moves_map: moves::MovesMap,
crate: &Crate) {
let cx = @MatchCheckCtxt {tcx: tcx,
method_map: method_map,
moves_map: moves_map};
oldvisit::visit_crate(crate, ((), oldvisit::mk_vt(@oldvisit::Visitor {
visit_expr: |a,b| check_expr(cx, a, b),
visit_local: |a,b| check_local(cx, a, b),
visit_fn: |kind, decl, body, sp, id, (e, v)|
check_fn(cx, kind, decl, body, sp, id, (e, v)),
.. *oldvisit::default_visitor::<()>()
})));
let mut v = CheckMatchVisitor { cx: cx };

visit::walk_crate(&mut v, crate, ());

tcx.sess.abort_if_errors();
}

pub fn check_expr(cx: @MatchCheckCtxt,
pub fn check_expr(v: &mut CheckMatchVisitor,
cx: @MatchCheckCtxt,
ex: @expr,
(s, v): ((), oldvisit::vt<()>)) {
oldvisit::visit_expr(ex, (s, v));
s: ()) {
visit::walk_expr(v, ex, s);
match ex.node {
expr_match(scrut, ref arms) => {
// First, check legality of move bindings.
Expand Down Expand Up @@ -787,10 +802,11 @@ pub fn default(cx: &MatchCheckCtxt, r: &[@pat]) -> Option<~[@pat]> {
else { None }
}

pub fn check_local(cx: &MatchCheckCtxt,
pub fn check_local(v: &mut CheckMatchVisitor,
cx: &MatchCheckCtxt,
loc: @Local,
(s, v): ((), oldvisit::vt<()>)) {
oldvisit::visit_local(loc, (s, v));
s: ()) {
visit::walk_local(v, loc, s);
if is_refutable(cx, loc.pat) {
cx.tcx.sess.span_err(loc.pat.span,
"refutable pattern in local binding");
Expand All @@ -800,15 +816,15 @@ pub fn check_local(cx: &MatchCheckCtxt,
check_legality_of_move_bindings(cx, false, [ loc.pat ]);
}

pub fn check_fn(cx: &MatchCheckCtxt,
kind: &oldvisit::fn_kind,
pub fn check_fn(v: &mut CheckMatchVisitor,
cx: &MatchCheckCtxt,
kind: &visit::fn_kind,
decl: &fn_decl,
body: &Block,
sp: span,
id: NodeId,
(s, v): ((),
oldvisit::vt<()>)) {
oldvisit::visit_fn(kind, decl, body, sp, id, (s, v));
s: ()) {
visit::walk_fn(v, kind, decl, body, sp, id, s);
for input in decl.inputs.iter() {
if is_refutable(cx, input.pat) {
cx.tcx.sess.span_err(input.pat.span,
Expand Down
Loading

0 comments on commit d597f54

Please sign in to comment.