<commit_before>import front.ast;
import front.ast.ident;
import front.ast.def;
import front.ast.ann;
import driver.session;
import util.common.span;
import std.map.hashmap;
import std.list.list;
import std.list.nil;
import std.list.cons;
import std.option;
import std.option.some;
import std.option.none;
import std._str;
import std._vec;

tag scope {
    scope_crate(@ast.crate);
    scope_item(@ast.item);
    scope_block(ast.block);
    scope_arm(ast.arm);
}

type env = rec(list[scope] scopes,
               session.session sess);

fn lookup_name(&env e, ast.ident i) -> option.t[def] {

    // log "resolving name " + i;

    fn found_def_item(@ast.item i) -> option.t[def] {
        alt (i.node) {
            case (ast.item_const(_, _, _, ?id, _)) {
                ret some[def](ast.def_const(id));
            }
            case (ast.item_fn(_, _, _, ?id, _)) {
                ret some[def](ast.def_fn(id));
            }
            case (ast.item_mod(_, _, ?id)) {
                ret some[def](ast.def_mod(id));
            }
            case (ast.item_ty(_, _, _, ?id, _)) {
                ret some[def](ast.def_ty(id));
            }
            case (ast.item_tag(_, _, _, ?id)) {
                ret some[def](ast.def_ty(id));
            }
        }
    }

    fn found_decl_stmt(@ast.stmt s) -> option.t[def] {
        alt (s.node) {
            case (ast.stmt_decl(?d)) {
                alt (d.node) {
                    case (ast.decl_local(?loc)) {
                        ret some[def](ast.def_local(loc.id));
                    }
                    case (ast.decl_item(?it)) {
                        ret found_def_item(it);
                    }
                }
            }
        }
        ret none[def];
    }

    fn check_mod(ast.ident i, ast._mod m) -> option.t[def] {
        alt (m.index.find(i)) {
            case (some[ast.mod_index_entry](?ent)) {
                alt (ent) {
                    case (ast.mie_item(?ix)) {
                        ret found_def_item(m.items.(ix));
                    }
                    case (ast.mie_tag_variant(?item_idx, ?variant_idx)) {
                        alt (m.items.(item_idx).node) {
                            case (ast.item_tag(_, ?variants, _, ?tid)) {
                                auto vid = variants.(variant_idx).id;
                                ret some[def](ast.def_variant(tid, vid));
                            }
                            case (_) {
                                log "tag item not actually a tag";
                                fail;
                            }
                        }
                    }
                }
            }
            case (none[ast.mod_index_entry]) { /* fall through */ }
        }
        ret none[def];
    }

    fn in_scope(ast.ident i, &scope s) -> option.t[def] {
        alt (s) {

            case (scope_crate(?c)) {
                ret check_mod(i, c.node.module);
            }

            case (scope_item(?it)) {
                alt (it.node) {
                    case (ast.item_fn(_, ?f, _, _, _)) {
                        for (ast.arg a in f.inputs) {
                            if (_str.eq(a.ident, i)) {
                                ret some[def](ast.def_arg(a.id));
                            }
                        }
                    }
                    case (ast.item_mod(_, ?m, _)) {
                        ret check_mod(i, m);
                    }
                    case (_) { /* fall through */ }
                }
            }

            case (scope_block(?b)) {
                alt (b.node.index.find(i)) {
                    case (some[uint](?ix)) {
                        ret found_decl_stmt(b.node.stmts.(ix));
                    }
                    case (_) { /* fall through */  }
                }
            }

            case (scope_arm(?a)) {
                alt (a.index.find(i)) {
                    case (some[ast.def_id](?did)) {
                        ret some[def](ast.def_binding(did));
                    }
                    case (_) { /* fall through */  }
                }
            }
        }
        ret none[def];
    }

    ret std.list.find[scope,def](e.scopes, bind in_scope(i, _));
}

fn fold_pat_tag(&env e, &span sp, ident i, vec[@ast.pat] args,
                option.t[ast.variant_def] old_def, ann a) -> @ast.pat {
    auto new_def;
    alt (lookup_name(e, i)) {
        case (some[def](?d)) {
            alt (d) {
                case (ast.def_variant(?did, ?vid)) {
                    new_def = some[ast.variant_def](tup(did, vid));
                }
                case (_) {
                    e.sess.err("not a tag variant: " + i);
                    new_def = none[ast.variant_def];
                }
            }
        }
        case (none[def]) {
            new_def = none[ast.variant_def];
            e.sess.err("unresolved name: " + i);
        }
    }

    ret @fold.respan[ast.pat_](sp, ast.pat_tag(i, args, new_def, a));
}

fn fold_expr_name(&env e, &span sp, &ast.name n,
                  &option.t[def] d, ann a) -> @ast.expr {

    if (_vec.len[@ast.ty](n.node.types) > 0u) {
        e.sess.unimpl("resolving name expr with ty params");
    }

    auto d_ = lookup_name(e, n.node.ident);

    alt (d_) {
        case (some[def](_)) {
            // log "resolved name " + n.node.ident;
        }
        case (none[def]) {
            e.sess.err("unresolved name: " + n.node.ident);
        }
    }

    ret @fold.respan[ast.expr_](sp, ast.expr_name(n, d_, a));
}

fn fold_ty_path(&env e, &span sp, ast.path p,
                &option.t[def] d) -> @ast.ty {

    let uint len = _vec.len[ast.name](p);
    check (len != 0u);
    if (len > 1u) {
        e.sess.unimpl("resolving path ty with >1 component");
    }

    let ast.name n = p.(0);

    if (_vec.len[@ast.ty](n.node.types) > 0u) {
        e.sess.unimpl("resolving path ty with ty params");
    }

    auto d_ = lookup_name(e, n.node.ident);

    alt (d_) {
        case (some[def](_)) {
            // log "resolved name " + n.node.ident;
        }
        case (none[def]) {
            e.sess.err("unresolved name: " + n.node.ident);
        }
    }

    ret @fold.respan[ast.ty_](sp, ast.ty_path(p, d_));
}

fn update_env_for_crate(&env e, @ast.crate c) -> env {
    ret rec(scopes = cons[scope](scope_crate(c), @e.scopes) with e);
}

fn update_env_for_item(&env e, @ast.item i) -> env {
    ret rec(scopes = cons[scope](scope_item(i), @e.scopes) with e);
}

fn update_env_for_block(&env e, &ast.block b) -> env {
    ret rec(scopes = cons[scope](scope_block(b), @e.scopes) with e);
}

fn update_env_for_arm(&env e, &ast.arm p) -> env {
    ret rec(scopes = cons[scope](scope_arm(p), @e.scopes) with e);
}

fn resolve_crate(session.session sess, @ast.crate crate) -> @ast.crate {

    let fold.ast_fold[env] fld = fold.new_identity_fold[env]();

    fld = @rec( fold_pat_tag = bind fold_pat_tag(_,_,_,_,_,_),
                fold_expr_name = bind fold_expr_name(_,_,_,_,_),
                fold_ty_path = bind fold_ty_path(_,_,_,_),
                update_env_for_crate = bind update_env_for_crate(_,_),
                update_env_for_item = bind update_env_for_item(_,_),
                update_env_for_block = bind update_env_for_block(_,_),
                update_env_for_arm = bind update_env_for_arm(_,_)
                with *fld );

    auto e = rec(scopes = nil[scope],
                 sess = sess);

    ret fold.fold_crate[env](e, fld, crate);
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Teach resolve about obj items.<commit_after>import front.ast;
import front.ast.ident;
import front.ast.def;
import front.ast.ann;
import driver.session;
import util.common.span;
import std.map.hashmap;
import std.list.list;
import std.list.nil;
import std.list.cons;
import std.option;
import std.option.some;
import std.option.none;
import std._str;
import std._vec;

tag scope {
    scope_crate(@ast.crate);
    scope_item(@ast.item);
    scope_block(ast.block);
    scope_arm(ast.arm);
}

type env = rec(list[scope] scopes,
               session.session sess);

fn lookup_name(&env e, ast.ident i) -> option.t[def] {

    // log "resolving name " + i;

    fn found_def_item(@ast.item i) -> option.t[def] {
        alt (i.node) {
            case (ast.item_const(_, _, _, ?id, _)) {
                ret some[def](ast.def_const(id));
            }
            case (ast.item_fn(_, _, _, ?id, _)) {
                ret some[def](ast.def_fn(id));
            }
            case (ast.item_mod(_, _, ?id)) {
                ret some[def](ast.def_mod(id));
            }
            case (ast.item_ty(_, _, _, ?id, _)) {
                ret some[def](ast.def_ty(id));
            }
            case (ast.item_tag(_, _, _, ?id)) {
                ret some[def](ast.def_ty(id));
            }
            case (ast.item_obj(_, _, _, ?id, _)) {
                ret some[def](ast.def_obj(id));
            }
        }
    }

    fn found_decl_stmt(@ast.stmt s) -> option.t[def] {
        alt (s.node) {
            case (ast.stmt_decl(?d)) {
                alt (d.node) {
                    case (ast.decl_local(?loc)) {
                        ret some[def](ast.def_local(loc.id));
                    }
                    case (ast.decl_item(?it)) {
                        ret found_def_item(it);
                    }
                }
            }
        }
        ret none[def];
    }

    fn check_mod(ast.ident i, ast._mod m) -> option.t[def] {
        alt (m.index.find(i)) {
            case (some[ast.mod_index_entry](?ent)) {
                alt (ent) {
                    case (ast.mie_item(?ix)) {
                        ret found_def_item(m.items.(ix));
                    }
                    case (ast.mie_tag_variant(?item_idx, ?variant_idx)) {
                        alt (m.items.(item_idx).node) {
                            case (ast.item_tag(_, ?variants, _, ?tid)) {
                                auto vid = variants.(variant_idx).id;
                                ret some[def](ast.def_variant(tid, vid));
                            }
                            case (_) {
                                log "tag item not actually a tag";
                                fail;
                            }
                        }
                    }
                }
            }
            case (none[ast.mod_index_entry]) { /* fall through */ }
        }
        ret none[def];
    }

    fn in_scope(ast.ident i, &scope s) -> option.t[def] {
        alt (s) {

            case (scope_crate(?c)) {
                ret check_mod(i, c.node.module);
            }

            case (scope_item(?it)) {
                alt (it.node) {
                    case (ast.item_fn(_, ?f, _, _, _)) {
                        for (ast.arg a in f.inputs) {
                            if (_str.eq(a.ident, i)) {
                                ret some[def](ast.def_arg(a.id));
                            }
                        }
                    }
                    case (ast.item_mod(_, ?m, _)) {
                        ret check_mod(i, m);
                    }
                    case (_) { /* fall through */ }
                }
            }

            case (scope_block(?b)) {
                alt (b.node.index.find(i)) {
                    case (some[uint](?ix)) {
                        ret found_decl_stmt(b.node.stmts.(ix));
                    }
                    case (_) { /* fall through */  }
                }
            }

            case (scope_arm(?a)) {
                alt (a.index.find(i)) {
                    case (some[ast.def_id](?did)) {
                        ret some[def](ast.def_binding(did));
                    }
                    case (_) { /* fall through */  }
                }
            }
        }
        ret none[def];
    }

    ret std.list.find[scope,def](e.scopes, bind in_scope(i, _));
}

fn fold_pat_tag(&env e, &span sp, ident i, vec[@ast.pat] args,
                option.t[ast.variant_def] old_def, ann a) -> @ast.pat {
    auto new_def;
    alt (lookup_name(e, i)) {
        case (some[def](?d)) {
            alt (d) {
                case (ast.def_variant(?did, ?vid)) {
                    new_def = some[ast.variant_def](tup(did, vid));
                }
                case (_) {
                    e.sess.err("not a tag variant: " + i);
                    new_def = none[ast.variant_def];
                }
            }
        }
        case (none[def]) {
            new_def = none[ast.variant_def];
            e.sess.err("unresolved name: " + i);
        }
    }

    ret @fold.respan[ast.pat_](sp, ast.pat_tag(i, args, new_def, a));
}

fn fold_expr_name(&env e, &span sp, &ast.name n,
                  &option.t[def] d, ann a) -> @ast.expr {

    if (_vec.len[@ast.ty](n.node.types) > 0u) {
        e.sess.unimpl("resolving name expr with ty params");
    }

    auto d_ = lookup_name(e, n.node.ident);

    alt (d_) {
        case (some[def](_)) {
            // log "resolved name " + n.node.ident;
        }
        case (none[def]) {
            e.sess.err("unresolved name: " + n.node.ident);
        }
    }

    ret @fold.respan[ast.expr_](sp, ast.expr_name(n, d_, a));
}

fn fold_ty_path(&env e, &span sp, ast.path p,
                &option.t[def] d) -> @ast.ty {

    let uint len = _vec.len[ast.name](p);
    check (len != 0u);
    if (len > 1u) {
        e.sess.unimpl("resolving path ty with >1 component");
    }

    let ast.name n = p.(0);

    if (_vec.len[@ast.ty](n.node.types) > 0u) {
        e.sess.unimpl("resolving path ty with ty params");
    }

    auto d_ = lookup_name(e, n.node.ident);

    alt (d_) {
        case (some[def](_)) {
            // log "resolved name " + n.node.ident;
        }
        case (none[def]) {
            e.sess.err("unresolved name: " + n.node.ident);
        }
    }

    ret @fold.respan[ast.ty_](sp, ast.ty_path(p, d_));
}

fn update_env_for_crate(&env e, @ast.crate c) -> env {
    ret rec(scopes = cons[scope](scope_crate(c), @e.scopes) with e);
}

fn update_env_for_item(&env e, @ast.item i) -> env {
    ret rec(scopes = cons[scope](scope_item(i), @e.scopes) with e);
}

fn update_env_for_block(&env e, &ast.block b) -> env {
    ret rec(scopes = cons[scope](scope_block(b), @e.scopes) with e);
}

fn update_env_for_arm(&env e, &ast.arm p) -> env {
    ret rec(scopes = cons[scope](scope_arm(p), @e.scopes) with e);
}

fn resolve_crate(session.session sess, @ast.crate crate) -> @ast.crate {

    let fold.ast_fold[env] fld = fold.new_identity_fold[env]();

    fld = @rec( fold_pat_tag = bind fold_pat_tag(_,_,_,_,_,_),
                fold_expr_name = bind fold_expr_name(_,_,_,_,_),
                fold_ty_path = bind fold_ty_path(_,_,_,_),
                update_env_for_crate = bind update_env_for_crate(_,_),
                update_env_for_item = bind update_env_for_item(_,_),
                update_env_for_block = bind update_env_for_block(_,_),
                update_env_for_arm = bind update_env_for_arm(_,_)
                with *fld );

    auto e = rec(scopes = nil[scope],
                 sess = sess);

    ret fold.fold_crate[env](e, fld, crate);
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>import std::vec;
import std::uint;
import std::str;
import std::term;
import std::io;
import std::option;
import std::option::some;
import std::option::none;

type filename = str;

type file_pos = {ch: uint, byte: uint};

/* A codemap is a thing that maps uints to file/line/column positions
 * in a crate. This to make it possible to represent the positions
 * with single-word things, rather than passing records all over the
 * compiler.
 */
type filemap =
    @{name: filename, start_pos: file_pos, mutable lines: [file_pos]};

type codemap = @{mutable files: [filemap]};

type loc = {filename: filename, line: uint, col: uint};

fn new_codemap() -> codemap { ret @{mutable files: []}; }

fn new_filemap(filename: filename, start_pos_ch: uint, start_pos_byte: uint)
   -> filemap {
    ret @{name: filename,
          start_pos: {ch: start_pos_ch, byte: start_pos_byte},
          mutable lines: [{ch: start_pos_ch, byte: start_pos_byte}]};
}

fn next_line(file: filemap, chpos: uint, byte_pos: uint) {
    file.lines += [{ch: chpos, byte: byte_pos}];
}

type lookup_fn = fn(file_pos) -> uint;

fn lookup_pos(map: codemap, pos: uint, lookup: lookup_fn) -> loc {
    let a = 0u;
    let b = vec::len(map.files);
    while b - a > 1u {
        let m = (a + b) / 2u;
        if lookup(map.files[m].start_pos) > pos { b = m; } else { a = m; }
    }
    let f = map.files[a];
    a = 0u;
    b = vec::len(f.lines);
    while b - a > 1u {
        let m = (a + b) / 2u;
        if lookup(f.lines[m]) > pos { b = m; } else { a = m; }
    }
    ret {filename: f.name, line: a + 1u, col: pos - lookup(f.lines[a])};
}

fn lookup_char_pos(map: codemap, pos: uint) -> loc {
    fn lookup(pos: file_pos) -> uint { ret pos.ch; }
    ret lookup_pos(map, pos, lookup);
}

fn lookup_byte_pos(map: codemap, pos: uint) -> loc {
    fn lookup(pos: file_pos) -> uint { ret pos.byte; }
    ret lookup_pos(map, pos, lookup);
}

tag opt_span {
     //hack (as opposed to option::t), to make `span` compile
    os_none;
    os_some(@span);
}
type span = {lo: uint, hi: uint, expanded_from: opt_span};

fn span_to_str(sp: &span, cm: &codemap) -> str {
    let cur = sp;
    let res = "";
    let prev_file = none;
    while true {
        let lo = lookup_char_pos(cm, cur.lo);
        let hi = lookup_char_pos(cm, cur.hi);
        res +=
            #fmt["%s:%u:%u: %u:%u",
                 if some(lo.filename) == prev_file {
                     "-"
                 } else { lo.filename }, lo.line, lo.col, hi.line, hi.col];
        alt cur.expanded_from {
          os_none. { break; }
          os_some(new_sp) {
            cur = *new_sp;
            prev_file = some(lo.filename);
            res += "<<";
          }
        }
    }

    ret res;
}

fn emit_diagnostic(sp: &option::t<span>, msg: &str, kind: &str, color: u8,
                   cm: &codemap) {
    let ss = "<input>:0:0:0:0";
    let maybe_lines: option::t<@file_lines> = none;
    alt sp {
      some(ssp) {
        ss = span_to_str(ssp, cm);
        maybe_lines = some(span_to_lines(ssp, cm));
      }
      none. { }
    }
    io::stdout().write_str(ss + " ");
    if term::color_supported() {
        term::fg(io::stdout().get_buf_writer(), color);
    }
    io::stdout().write_str(#fmt["%s:", kind]);
    if term::color_supported() { term::reset(io::stdout().get_buf_writer()); }
    io::stdout().write_str(#fmt[" %s\n", msg]);

    maybe_highlight_lines(sp, cm, maybe_lines);
}

fn maybe_highlight_lines(sp: &option::t<span>, cm: &codemap,
                         maybe_lines: option::t<@file_lines>) {

    alt maybe_lines {
      some(lines) {
        // If we're not looking at a real file then we can't re-open it to
        // pull out the lines
        if lines.name == "-" { ret; }

        // FIXME: reading in the entire file is the worst possible way to
        //        get access to the necessary lines.
        let file = io::read_whole_file_str(lines.name);
        let fm = get_filemap(cm, lines.name);

        // arbitrarily only print up to six lines of the error
        let max_lines = 6u;
        let elided = false;
        let display_lines = lines.lines;
        if vec::len(display_lines) > max_lines {
            display_lines = vec::slice(display_lines, 0u, max_lines);
            elided = true;
        }
        // Print the offending lines
        for line: uint in display_lines {
            io::stdout().write_str(#fmt["%s:%u ", fm.name, line + 1u]);
            let s = get_line(fm, line as int, file);
            if !str::ends_with(s, "\n") { s += "\n"; }
            io::stdout().write_str(s);
        }
        if elided {
            let last_line = display_lines[vec::len(display_lines) - 1u];
            let s = #fmt["%s:%u ", fm.name, last_line + 1u];
            let indent = str::char_len(s);
            let out = "";
            while indent > 0u { out += " "; indent -= 1u; }
            out += "...\n";
            io::stdout().write_str(out);
        }

        // If there's one line at fault we can easily point to the problem
        if vec::len(lines.lines) == 1u {
            let lo = lookup_char_pos(cm, option::get(sp).lo);
            let digits = 0u;
            let num = lines.lines[0] / 10u;

            // how many digits must be indent past?
            while num > 0u { num /= 10u; digits += 1u; }

            // indent past |name:## | and the 0-offset column location
            let left = str::char_len(fm.name) + digits + lo.col + 3u;
            let s = "";
            while left > 0u { str::push_char(s, ' '); left -= 1u; }

            s += "^";
            let hi = lookup_char_pos(cm, option::get(sp).hi);
            if hi.col != lo.col {
                // the ^ already takes up one space
                let width = hi.col - lo.col - 1u;
                while width > 0u { str::push_char(s, '~'); width -= 1u; }
            }
            io::stdout().write_str(s + "\n");
        }
      }
      _ { }
    }
}

fn emit_warning(sp: &option::t<span>, msg: &str, cm: &codemap) {
    emit_diagnostic(sp, msg, "warning", 11u8, cm);
}
fn emit_error(sp: &option::t<span>, msg: &str, cm: &codemap) {
    emit_diagnostic(sp, msg, "error", 9u8, cm);
}
fn emit_note(sp: &option::t<span>, msg: &str, cm: &codemap) {
    emit_diagnostic(sp, msg, "note", 10u8, cm);
}

type file_lines = {name: str, lines: [uint]};

fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines {
    let lo = lookup_char_pos(cm, sp.lo);
    let hi = lookup_char_pos(cm, sp.hi);
    let lines = [];
    for each i: uint in uint::range(lo.line - 1u, hi.line as uint) {
        lines += [i];
    }
    ret @{name: lo.filename, lines: lines};
}

fn get_line(fm: filemap, line: int, file: &str) -> str {
    let begin: uint = fm.lines[line].byte - fm.start_pos.byte;
    let end: uint;
    if line as uint < vec::len(fm.lines) - 1u {
        end = fm.lines[line + 1].byte - fm.start_pos.byte;
    } else {
        // If we're not done parsing the file, we're at the limit of what's
        // parsed. If we just slice the rest of the string, we'll print out
        // the remainder of the file, which is undesirable.
        end = str::byte_len(file);
        let rest = str::slice(file, begin, end);
        let newline = str::index(rest, '\n' as u8);
        if newline != -1 { end = begin + (newline as uint); }
    }
    ret str::slice(file, begin, end);
}

fn get_filemap(cm: codemap, filename: str) -> filemap {
    for fm: filemap in cm.files { if fm.name == filename { ret fm; } }
    //XXjdm the following triggers a mismatched type bug
    //      (or expected function, found _|_)
    fail; // ("asking for " + filename + " which we don't know about");
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Don't output bogus spans when reporting a message without one.<commit_after>import std::vec;
import std::uint;
import std::str;
import std::term;
import std::io;
import std::option;
import std::option::some;
import std::option::none;

type filename = str;

type file_pos = {ch: uint, byte: uint};

/* A codemap is a thing that maps uints to file/line/column positions
 * in a crate. This to make it possible to represent the positions
 * with single-word things, rather than passing records all over the
 * compiler.
 */
type filemap =
    @{name: filename, start_pos: file_pos, mutable lines: [file_pos]};

type codemap = @{mutable files: [filemap]};

type loc = {filename: filename, line: uint, col: uint};

fn new_codemap() -> codemap { ret @{mutable files: []}; }

fn new_filemap(filename: filename, start_pos_ch: uint, start_pos_byte: uint)
   -> filemap {
    ret @{name: filename,
          start_pos: {ch: start_pos_ch, byte: start_pos_byte},
          mutable lines: [{ch: start_pos_ch, byte: start_pos_byte}]};
}

fn next_line(file: filemap, chpos: uint, byte_pos: uint) {
    file.lines += [{ch: chpos, byte: byte_pos}];
}

type lookup_fn = fn(file_pos) -> uint;

fn lookup_pos(map: codemap, pos: uint, lookup: lookup_fn) -> loc {
    let a = 0u;
    let b = vec::len(map.files);
    while b - a > 1u {
        let m = (a + b) / 2u;
        if lookup(map.files[m].start_pos) > pos { b = m; } else { a = m; }
    }
    let f = map.files[a];
    a = 0u;
    b = vec::len(f.lines);
    while b - a > 1u {
        let m = (a + b) / 2u;
        if lookup(f.lines[m]) > pos { b = m; } else { a = m; }
    }
    ret {filename: f.name, line: a + 1u, col: pos - lookup(f.lines[a])};
}

fn lookup_char_pos(map: codemap, pos: uint) -> loc {
    fn lookup(pos: file_pos) -> uint { ret pos.ch; }
    ret lookup_pos(map, pos, lookup);
}

fn lookup_byte_pos(map: codemap, pos: uint) -> loc {
    fn lookup(pos: file_pos) -> uint { ret pos.byte; }
    ret lookup_pos(map, pos, lookup);
}

tag opt_span {
     //hack (as opposed to option::t), to make `span` compile
    os_none;
    os_some(@span);
}
type span = {lo: uint, hi: uint, expanded_from: opt_span};

fn span_to_str(sp: &span, cm: &codemap) -> str {
    let cur = sp;
    let res = "";
    let prev_file = none;
    while true {
        let lo = lookup_char_pos(cm, cur.lo);
        let hi = lookup_char_pos(cm, cur.hi);
        res +=
            #fmt["%s:%u:%u: %u:%u",
                 if some(lo.filename) == prev_file {
                     "-"
                 } else { lo.filename }, lo.line, lo.col, hi.line, hi.col];
        alt cur.expanded_from {
          os_none. { break; }
          os_some(new_sp) {
            cur = *new_sp;
            prev_file = some(lo.filename);
            res += "<<";
          }
        }
    }

    ret res;
}

fn emit_diagnostic(sp: &option::t<span>, msg: &str, kind: &str, color: u8,
                   cm: &codemap) {
    let ss = "";
    let maybe_lines: option::t<@file_lines> = none;
    alt sp {
      some(ssp) {
        ss = span_to_str(ssp, cm) + " ";
        maybe_lines = some(span_to_lines(ssp, cm));
      }
      none. { }
    }
    io::stdout().write_str(ss);
    if term::color_supported() {
        term::fg(io::stdout().get_buf_writer(), color);
    }
    io::stdout().write_str(#fmt["%s:", kind]);
    if term::color_supported() { term::reset(io::stdout().get_buf_writer()); }
    io::stdout().write_str(#fmt[" %s\n", msg]);

    maybe_highlight_lines(sp, cm, maybe_lines);
}

fn maybe_highlight_lines(sp: &option::t<span>, cm: &codemap,
                         maybe_lines: option::t<@file_lines>) {

    alt maybe_lines {
      some(lines) {
        // If we're not looking at a real file then we can't re-open it to
        // pull out the lines
        if lines.name == "-" { ret; }

        // FIXME: reading in the entire file is the worst possible way to
        //        get access to the necessary lines.
        let file = io::read_whole_file_str(lines.name);
        let fm = get_filemap(cm, lines.name);

        // arbitrarily only print up to six lines of the error
        let max_lines = 6u;
        let elided = false;
        let display_lines = lines.lines;
        if vec::len(display_lines) > max_lines {
            display_lines = vec::slice(display_lines, 0u, max_lines);
            elided = true;
        }
        // Print the offending lines
        for line: uint in display_lines {
            io::stdout().write_str(#fmt["%s:%u ", fm.name, line + 1u]);
            let s = get_line(fm, line as int, file);
            if !str::ends_with(s, "\n") { s += "\n"; }
            io::stdout().write_str(s);
        }
        if elided {
            let last_line = display_lines[vec::len(display_lines) - 1u];
            let s = #fmt["%s:%u ", fm.name, last_line + 1u];
            let indent = str::char_len(s);
            let out = "";
            while indent > 0u { out += " "; indent -= 1u; }
            out += "...\n";
            io::stdout().write_str(out);
        }

        // If there's one line at fault we can easily point to the problem
        if vec::len(lines.lines) == 1u {
            let lo = lookup_char_pos(cm, option::get(sp).lo);
            let digits = 0u;
            let num = lines.lines[0] / 10u;

            // how many digits must be indent past?
            while num > 0u { num /= 10u; digits += 1u; }

            // indent past |name:## | and the 0-offset column location
            let left = str::char_len(fm.name) + digits + lo.col + 3u;
            let s = "";
            while left > 0u { str::push_char(s, ' '); left -= 1u; }

            s += "^";
            let hi = lookup_char_pos(cm, option::get(sp).hi);
            if hi.col != lo.col {
                // the ^ already takes up one space
                let width = hi.col - lo.col - 1u;
                while width > 0u { str::push_char(s, '~'); width -= 1u; }
            }
            io::stdout().write_str(s + "\n");
        }
      }
      _ { }
    }
}

fn emit_warning(sp: &option::t<span>, msg: &str, cm: &codemap) {
    emit_diagnostic(sp, msg, "warning", 11u8, cm);
}
fn emit_error(sp: &option::t<span>, msg: &str, cm: &codemap) {
    emit_diagnostic(sp, msg, "error", 9u8, cm);
}
fn emit_note(sp: &option::t<span>, msg: &str, cm: &codemap) {
    emit_diagnostic(sp, msg, "note", 10u8, cm);
}

type file_lines = {name: str, lines: [uint]};

fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines {
    let lo = lookup_char_pos(cm, sp.lo);
    let hi = lookup_char_pos(cm, sp.hi);
    let lines = [];
    for each i: uint in uint::range(lo.line - 1u, hi.line as uint) {
        lines += [i];
    }
    ret @{name: lo.filename, lines: lines};
}

fn get_line(fm: filemap, line: int, file: &str) -> str {
    let begin: uint = fm.lines[line].byte - fm.start_pos.byte;
    let end: uint;
    if line as uint < vec::len(fm.lines) - 1u {
        end = fm.lines[line + 1].byte - fm.start_pos.byte;
    } else {
        // If we're not done parsing the file, we're at the limit of what's
        // parsed. If we just slice the rest of the string, we'll print out
        // the remainder of the file, which is undesirable.
        end = str::byte_len(file);
        let rest = str::slice(file, begin, end);
        let newline = str::index(rest, '\n' as u8);
        if newline != -1 { end = begin + (newline as uint); }
    }
    ret str::slice(file, begin, end);
}

fn get_filemap(cm: codemap, filename: str) -> filemap {
    for fm: filemap in cm.files { if fm.name == filename { ret fm; } }
    //XXjdm the following triggers a mismatched type bug
    //      (or expected function, found _|_)
    fail; // ("asking for " + filename + " which we don't know about");
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Calculation of the (misnamed) "strict version hash" for crates and
//! items. This hash is used to tell when the HIR changed in such a
//! way that results from previous compilations may no longer be
//! applicable and hence must be recomputed. It should probably be
//! renamed to the ICH (incremental compilation hash).
//!
//! The hashes for all items are computed once at the beginning of
//! compilation and stored into a map. In addition, a hash is computed
//! of the **entire crate**.
//!
//! Storing the hashes in a map avoids the need to compute them twice
//! (once when loading prior incremental results and once when
//! saving), but it is also important for correctness: at least as of
//! the time of this writing, the typeck passes rewrites entries in
//! the dep-map in-place to accommodate UFCS resolutions. Since name
//! resolution is part of the hash, the result is that hashes computed
//! at the end of compilation would be different from those computed
//! at the beginning.

use syntax::ast;
use std::cell::RefCell;
use std::hash::Hash;
use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::hir::intravisit as visit;
use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
use rustc::ty::TyCtxt;
use rustc_data_structures::stable_hasher::StableHasher;
use ich::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc::util::common::record_time;
use rustc::session::config::DebugInfoLevel::NoDebugInfo;

use self::def_path_hash::DefPathHashes;
use self::svh_visitor::StrictVersionHashVisitor;
use self::caching_codemap_view::CachingCodemapView;

mod def_path_hash;
mod svh_visitor;
mod caching_codemap_view;

pub type IchHasher = StableHasher<Fingerprint>;

pub struct IncrementalHashesMap {
    hashes: FxHashMap<DepNode<DefId>, Fingerprint>,

    // These are the metadata hashes for the current crate as they were stored
    // during the last compilation session. They are only loaded if
    // -Z query-dep-graph was specified and are needed for auto-tests using
    // the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to
    // check whether some metadata hash has changed in between two revisions.
    pub prev_metadata_hashes: RefCell<FxHashMap<DefId, Fingerprint>>,
}

impl IncrementalHashesMap {
    pub fn new() -> IncrementalHashesMap {
        IncrementalHashesMap {
            hashes: FxHashMap(),
            prev_metadata_hashes: RefCell::new(FxHashMap()),
        }
    }

    pub fn insert(&mut self, k: DepNode<DefId>, v: Fingerprint) -> Option<Fingerprint> {
        self.hashes.insert(k, v)
    }

    pub fn iter<'a>(&'a self)
                    -> ::std::collections::hash_map::Iter<'a, DepNode<DefId>, Fingerprint> {
        self.hashes.iter()
    }

    pub fn len(&self) -> usize {
        self.hashes.len()
    }
}

impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
    type Output = Fingerprint;

    fn index(&self, index: &'a DepNode<DefId>) -> &Fingerprint {
        match self.hashes.get(index) {
            Some(fingerprint) => fingerprint,
            None => {
                bug!("Could not find ICH for {:?}", index);
            }
        }
    }
}

pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
                                                    -> IncrementalHashesMap {
    let _ignore = tcx.dep_graph.in_ignore();
    let krate = tcx.map.krate();
    let hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo;
    let mut visitor = HashItemsVisitor {
        tcx: tcx,
        hashes: IncrementalHashesMap::new(),
        def_path_hashes: DefPathHashes::new(tcx),
        codemap: CachingCodemapView::new(tcx),
        hash_spans: hash_spans,
    };
    record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
        visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| {
            v.hash_crate_root_module(krate);
        });
        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());

        for macro_def in krate.exported_macros.iter() {
            visitor.calculate_node_id(macro_def.id,
                                      |v| v.visit_macro_def(macro_def));
        }
    });

    tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);

    record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
    visitor.hashes
}

struct HashItemsVisitor<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    def_path_hashes: DefPathHashes<'a, 'tcx>,
    codemap: CachingCodemapView<'tcx>,
    hashes: IncrementalHashesMap,
    hash_spans: bool,
}

impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
    fn calculate_node_id<W>(&mut self, id: ast::NodeId, walk_op: W)
        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
    {
        let def_id = self.tcx.map.local_def_id(id);
        self.calculate_def_id(def_id, walk_op)
    }

    fn calculate_def_id<W>(&mut self, def_id: DefId, mut walk_op: W)
        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
    {
        assert!(def_id.is_local());
        debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
        self.calculate_def_hash(DepNode::Hir(def_id), false, &mut walk_op);
        self.calculate_def_hash(DepNode::HirBody(def_id), true, &mut walk_op);
    }

    fn calculate_def_hash<W>(&mut self,
                             dep_node: DepNode<DefId>,
                             hash_bodies: bool,
                             walk_op: &mut W)
        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
    {
        let mut state = IchHasher::new();
        walk_op(&mut StrictVersionHashVisitor::new(&mut state,
                                                   self.tcx,
                                                   &mut self.def_path_hashes,
                                                   &mut self.codemap,
                                                   self.hash_spans,
                                                   hash_bodies));
        let bytes_hashed = state.bytes_hashed();
        let item_hash = state.finish();
        debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash);
        self.hashes.insert(dep_node, item_hash);

        let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
            bytes_hashed;
        self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
    }

    fn compute_crate_hash(&mut self) {
        let krate = self.tcx.map.krate();

        let mut crate_state = IchHasher::new();

        let crate_disambiguator = self.tcx.sess.local_crate_disambiguator();
        "crate_disambiguator".hash(&mut crate_state);
        crate_disambiguator.as_str().len().hash(&mut crate_state);
        crate_disambiguator.as_str().hash(&mut crate_state);

        // add each item (in some deterministic order) to the overall
        // crate hash.
        {
            let def_path_hashes = &mut self.def_path_hashes;
            let mut item_hashes: Vec<_> =
                self.hashes.iter()
                           .map(|(item_dep_node, &item_hash)| {
                               // convert from a DepNode<DefId> tp a
                               // DepNode<u64> where the u64 is the
                               // hash of the def-id's def-path:
                               let item_dep_node =
                                   item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did)))
                                                .unwrap();
                               (item_dep_node, item_hash)
                           })
                           .collect();
            item_hashes.sort(); // avoid artificial dependencies on item ordering
            item_hashes.hash(&mut crate_state);
        }

        {
            let mut visitor = StrictVersionHashVisitor::new(&mut crate_state,
                                                            self.tcx,
                                                            &mut self.def_path_hashes,
                                                            &mut self.codemap,
                                                            self.hash_spans,
                                                            false);
            visitor.hash_attributes(&krate.attrs);
        }

        let crate_hash = crate_state.finish();
        self.hashes.insert(DepNode::Krate, crate_hash);
        debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
    }
}

impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }

    fn visit_item(&mut self, item: &'tcx hir::Item) {
        self.calculate_node_id(item.id, |v| v.visit_item(item));
        visit::walk_item(self, item);
    }

    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
        self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item));
        visit::walk_impl_item(self, impl_item);
    }

    fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
        self.calculate_node_id(item.id, |v| v.visit_foreign_item(item));
        visit::walk_foreign_item(self, item);
    }
}
<commit_msg>ICH: Don't store hashes for individual foreign items.<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Calculation of the (misnamed) "strict version hash" for crates and
//! items. This hash is used to tell when the HIR changed in such a
//! way that results from previous compilations may no longer be
//! applicable and hence must be recomputed. It should probably be
//! renamed to the ICH (incremental compilation hash).
//!
//! The hashes for all items are computed once at the beginning of
//! compilation and stored into a map. In addition, a hash is computed
//! of the **entire crate**.
//!
//! Storing the hashes in a map avoids the need to compute them twice
//! (once when loading prior incremental results and once when
//! saving), but it is also important for correctness: at least as of
//! the time of this writing, the typeck passes rewrites entries in
//! the dep-map in-place to accommodate UFCS resolutions. Since name
//! resolution is part of the hash, the result is that hashes computed
//! at the end of compilation would be different from those computed
//! at the beginning.

use syntax::ast;
use std::cell::RefCell;
use std::hash::Hash;
use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::hir::intravisit as visit;
use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
use rustc::ty::TyCtxt;
use rustc_data_structures::stable_hasher::StableHasher;
use ich::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc::util::common::record_time;
use rustc::session::config::DebugInfoLevel::NoDebugInfo;

use self::def_path_hash::DefPathHashes;
use self::svh_visitor::StrictVersionHashVisitor;
use self::caching_codemap_view::CachingCodemapView;

mod def_path_hash;
mod svh_visitor;
mod caching_codemap_view;

pub type IchHasher = StableHasher<Fingerprint>;

pub struct IncrementalHashesMap {
    hashes: FxHashMap<DepNode<DefId>, Fingerprint>,

    // These are the metadata hashes for the current crate as they were stored
    // during the last compilation session. They are only loaded if
    // -Z query-dep-graph was specified and are needed for auto-tests using
    // the #[rustc_metadata_dirty] and #[rustc_metadata_clean] attributes to
    // check whether some metadata hash has changed in between two revisions.
    pub prev_metadata_hashes: RefCell<FxHashMap<DefId, Fingerprint>>,
}

impl IncrementalHashesMap {
    pub fn new() -> IncrementalHashesMap {
        IncrementalHashesMap {
            hashes: FxHashMap(),
            prev_metadata_hashes: RefCell::new(FxHashMap()),
        }
    }

    pub fn insert(&mut self, k: DepNode<DefId>, v: Fingerprint) -> Option<Fingerprint> {
        self.hashes.insert(k, v)
    }

    pub fn iter<'a>(&'a self)
                    -> ::std::collections::hash_map::Iter<'a, DepNode<DefId>, Fingerprint> {
        self.hashes.iter()
    }

    pub fn len(&self) -> usize {
        self.hashes.len()
    }
}

impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
    type Output = Fingerprint;

    fn index(&self, index: &'a DepNode<DefId>) -> &Fingerprint {
        match self.hashes.get(index) {
            Some(fingerprint) => fingerprint,
            None => {
                bug!("Could not find ICH for {:?}", index);
            }
        }
    }
}

pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
                                                    -> IncrementalHashesMap {
    let _ignore = tcx.dep_graph.in_ignore();
    let krate = tcx.map.krate();
    let hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo;
    let mut visitor = HashItemsVisitor {
        tcx: tcx,
        hashes: IncrementalHashesMap::new(),
        def_path_hashes: DefPathHashes::new(tcx),
        codemap: CachingCodemapView::new(tcx),
        hash_spans: hash_spans,
    };
    record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
        visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| {
            v.hash_crate_root_module(krate);
        });
        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());

        for macro_def in krate.exported_macros.iter() {
            visitor.calculate_node_id(macro_def.id,
                                      |v| v.visit_macro_def(macro_def));
        }
    });

    tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);

    record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
    visitor.hashes
}

struct HashItemsVisitor<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    def_path_hashes: DefPathHashes<'a, 'tcx>,
    codemap: CachingCodemapView<'tcx>,
    hashes: IncrementalHashesMap,
    hash_spans: bool,
}

impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
    fn calculate_node_id<W>(&mut self, id: ast::NodeId, walk_op: W)
        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
    {
        let def_id = self.tcx.map.local_def_id(id);
        self.calculate_def_id(def_id, walk_op)
    }

    fn calculate_def_id<W>(&mut self, def_id: DefId, mut walk_op: W)
        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
    {
        assert!(def_id.is_local());
        debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
        self.calculate_def_hash(DepNode::Hir(def_id), false, &mut walk_op);
        self.calculate_def_hash(DepNode::HirBody(def_id), true, &mut walk_op);
    }

    fn calculate_def_hash<W>(&mut self,
                             dep_node: DepNode<DefId>,
                             hash_bodies: bool,
                             walk_op: &mut W)
        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
    {
        let mut state = IchHasher::new();
        walk_op(&mut StrictVersionHashVisitor::new(&mut state,
                                                   self.tcx,
                                                   &mut self.def_path_hashes,
                                                   &mut self.codemap,
                                                   self.hash_spans,
                                                   hash_bodies));
        let bytes_hashed = state.bytes_hashed();
        let item_hash = state.finish();
        debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash);
        self.hashes.insert(dep_node, item_hash);

        let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
            bytes_hashed;
        self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
    }

    fn compute_crate_hash(&mut self) {
        let krate = self.tcx.map.krate();

        let mut crate_state = IchHasher::new();

        let crate_disambiguator = self.tcx.sess.local_crate_disambiguator();
        "crate_disambiguator".hash(&mut crate_state);
        crate_disambiguator.as_str().len().hash(&mut crate_state);
        crate_disambiguator.as_str().hash(&mut crate_state);

        // add each item (in some deterministic order) to the overall
        // crate hash.
        {
            let def_path_hashes = &mut self.def_path_hashes;
            let mut item_hashes: Vec<_> =
                self.hashes.iter()
                           .map(|(item_dep_node, &item_hash)| {
                               // convert from a DepNode<DefId> tp a
                               // DepNode<u64> where the u64 is the
                               // hash of the def-id's def-path:
                               let item_dep_node =
                                   item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did)))
                                                .unwrap();
                               (item_dep_node, item_hash)
                           })
                           .collect();
            item_hashes.sort(); // avoid artificial dependencies on item ordering
            item_hashes.hash(&mut crate_state);
        }

        {
            let mut visitor = StrictVersionHashVisitor::new(&mut crate_state,
                                                            self.tcx,
                                                            &mut self.def_path_hashes,
                                                            &mut self.codemap,
                                                            self.hash_spans,
                                                            false);
            visitor.hash_attributes(&krate.attrs);
        }

        let crate_hash = crate_state.finish();
        self.hashes.insert(DepNode::Krate, crate_hash);
        debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
    }
}

impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::None
    }

    fn visit_item(&mut self, item: &'tcx hir::Item) {
        self.calculate_node_id(item.id, |v| v.visit_item(item));
        visit::walk_item(self, item);
    }

    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
        self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item));
        visit::walk_impl_item(self, impl_item);
    }
}
<|endoftext|>


<commit_before><commit_msg>Add regression test for #20533. Fixes #20533.<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Regression test for issue #20533. At some point, only 1 out of the
// 3 errors below were being reported.

use std::marker::PhantomData;

fn foo<'a, T>(_x: &'a T) -> PhantomData<&'a ()> {
    PhantomData
}

struct Wrap<T>(T);

fn bar<'a, T>(_x: &'a T) -> Wrap<PhantomData<&'a ()>> {
    Wrap(PhantomData)
}

struct Baked<'a>(PhantomData<&'a ()>);

fn baz<'a, T>(_x: &'a T) -> Baked<'a> {
    Baked(PhantomData)
}

struct AffineU32(u32);

fn main() {
    {
        let a = AffineU32(1_u32);
        let x = foo(&a);
        drop(a); //~ ERROR cannot move out of `a`
        drop(x);
    }
    {
        let a = AffineU32(1_u32);
        let x = bar(&a);
        drop(a); //~ ERROR cannot move out of `a`
        drop(x);
    }
    {
        let a = AffineU32(1_u32);
        let x = baz(&a);
        drop(a); //~ ERROR cannot move out of `a`
        drop(x);
    }
}

<|endoftext|>


<commit_before><commit_msg>new merging spine<commit_after>//! An append-only collection of update batches.
//!
//! The `Spine` is a general-purpose trace implementation based on collection and merging
//! immutable batches of updates. It is generic with respect to the batch type, and can be
//! instantiated for any implementor of `trace::Batch`.

use std::fmt::Debug;

use ::difference::Monoid;
use lattice::Lattice;
use trace::{Batch, BatchReader, Trace, TraceReader};
// use trace::cursor::cursor_list::CursorList;
use trace::cursor::{Cursor, CursorList};
use trace::Merger;

use ::timely::dataflow::operators::generic::OperatorInfo;

/// An append-only collection of update tuples.
///
/// A spine maintains a small number of immutable collections of update tuples, merging the collections when
/// two have similar sizes. In this way, it allows the addition of more tuples, which may then be merged with
/// other immutable collections.
pub struct Spine<K, V, T: Lattice+Ord, R: Monoid, B: Batch<K, V, T, R>> {
    operator: OperatorInfo,
    logger: Option<::logging::Logger>,
    phantom: ::std::marker::PhantomData<(K, V, R)>,
    advance_frontier: Vec<T>,                   // Times after which the trace must accumulate correctly.
    through_frontier: Vec<T>,                   // Times after which the trace must be able to subset its inputs.
    merging: Vec<Option<MergeState<K,V,T,R,B>>>,// Several possibly shared collections of updates.
    pending: Vec<B>,                       // Batches at times in advance of `frontier`.
    upper: Vec<T>,
    effort: usize,
    activator: Option<timely::scheduling::activate::Activator>,
}

impl<K, V, T, R, B> TraceReader for Spine<K, V, T, R, B>
where
    K: Ord+Clone,           // Clone is required by `batch::advance_*` (in-place could remove).
    V: Ord+Clone,           // Clone is required by `batch::advance_*` (in-place could remove).
    T: Lattice+Ord+Clone+Debug+Default,
    R: Monoid,
    B: Batch<K, V, T, R>+Clone+'static,
{
    type Key = K;
    type Val = V;
    type Time = T;
    type R = R;

    type Batch = B;
    type Cursor = CursorList<K, V, T, R, <B as BatchReader<K, V, T, R>>::Cursor>;

    fn cursor_through(&mut self, upper: &[T]) -> Option<(Self::Cursor, <Self::Cursor as Cursor<K, V, T, R>>::Storage)> {

        // The supplied `upper` should have the property that for each of our
        // batch `lower` and `upper` frontiers, the supplied upper is comparable
        // to the frontier; it should not be incomparable, because the frontiers
        // that we created form a total order. If it is, there is a bug.
        //
        // We should acquire a cursor including all batches whose upper is less
        // or equal to the supplied upper, excluding all batches whose lower is
        // greater or equal to the supplied upper, and if a batch straddles the
        // supplied upper it had better be empty.

        // We shouldn't grab a cursor into a closed trace, right?
        assert!(self.advance_frontier.len() > 0);

        // Check that `upper` is greater or equal to `self.through_frontier`.
        // Otherwise, the cut could be in `self.merging` and it is user error anyhow.
        assert!(upper.iter().all(|t1| self.through_frontier.iter().any(|t2| t2.less_equal(t1))));

        let mut cursors = Vec::new();
        let mut storage = Vec::new();

        for merge_state in self.merging.iter().rev() {
            match *merge_state {
                Some(MergeState::Merging(ref batch1, ref batch2, _, _)) => {
                    if !batch1.is_empty() {
                        cursors.push(batch1.cursor());
                        storage.push(batch1.clone());
                    }
                    if !batch2.is_empty() {
                        cursors.push(batch2.cursor());
                        storage.push(batch2.clone());
                    }
                },
                Some(MergeState::Complete(ref batch)) => {
                    if !batch.is_empty() {
                        cursors.push(batch.cursor());
                        storage.push(batch.clone());
                    }
                },
                None => { }
            }
        }

        for batch in self.pending.iter() {

            if !batch.is_empty() {

                // For a non-empty `batch`, it is a catastrophic error if `upper`
                // requires some-but-not-all of the updates in the batch. We can
                // determine this from `upper` and the lower and upper bounds of
                // the batch itself.
                //
                // TODO: It is not clear if this is the 100% correct logic, due
                // to the possible non-total-orderedness of the frontiers.

                let include_lower = upper.iter().all(|t1| batch.lower().iter().any(|t2| t2.less_equal(t1)));
                let include_upper = upper.iter().all(|t1| batch.upper().iter().any(|t2| t2.less_equal(t1)));

                if include_lower != include_upper && upper != batch.lower() {
                    panic!("`cursor_through`: `upper` straddles batch");
                }

                // include pending batches
                if include_upper {
                    cursors.push(batch.cursor());
                    storage.push(batch.clone());
                }
            }
        }

        Some((CursorList::new(cursors, &storage), storage))
    }
    fn advance_by(&mut self, frontier: &[T]) {
        self.advance_frontier = frontier.to_vec();
        if self.advance_frontier.len() == 0 {
            self.pending.clear();
            self.merging.clear();
        }
    }
    fn advance_frontier(&mut self) -> &[T] { &self.advance_frontier[..] }
    fn distinguish_since(&mut self, frontier: &[T]) {
        self.through_frontier = frontier.to_vec();
        self.consider_merges();
    }
    fn distinguish_frontier(&mut self) -> &[T] { &self.through_frontier[..] }

    fn map_batches<F: FnMut(&Self::Batch)>(&mut self, mut f: F) {
        for batch in self.merging.iter().rev() {
            match *batch {
                Some(MergeState::Merging(ref batch1, ref batch2, _, _)) => { f(batch1); f(batch2); },
                Some(MergeState::Complete(ref batch)) => { f(batch); },
                None => { },
            }
        }
        for batch in self.pending.iter() {
            f(batch);
        }
    }
}

// A trace implementation for any key type that can be borrowed from or converted into `Key`.
// TODO: Almost all this implementation seems to be generic with respect to the trace and batch types.
impl<K, V, T, R, B> Trace for Spine<K, V, T, R, B>
where
    K: Ord+Clone,
    V: Ord+Clone,
    T: Lattice+Ord+Clone+Debug+Default,
    R: Monoid,
    B: Batch<K, V, T, R>+Clone+'static,
{

    fn new(
        info: ::timely::dataflow::operators::generic::OperatorInfo,
        logging: Option<::logging::Logger>,
        activator: Option<timely::scheduling::activate::Activator>,
    ) -> Self {
        Self::with_effort(4, info, logging, activator)
    }

    fn exert(&mut self, batch_size: usize, batch_index: usize) {
        self.work_for(batch_size, batch_index);
    }

    // Ideally, this method acts as insertion of `batch`, even if we are not yet able to begin
    // merging the batch. This means it is a good time to perform amortized work proportional
    // to the size of batch.
    fn insert(&mut self, batch: Self::Batch) {

        self.logger.as_ref().map(|l| l.log(::logging::BatchEvent {
            operator: self.operator.global_id,
            length: batch.len()
        }));

        assert!(batch.lower() != batch.upper());
        assert_eq!(batch.lower(), &self.upper[..]);

        self.upper = batch.upper().to_vec();

        // TODO: Consolidate or discard empty batches.
        self.pending.push(batch);
        self.consider_merges();
    }

    fn close(&mut self) {
        if !self.upper.is_empty() {
            use trace::Builder;
            let builder = B::Builder::new();
            let batch = builder.done(&self.upper[..], &[], &self.upper[..]);
            self.insert(batch);
        }
    }
}

impl<K, V, T, R, B> Spine<K, V, T, R, B>
where
    K: Ord+Clone,
    V: Ord+Clone,
    T: Lattice+Ord+Clone+Debug+Default,
    R: Monoid,
    B: Batch<K, V, T, R>,
{
    /// Allocates a fueled `Spine` with a specified effort multiplier.
    ///
    /// This trace will merge batches progressively, with each inserted batch applying a multiple
    /// of the batch's length in effort to each merge. The `effort` parameter is that multiplier.
    /// This value should be at least one for the merging to happen; a value of zero is not helpful.
    pub fn with_effort(
        mut effort: usize,
        operator: OperatorInfo,
        logger: Option<::logging::Logger>,
        activator: Option<timely::scheduling::activate::Activator>,
    ) -> Self {

        // Zero effort is .. not smart.
        if effort == 0 { effort = 1; }

        Spine {
            operator,
            logger,
            phantom: ::std::marker::PhantomData,
            advance_frontier: vec![<T as Lattice>::minimum()],
            through_frontier: vec![<T as Lattice>::minimum()],
            merging: Vec::new(),
            pending: Vec::new(),
            upper: vec![Default::default()],
            effort,
            activator,
        }
    }

    // Migrate data from `self.pending` into `self.merging`.
    #[inline(never)]
    fn consider_merges(&mut self) {

        while self.pending.len() > 0 &&
              self.through_frontier.iter().all(|t1| self.pending[0].upper().iter().any(|t2| t2.less_equal(t1)))
        {
            // this could be a VecDeque, if we ever notice this.
            let batch = self.pending.remove(0);

            self.introduce_batch(batch, batch.len().next_power_of_two());

            // Having performed all of our work, if more than one batch remains reschedule ourself.
            if self.merging.len() > 2 && self.merging[..self.merging.len()-1].iter().any(|b| b.present()) {
                self.activator.activate();
            }
        }
    }

    /// Introduces a batch at an indicated level.
    ///
    /// The level indication is often related to the size of the batch, but
    /// it can also be used to artificially fuel the computation by supplying
    /// empty batches at non-trivial indices, to move merges along.
    pub fn introduce_batch(&mut self, batch: B, batch_index: usize) {

        // This spine is represented as a list of layers, where each element in the list is either
        //
        //   1. MergeState::Empty   empty
        //   2. MergeState::Single  a single batch
        //   3. MergeState::Double  : a pair of batches
        //
        // Each of the batches at layer i contains at most 2^i elements. The sequence of batches
        // should have the upper bound of one match the lower bound of the next. Batches may be
        // logically empty, with matching upper and lower bounds, as a bookkeeping mechanism.
        //
        // We attempt to maintain the invariant that no two adjacent levels have pairs of batches.
        // This invariant exists to make sure we have the breathing room to initiate but not
        // immediately complete merges. As soon as a layer contains two batches we initiate a merge
        // into a batch of the next sized layer, and we start to apply fuel to this merge. When it
        // completes, we install the newly merged batch in the next layer and uninstall the two
        // batches from their layer.
        //
        // We a merge completes, it vacates an entire level. Assuming we have maintained our invariant,
        // the number of updates below that level (say "k") is at most
        //
        //         2^k-1 + 2*2^k-2 + 2^k-3 + 2*2^k-4 + ...
        //      <=
        //         2^k+1 - 2^k-1
        //
        // Fortunately, the now empty layer k needs 2^k+1 updates before it will initiate a new merge,
        // and the collection must accept 2^k-1 updates before such a merge could possibly be initiated.
        // This means that if each introduced merge applies a proportionate amount of fuel to the merge,
        // we should be able to complete any merge at the next level before a new one is proposed.
        //
        // I believe most of this reasoning holds under the properties of the invariant that no adjacent
        // layers have two batches. This gives us the ability to do further housekeeping, especially as
        // we work with the largest layers, which we might expect not to grow in size. If at any point we
        // can tidy the largest layer downward without violating the invariant (e.g. draw it down to an
        // empty layer, or to a singleton layer and commence a merge) we should consider that in the
        // interests of maintaining a compact representation that does not grow without bounds.

        // Step 2. Apply fuel to each in-progress merge.
        //
        //         Ideally we apply fuel to the merges of the smallest
        //         layers first, as progress on these layers is important,
        //         and the sooner it happens the sooner we have fewer layers
        //         for cursors to navigate, which improves read performance.
        //
        //          It is important that by the end of this, we have ensured
        //          that position `batch_index+1` has at most a single batch,
        //          as our roll-up strategy will insert into that position.
        self.apply_fuel(self.effort << batch_index);

        // Step 1. Before installing the batch we must ensure the invariant,
        //         that no adjacent layers contain two batches. We can make
        //         this happen by forcibly completing all lower merges and
        //         integrating them with the batch itself, which can go at
        //         level index+1 as a single batch.
        //
        //         Note that this corresponds to the introduction of some
        //         volume of fake updates, and we will need to fuel merges
        //         by a proportional amount to ensure that they are not
        //         surprised later on.
        self.roll_up(batch_index);

        // Step 4. This insertion should be into an empty layer. It is a
        //         logical error otherwise, as we may be violating our
        //         invariant, from which all derives.
        self.insert_at(batch, batch_index);

        // Step 3. Tidy the largest layers.
        //
        //         It is important that we not tidy only smaller layers,
        //         as their ascension is what ensures the merging and
        //         eventual compaction of the largest layers.
        self.tidy_layers();
    }

    /// Ensures that layers up through and including `index` are empty.
    ///
    /// This method is used to prepare for the insertion of a single batch
    /// at `index`, which should maintain the invariant.
    fn roll_up(&mut self, index: usize) {

        let merge =
        self.merging[.. index+1]
            .iter_mut()
            .fold(None, |merge, level|
                match (merge, level.complete()) {
                    (Some(batch_new), Some(batch_old)) => {
                        Some(MergeState::begin_merge(batch_old, batch_new, None).complete())
                    },
                    (None, batch) => batch,
                    (merge, None) => merge,
                }
            );

        if let Some(batch) = merge {
            self.insert_at(batch, index + 1);
        }
    }

    /// Applies an amount of fuel to merges in progress.
    pub fn apply_fuel(mut fuel: usize) {

        // Scale fuel up by number of in-progress merges, or by the length of the spine.
        // We just need to make sure that the issued fuel is applied to each in-progress
        // merge, by the time its layer is needed to accept a new merge.

        fuel *= self.merging.len();
        for index in 0 .. self.merging.len() {
            if let Some(batch) = self.merging.work(&mut fuel) {
                self.insert_at(batch, index+1);
            }
        }
    }

    /// Inserts a batch at a specific location.
    ///
    /// This is a non-public internal method that can panic if we try and insert into a
    /// layer which already contains two batches (and is in the process of merging).
    fn insert_at(&mut self, batch: B, index: usize) {
        while self.merging.len() <= index {
            self.merging.push(MergeState::Empty);
        }
        let frontier = if index == self.merging.len()-1 { Some(self.advance_frontier.clone()) } else { None };
        self.merging[index].insert(batch, frontier);
    }

    /// Attempts to draw down large layers to size appropriate layers.
    fn tidy_layers(&mut self) {

        // If the largest layer is complete (not merging), we can attempt
        // to draw it down to the next layer if either that layer is empty,
        // or if it is a singleton and the layer below it is not merging.
        // We expect this should happen at various points if we have enough
        // fuel rolling around.

        let done = false;
        while !done {

        }

    }

}

/// Describes the state of a layer.
///
/// A layer can be empty, contain a single batch, or contain a pair of batches that are in the process
/// of merging into a batch for the next layer.
enum MergeState<K, V, T, R, B: Batch<K, V, T, R>> {
    /// An empty layer, containing no updates.
    Empty,
    /// A layer containing a single batch.
    Single(B),
    /// A layer containing two batch, in the process of merging.
    Double(B, B, Option<Vec<T>>, <B as Batch<K,V,T,R>>::Merger),
}

impl<K, V, T: Eq, R, B: Batch<K, V, T, R>> MergeState<K, V, T, R, B> {

    /// Immediately complete any merge.
    ///
    /// This consumes the layer, though we should probably consider returning the resources of the
    /// underlying source batches if we can manage that.
    fn complete(&mut self) -> Option<B>  {
        match std::mem::replace(self, MergeState::Empty) {
            Empty => None,
            Single(batch) => Some(batch),
            Double(b1, b2, frontier, merge) => {
                let mut fuel = usize::max_value();
                in_progress.work(source1, source2, frontier, &mut fuel);
                assert!(fuel > 0);
                let finished = finished.done();
                // logger.as_ref().map(|l|
                //     l.log(::logging::MergeEvent {
                //         operator,
                //         scale,
                //         length1: b1.len(),
                //         length2: b2.len(),
                //         complete: Some(finished.len()),
                //     })
                // );
                Some(finished)
            },
        }
    }

    fn work(&mut self, fuel: &mut usize) -> Option<B> {
        match std::mem::replace(self, MergeState::Empty) {
            MergeState::Double(b1, b2, frontier, merge) => {
                merge.work(b1, b2, frontier, fuel);
                if fuel > 0 {
                    let finished = finished.done();
                    // logger.as_ref().map(|l|
                    //     l.log(::logging::MergeEvent {
                    //         operator,
                    //         scale,
                    //         length1: b1.len(),
                    //         length2: b2.len(),
                    //         complete: Some(finished.len()),
                    //     })
                    // );
                    Some(finished)
                }
            }
            _ => None,
        }
    }

    /// Extract the merge state, often temporarily.
    fn take(&mut self) -> MergeState {
        std::mem::replace(self, MergeState::Empty)
    }

    /// Inserts a batch and begins a merge if needed.
    fn insert(&mut self, batch: B, frontier: Option<Vec<T>>) {
        match self.take() {
            Empty => { *self = MergeState::Single(batch); },
            Single(batch_old) => {
                *self = MergeState::begin_merge(batch_old, batch, frontier);
            }
            Double(_,_,_,_) => {
                panic!("Attempted to insert batch into incomplete merge!");
            }
        };
    }

    fn is_complete(&self) -> bool {
        match *self {
            MergeState::Complete(_) => true,
            _ => false,
        }
    }
    fn begin_merge(batch1: B, batch2: B, frontier: Option<Vec<T>>) -> Self {
        // logger.as_ref().map(|l| l.log(
        //     ::logging::MergeEvent {
        //         operator,
        //         scale,
        //         length1: batch1.len(),
        //         length2: batch2.len(),
        //         complete: None,
        //     }
        // ));
        assert!(batch1.upper() == batch2.lower());
        let begin_merge = <B as Batch<K, V, T, R>>::begin_merge(&batch1, &batch2);
        MergeState::Merging(batch1, batch2, frontier, begin_merge)
    }
    fn work(mut self, fuel: &mut usize) -> Self {
        if let MergeState::Merging(ref source1, ref source2, ref frontier, ref mut in_progress) = self {
            in_progress.work(source1, source2, frontier, fuel);
        }
        if *fuel > 0 {
            match self {
                // ALLOC: Here is where we may de-allocate batches.
                MergeState::Merging(b1, b2, _, finished) => {
                    let finished = finished.done();
                    // logger.as_ref().map(|l|
                    //     l.log(::logging::MergeEvent {
                    //         operator,
                    //         scale,
                    //         length1: b1.len(),
                    //         length2: b2.len(),
                    //         complete: Some(finished.len()),
                    //     })
                    // );
                    MergeState::Complete(finished)
                },
                MergeState::Complete(x) => MergeState::Complete(x),
            }
        }
        else { self }
    }
    fn len(&self) -> usize {
        match *self {
            MergeState::Merging(ref batch1, ref batch2, _, _) => batch1.len() + batch2.len(),
            MergeState::Complete(ref batch) => batch.len(),
        }
    }
}<|endoftext|>


<commit_before><commit_msg>Use DYNAMIC_DRAW hint, which makes a significant difference in frame rate, at least for nVidia/Windows/debug<commit_after><|endoftext|>


<commit_before><commit_msg>Remove spurious command buffer resets introduced after refactoring the one-time-use command-buffers<commit_after><|endoftext|>


<commit_before><commit_msg>Refactor a load of initialisation into RAII-controlled types<commit_after><|endoftext|>


<commit_before><commit_msg>Disable or remove the temporary pipeline creation debug statements<commit_after><|endoftext|>


<commit_before><commit_msg>last line<commit_after><|endoftext|>


<commit_before><commit_msg>Add uart example<commit_after>#![feature(used)]
#![no_std]
extern crate stm32f0_hal as hal;
extern crate cortex_m;

use hal::rcc;
use hal::uart;

fn main() {
    rcc::init(); // Full Speed 48Mhz
    uart::init(6000000,uart::NBITS::_8bits,uart::STOPBITS::_1b,uart::PARITY::None);
    loop {
        if uart::transmit_complete() {
            uart::send(0x55);
        }
    }
}<|endoftext|>


<commit_before><commit_msg>git add errors.rs<commit_after>error_chain!{
    foreign_links {
        Io(::std::io::Error);
        Alsa(::alsa::Error);
    }
}
<|endoftext|>


<commit_before><commit_msg>Restoring back to the state that can create file<commit_after><|endoftext|>


<commit_before>use std::old_io::net::ip::{SocketAddr, IpAddr, Port};
use std::sync::{Arc, RwLock};
use std::collections::HashMap;
use hyper::server::{Request, Response};
use http::server::Config;
use http::server::Server as HttpServer;

use middleware::MiddlewareStack;
use request;
use response;
use mustache;

pub struct Server {
    middleware_stack: MiddlewareStack,
    ip: IpAddr,
    port: Port,
    templates: response::TemplateCache
}

impl HttpServer for Arc<Server> {
    fn get_config(&self) -> Config {
        Config { bind_address: SocketAddr { ip: self.ip, port: self.port } }
    }

    fn handle_request(&self, req: Request, res: &mut ResponseWriter) {

        let nickel_req = &mut request::Request::from_internal(&req);
        let nickel_res = &mut response::Response::from_internal(res, &self.templates);

        self.middleware_stack.invoke(nickel_req, nickel_res);
    }
}

impl Server {
    pub fn new(middleware_stack: MiddlewareStack, ip: IpAddr, port: Port) -> Server {
        Server {
            middleware_stack: middleware_stack,
            ip: ip,
            port: port,
            templates: RwLock::new(HashMap::<&'static str, mustache::Template>::new())
        }
    }

    // why do we need this? Is the http::Server.serve_forever method protected in C# terms?
    pub fn serve(self) {
        let arc = Arc::new(self);
        arc.serve_forever();
    }
}
<commit_msg>refactor(hyper): use Server from hyper<commit_after>use std::old_io::net::ip::{SocketAddr, IpAddr, Port};
use std::sync::{Arc, RwLock};
use std::collections::HashMap;
use hyper::server::{Request, Response, Handler};
use hyper::server::Server as HyperServer;

use middleware::MiddlewareStack;
use request;
use response;
use mustache;

pub struct Server {
    middleware_stack: MiddlewareStack,
    ip: IpAddr,
    port: Port,
    templates: response::TemplateCache
}

impl Handler for Arc<Server> {
    fn handle<'a>(&'a self, req: Request<'a>, res: Response<'a>) {
        let nickel_req = request::Request::from_internal(&req);
        let nickel_res = response::Response::from_internal(res, &self.templates);

        self.middleware_stack.invoke(nickel_req, nickel_res);
    }
}

impl Server {
    pub fn new(middleware_stack: MiddlewareStack, ip: IpAddr, port: Port) -> Server {
        Server {
            middleware_stack: middleware_stack,
            ip: ip,
            port: port,
            templates: RwLock::new(HashMap::<&'static str, mustache::Template>::new())
        }
    }

    // why do we need this? Is the http::Server.serve_forever method protected in C# terms?
    pub fn serve(self) {
        let socket = HyperServer::http(self.ip, self.port);
        let arc = Arc::new(self);
        socket.listen(arc);
    }
}

<|endoftext|>


<commit_before>import std::ivec;
import std::uint;
import std::str;
import std::termivec;
import std::ioivec;
import std::option;
import std::option::some;
import std::option::none;

type filename = str;

/* A codemap is a thing that maps uints to file/line/column positions
 * in a crate. This to make it possible to represent the positions
 * with single-word things, rather than passing records all over the
 * compiler.
 */
type filemap = @rec(filename name, uint start_pos, mutable uint[] lines);

type codemap = @rec(mutable filemap[] files);

type loc = rec(filename filename, uint line, uint col);

fn new_codemap() -> codemap {
    let filemap[] files = ~[];
    ret @rec(mutable files=files);
}

fn new_filemap(filename filename, uint start_pos) -> filemap {
    ret @rec(name=filename, start_pos=start_pos, mutable lines=~[0u]);
}

fn next_line(filemap file, uint pos) { file.lines += ~[pos]; }

fn lookup_pos(codemap map, uint pos) -> loc {
    auto a = 0u;
    auto b = ivec::len[filemap](map.files);
    while (b - a > 1u) {
        auto m = (a + b) / 2u;
        if (map.files.(m).start_pos > pos) { b = m; } else { a = m; }
    }
    auto f = map.files.(a);
    a = 0u;
    b = ivec::len[uint](f.lines);
    while (b - a > 1u) {
        auto m = (a + b) / 2u;
        if (f.lines.(m) > pos) { b = m; } else { a = m; }
    }
    ret rec(filename=f.name, line=a + 1u, col=pos - f.lines.(a));
}

type span = rec(uint lo, uint hi);

fn span_to_str(&span sp, &codemap cm) -> str {
    auto lo = lookup_pos(cm, sp.lo);
    auto hi = lookup_pos(cm, sp.hi);
    ret #fmt("%s:%u:%u:%u:%u", lo.filename, lo.line, lo.col, hi.line, hi.col);
}

fn emit_diagnostic(&option::t[span] sp, &str msg, &str kind, u8 color,
                   &codemap cm) {
    auto ss = "<input>:0:0:0:0";
    let option::t[@file_lines] maybe_lines = none;
    alt (sp) {
        case (some(?ssp)) {
            ss = span_to_str(ssp, cm);

            maybe_lines = some(span_to_lines(ssp, cm));

        }
        case (none) { }
    }
    ioivec::stdout().write_str(ss + ": ");
    if (termivec::color_supported()) {
        termivec::fg(ioivec::stdout().get_buf_writer(), color);
    }
    ioivec::stdout().write_str(#fmt("%s:", kind));
    if (termivec::color_supported()) {
        termivec::reset(ioivec::stdout().get_buf_writer());
    }
    ioivec::stdout().write_str(#fmt(" %s\n", msg));
    alt (maybe_lines) {
        case (some(?lines)) {
            // FIXME: reading in the entire file is the worst possible way to
            //        get access to the necessary lines.
            auto rdr = ioivec::file_reader(lines.name);
            auto file = str::unsafe_from_bytes_ivec(rdr.read_whole_stream());
            auto fm = get_filemap(cm, lines.name);

            // arbitrarily only print up to six lines of the error
            auto max_lines = 6u;
            auto elided = false;
            auto display_lines = lines.lines;
            if (ivec::len(display_lines) > max_lines) {
                display_lines = ivec::slice(display_lines, 0u, max_lines);
                elided = true;
            }
            // Print the offending lines
            for (uint line in display_lines) {
                ioivec::stdout().write_str(#fmt("%s:%u ", fm.name,
                                                line + 1u));
                auto s = get_line(fm, line as int, file);
                if (!str::ends_with(s, "\n")) {
                    s += "\n";
                }
                ioivec::stdout().write_str(s);
            }
            if (elided) {
                auto last_line = display_lines.(ivec::len(display_lines) -
                                                1u);
                auto s = #fmt("%s:%u ", fm.name, last_line + 1u);
                auto indent = str::char_len(s);
                auto out = "";
                while (indent > 0u) { out += " "; indent -= 1u; }
                out += "...\n";
                ioivec::stdout().write_str(out);
            }

            // If there's one line at fault we can easily point to the problem
            if (ivec::len(lines.lines) == 1u) {
                auto lo = codemap::lookup_pos(cm, option::get(sp).lo);
                auto lo = lookup_pos(cm, option::get(sp).lo);
                auto digits = 0u;
                auto num = lines.lines.(0) / 10u;

                // how many digits must be indent past?
                while (num > 0u) { num /= 10u; digits += 1u; }

                // indent past |name:## | and the 0-offset column location
                auto left = str::char_len(fm.name) + digits + lo.col + 3u;
                auto s = "";
                while (left > 0u) { str::push_char(s, ' '); left -= 1u; }

                s += "^";
                auto hi = lookup_pos(cm, option::get(sp).hi);
                if (hi.col != lo.col) {
                    // the ^ already takes up one space
                    auto width = hi.col - lo.col - 1u;
                    while (width > 0u) {
                        str::push_char(s, '~');
                        width -= 1u;
                    }
                }
                ioivec::stdout().write_str(s + "\n");
            }
        }
        case (_) {}
    }
}

fn emit_warning(&option::t[span] sp, &str msg, &codemap cm) {
    emit_diagnostic(sp, msg, "warning", 11u8, cm);
}
fn emit_error(&option::t[span] sp, &str msg, &codemap cm) {
    emit_diagnostic(sp, msg, "error", 9u8, cm);
}
fn emit_note(&option::t[span] sp, &str msg, &codemap cm) {
    emit_diagnostic(sp, msg, "note", 10u8, cm);
}

type file_lines = rec(str name, uint[] lines);

fn span_to_lines(span sp, codemap::codemap cm) -> @file_lines {
    auto lo = codemap::lookup_pos(cm, sp.lo);
    auto hi = codemap::lookup_pos(cm, sp.hi);
    auto lines = ~[];
    for each (uint i in uint::range(lo.line - 1u, hi.line as uint)) {
        lines += ~[i];
    }
    ret @rec(name=lo.filename, lines=lines);
}

fn get_line(filemap fm, int line, &str file) -> str {
    let uint begin = fm.lines.(line) - fm.lines.(0);
    let uint end;
    if ((line as uint) + 1u >= ivec::len(fm.lines)) {
        end = str::byte_len(file);
    } else {
        end = fm.lines.(line + 1) - fm.lines.(0);
    }
    ret str::slice(file, begin, end);
}

fn get_filemap(codemap cm, str filename) -> filemap {
    for (filemap fm in cm.files) {
        if (fm.name == filename) {
            ret fm;
        }
    }
    //XXjdm the following triggers a mismatched type bug
    //      (or expected function, found _|_)
    fail;// ("asking for " + filename + " which we don't know about");
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Use the actual start position of the file in the codemap rather than the position of the first newline.<commit_after>import std::ivec;
import std::uint;
import std::str;
import std::termivec;
import std::ioivec;
import std::option;
import std::option::some;
import std::option::none;

type filename = str;

/* A codemap is a thing that maps uints to file/line/column positions
 * in a crate. This to make it possible to represent the positions
 * with single-word things, rather than passing records all over the
 * compiler.
 */
type filemap = @rec(filename name, uint start_pos, mutable uint[] lines);

type codemap = @rec(mutable filemap[] files);

type loc = rec(filename filename, uint line, uint col);

fn new_codemap() -> codemap {
    let filemap[] files = ~[];
    ret @rec(mutable files=files);
}

fn new_filemap(filename filename, uint start_pos) -> filemap {
    ret @rec(name=filename, start_pos=start_pos, mutable lines=~[0u]);
}

fn next_line(filemap file, uint pos) { file.lines += ~[pos]; }

fn lookup_pos(codemap map, uint pos) -> loc {
    auto a = 0u;
    auto b = ivec::len[filemap](map.files);
    while (b - a > 1u) {
        auto m = (a + b) / 2u;
        if (map.files.(m).start_pos > pos) { b = m; } else { a = m; }
    }
    auto f = map.files.(a);
    a = 0u;
    b = ivec::len[uint](f.lines);
    while (b - a > 1u) {
        auto m = (a + b) / 2u;
        if (f.lines.(m) > pos) { b = m; } else { a = m; }
    }
    ret rec(filename=f.name, line=a + 1u, col=pos - f.lines.(a));
}

type span = rec(uint lo, uint hi);

fn span_to_str(&span sp, &codemap cm) -> str {
    auto lo = lookup_pos(cm, sp.lo);
    auto hi = lookup_pos(cm, sp.hi);
    ret #fmt("%s:%u:%u:%u:%u", lo.filename, lo.line, lo.col, hi.line, hi.col);
}

fn emit_diagnostic(&option::t[span] sp, &str msg, &str kind, u8 color,
                   &codemap cm) {
    auto ss = "<input>:0:0:0:0";
    let option::t[@file_lines] maybe_lines = none;
    alt (sp) {
        case (some(?ssp)) {
            ss = span_to_str(ssp, cm);
            maybe_lines = some(span_to_lines(ssp, cm));
        }
        case (none) { }
    }
    ioivec::stdout().write_str(ss + ": ");
    if (termivec::color_supported()) {
        termivec::fg(ioivec::stdout().get_buf_writer(), color);
    }
    ioivec::stdout().write_str(#fmt("%s:", kind));
    if (termivec::color_supported()) {
        termivec::reset(ioivec::stdout().get_buf_writer());
    }
    ioivec::stdout().write_str(#fmt(" %s\n", msg));
    alt (maybe_lines) {
        case (some(?lines)) {
            // FIXME: reading in the entire file is the worst possible way to
            //        get access to the necessary lines.
            auto rdr = ioivec::file_reader(lines.name);
            auto file = str::unsafe_from_bytes_ivec(rdr.read_whole_stream());
            auto fm = get_filemap(cm, lines.name);

            // arbitrarily only print up to six lines of the error
            auto max_lines = 6u;
            auto elided = false;
            auto display_lines = lines.lines;
            if (ivec::len(display_lines) > max_lines) {
                display_lines = ivec::slice(display_lines, 0u, max_lines);
                elided = true;
            }
            // Print the offending lines
            for (uint line in display_lines) {
                ioivec::stdout().write_str(#fmt("%s:%u ", fm.name,
                                                line + 1u));
                auto s = get_line(fm, line as int, file);
                if (!str::ends_with(s, "\n")) {
                    s += "\n";
                }
                ioivec::stdout().write_str(s);
            }
            if (elided) {
                auto last_line = display_lines.(ivec::len(display_lines) -
                                                1u);
                auto s = #fmt("%s:%u ", fm.name, last_line + 1u);
                auto indent = str::char_len(s);
                auto out = "";
                while (indent > 0u) { out += " "; indent -= 1u; }
                out += "...\n";
                ioivec::stdout().write_str(out);
            }

            // If there's one line at fault we can easily point to the problem
            if (ivec::len(lines.lines) == 1u) {
                auto lo = codemap::lookup_pos(cm, option::get(sp).lo);
                auto lo = lookup_pos(cm, option::get(sp).lo);
                auto digits = 0u;
                auto num = lines.lines.(0) / 10u;

                // how many digits must be indent past?
                while (num > 0u) { num /= 10u; digits += 1u; }

                // indent past |name:## | and the 0-offset column location
                auto left = str::char_len(fm.name) + digits + lo.col + 3u;
                auto s = "";
                while (left > 0u) { str::push_char(s, ' '); left -= 1u; }

                s += "^";
                auto hi = lookup_pos(cm, option::get(sp).hi);
                if (hi.col != lo.col) {
                    // the ^ already takes up one space
                    auto width = hi.col - lo.col - 1u;
                    while (width > 0u) {
                        str::push_char(s, '~');
                        width -= 1u;
                    }
                }
                ioivec::stdout().write_str(s + "\n");
            }
        }
        case (_) {}
    }
}

fn emit_warning(&option::t[span] sp, &str msg, &codemap cm) {
    emit_diagnostic(sp, msg, "warning", 11u8, cm);
}
fn emit_error(&option::t[span] sp, &str msg, &codemap cm) {
    emit_diagnostic(sp, msg, "error", 9u8, cm);
}
fn emit_note(&option::t[span] sp, &str msg, &codemap cm) {
    emit_diagnostic(sp, msg, "note", 10u8, cm);
}

type file_lines = rec(str name, uint[] lines);

fn span_to_lines(span sp, codemap::codemap cm) -> @file_lines {
    auto lo = codemap::lookup_pos(cm, sp.lo);
    auto hi = codemap::lookup_pos(cm, sp.hi);
    auto lines = ~[];
    for each (uint i in uint::range(lo.line - 1u, hi.line as uint)) {
        lines += ~[i];
    }
    ret @rec(name=lo.filename, lines=lines);
}

fn get_line(filemap fm, int line, &str file) -> str {
    let uint begin = fm.lines.(line) - fm.start_pos;
    let uint end;
    if ((line as uint) + 1u >= ivec::len(fm.lines)) {
        end = str::byte_len(file);
    } else {
        end = fm.lines.(line + 1) - fm.start_pos;
    }
    ret str::slice(file, begin, end);
}

fn get_filemap(codemap cm, str filename) -> filemap {
    for (filemap fm in cm.files) {
        if (fm.name == filename) {
            ret fm;
        }
    }
    //XXjdm the following triggers a mismatched type bug
    //      (or expected function, found _|_)
    fail;// ("asking for " + filename + " which we don't know about");
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
    // test compound assignment operators with ref as right-hand side,
    // for each operator, with various types as operands.

    // test AddAssign
    {
        let mut x = 3i8;
        x += &2i8;
        assert_eq!(x, 5i8);
    }

    // test SubAssign
    {
        let mut x = 7i16;
        x -= &4;
        assert_eq!(x, 3i16);
    }

    // test MulAssign
    {
        let mut x = 3f32;
        x *= &3f32;
        assert_eq!(x, 9f32);
    }

    // test DivAssign
    {
        let mut x = 6f64;
        x /= &2f64;
        assert_eq!(x, 3f64);
    }

    // test RemAssign
    {
        let mut x = 7i64;
        x %= &4i64;
        assert_eq!(x, 3i64);
    }

    // test BitOrAssign
    {
        let mut x = 0b1010u8;
        x |= &0b1100u8;
        assert_eq!(x, 0b1110u8);
    }

    // test BitAndAssign
    {
        let mut x = 0b1010u16;
        x &= &0b1100u16;
        assert_eq!(x, 0b1000u16);
    }

    // test BitXorAssign
    {
        let mut x = 0b1010u32;
        x ^= &0b1100u32;
        assert_eq!(x, 0b0110u32);
    }

    // test ShlAssign
    {
        let mut x = 0b1010u64;
        x <<= &2u32;
        assert_eq!(x, 0b101000u64);
    }

    // test ShrAssign
    {
        let mut x = 0b1010u64;
        x >>= &2i16;
        assert_eq!(x, 0b10u64);
    }
}<commit_msg>Missing trailing newline<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
    // test compound assignment operators with ref as right-hand side,
    // for each operator, with various types as operands.

    // test AddAssign
    {
        let mut x = 3i8;
        x += &2i8;
        assert_eq!(x, 5i8);
    }

    // test SubAssign
    {
        let mut x = 7i16;
        x -= &4;
        assert_eq!(x, 3i16);
    }

    // test MulAssign
    {
        let mut x = 3f32;
        x *= &3f32;
        assert_eq!(x, 9f32);
    }

    // test DivAssign
    {
        let mut x = 6f64;
        x /= &2f64;
        assert_eq!(x, 3f64);
    }

    // test RemAssign
    {
        let mut x = 7i64;
        x %= &4i64;
        assert_eq!(x, 3i64);
    }

    // test BitOrAssign
    {
        let mut x = 0b1010u8;
        x |= &0b1100u8;
        assert_eq!(x, 0b1110u8);
    }

    // test BitAndAssign
    {
        let mut x = 0b1010u16;
        x &= &0b1100u16;
        assert_eq!(x, 0b1000u16);
    }

    // test BitXorAssign
    {
        let mut x = 0b1010u32;
        x ^= &0b1100u32;
        assert_eq!(x, 0b0110u32);
    }

    // test ShlAssign
    {
        let mut x = 0b1010u64;
        x <<= &2u32;
        assert_eq!(x, 0b101000u64);
    }

    // test ShrAssign
    {
        let mut x = 0b1010u64;
        x >>= &2i16;
        assert_eq!(x, 0b10u64);
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// pretty-expanded FIXME #23616

#![feature(libc)]

extern crate libc;
use std::mem;

struct arena(());

struct Bcx<'a> {
    fcx: &'a Fcx<'a>
}

struct Fcx<'a> {
    arena: &'a arena,
    ccx: &'a Ccx
}

struct Ccx {
    x: isize
}

fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> {
    unsafe {
        mem::transmute(libc::malloc(mem::size_of::<Bcx<'a>>()
            as libc::size_t))
    }
}

fn h<'a>(bcx : &'a Bcx<'a>) -> &'a Bcx<'a> {
    return alloc(bcx.fcx.arena);
}

fn g(fcx : &Fcx) {
    let bcx = Bcx { fcx: fcx };
    let bcx2 = h(&bcx);
    unsafe {
        libc::free(mem::transmute(bcx2));
    }
}

fn f(ccx : &Ccx) {
    let a = arena(());
    let fcx = Fcx { arena: &a, ccx: ccx };
    return g(&fcx);
}

pub fn main() {
    let ccx = Ccx { x: 0 };
    f(&ccx);
}
<commit_msg>Update regions-mock-trans.rs<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// pretty-expanded FIXME #23616

#![feature(libc)]

#![allow(dead_code)]

extern crate libc;
use std::mem;

struct Arena(());

struct Bcx<'a> {
    fcx: &'a Fcx<'a>
}

struct Fcx<'a> {
    arena: &'a Arena,
    ccx: &'a Ccx
}

struct Ccx {
    x: isize
}

fn alloc<'a>(_bcx : &'a Arena) -> &'a Bcx<'a> {
    unsafe {
        mem::transmute(libc::malloc(mem::size_of::<Bcx<'a>>()
            as libc::size_t))
    }
}

fn h<'a>(bcx : &'a Bcx<'a>) -> &'a Bcx<'a> {
    return alloc(bcx.fcx.arena);
}

fn g(fcx : &Fcx) {
    let bcx = Bcx { fcx: fcx };
    let bcx2 = h(&bcx);
    unsafe {
        libc::free(mem::transmute(bcx2));
    }
}

fn f(ccx : &Ccx) {
    let a = Arena(());
    let fcx = Fcx { arena: &a, ccx: ccx };
    return g(&fcx);
}

pub fn main() {
    let ccx = Ccx { x: 0 };
    f(&ccx);
}
<|endoftext|>