about summary refs log tree commit diff
path: root/src/librustc
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustc')
-rw-r--r--src/librustc/driver.rs5
-rw-r--r--src/librustc/driver/mod.rs8
-rw-r--r--src/librustc/metadata.rs31
-rw-r--r--src/librustc/metadata/mod.rs33
-rw-r--r--src/librustc/middle/borrowck.rs618
-rw-r--r--src/librustc/middle/borrowck/mod.rs620
-rw-r--r--src/librustc/middle/typeck.rs376
-rw-r--r--src/librustc/middle/typeck/mod.rs377
-rw-r--r--src/librustc/rustc.rc10
9 files changed, 1042 insertions, 1036 deletions
diff --git a/src/librustc/driver.rs b/src/librustc/driver.rs
deleted file mode 100644
index cbe6345a9f1..00000000000
--- a/src/librustc/driver.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-use syntax::diagnostic;
-export diagnostic;
-
-export driver;
-export session;
diff --git a/src/librustc/driver/mod.rs b/src/librustc/driver/mod.rs
index 7d9a55571d4..a9d5afeb522 100644
--- a/src/librustc/driver/mod.rs
+++ b/src/librustc/driver/mod.rs
@@ -1,4 +1,12 @@
 #[legacy_exports];
+
+use syntax::diagnostic;
+
+export diagnostic;
+
+export driver;
+export session;
+
 #[legacy_exports]
 mod driver;
 #[legacy_exports]
diff --git a/src/librustc/metadata.rs b/src/librustc/metadata.rs
deleted file mode 100644
index 2d2d6a3f79e..00000000000
--- a/src/librustc/metadata.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Define the rustc API's that the metadata module has access to
-// Over time we will reduce these dependencies and, once metadata has
-// no dependencies on rustc it can move into its own crate.
-
-mod middle {
-    #[legacy_exports];
-    pub use middle_::ty;
-    pub use middle_::resolve;
-}
-
-mod front {
-    #[legacy_exports];
-}
-
-mod back {
-    #[legacy_exports];
-}
-
-mod driver {
-    #[legacy_exports];
-}
-
-mod util {
-    #[legacy_exports];
-    pub use util_::ppaux;
-}
-
-mod lib {
-    #[legacy_exports];
-    pub use lib_::llvm;
-}
diff --git a/src/librustc/metadata/mod.rs b/src/librustc/metadata/mod.rs
index a82ad39d412..dfe983cc32b 100644
--- a/src/librustc/metadata/mod.rs
+++ b/src/librustc/metadata/mod.rs
@@ -30,3 +30,36 @@ mod csearch;
 mod loader;
 #[legacy_exports]
 mod filesearch;
+
+
+// Define the rustc API's that the metadata module has access to
+// Over time we will reduce these dependencies and, once metadata has
+// no dependencies on rustc it can move into its own crate.
+
+mod middle {
+    #[legacy_exports];
+    pub use middle_::ty;
+    pub use middle_::resolve;
+}
+
+mod front {
+    #[legacy_exports];
+}
+
+mod back {
+    #[legacy_exports];
+}
+
+mod driver {
+    #[legacy_exports];
+}
+
+mod util {
+    #[legacy_exports];
+    pub use util_::ppaux;
+}
+
+mod lib {
+    #[legacy_exports];
+    pub use lib_::llvm;
+}
diff --git a/src/librustc/middle/borrowck.rs b/src/librustc/middle/borrowck.rs
deleted file mode 100644
index df573b121f8..00000000000
--- a/src/librustc/middle/borrowck.rs
+++ /dev/null
@@ -1,618 +0,0 @@
-/*!
-# Borrow check
-
-This pass is in job of enforcing *memory safety* and *purity*.  As
-memory safety is by far the more complex topic, I'll focus on that in
-this description, but purity will be covered later on. In the context
-of Rust, memory safety means three basic things:
-
-- no writes to immutable memory;
-- all pointers point to non-freed memory;
-- all pointers point to memory of the same type as the pointer.
-
-The last point might seem confusing: after all, for the most part,
-this condition is guaranteed by the type check.  However, there are
-two cases where the type check effectively delegates to borrow check.
-
-The first case has to do with enums.  If there is a pointer to the
-interior of an enum, and the enum is in a mutable location (such as a
-local variable or field declared to be mutable), it is possible that
-the user will overwrite the enum with a new value of a different
-variant, and thus effectively change the type of the memory that the
-pointer is pointing at.
-
-The second case has to do with mutability.  Basically, the type
-checker has only a limited understanding of mutability.  It will allow
-(for example) the user to get an immutable pointer with the address of
-a mutable local variable.  It will also allow a `@mut T` or `~mut T`
-pointer to be borrowed as a `&r.T` pointer.  These seeming oversights
-are in fact intentional; they allow the user to temporarily treat a
-mutable value as immutable.  It is up to the borrow check to guarantee
-that the value in question is not in fact mutated during the lifetime
-`r` of the reference.
-
-# Definition of unstable memory
-
-The primary danger to safety arises due to *unstable memory*.
-Unstable memory is memory whose validity or type may change as a
-result of an assignment, move, or a variable going out of scope.
-There are two cases in Rust where memory is unstable: the contents of
-unique boxes and enums.
-
-Unique boxes are unstable because when the variable containing the
-unique box is re-assigned, moves, or goes out of scope, the unique box
-is freed or---in the case of a move---potentially given to another
-task.  In either case, if there is an extant and usable pointer into
-the box, then safety guarantees would be compromised.
-
-Enum values are unstable because they are reassigned the types of
-their contents may change if they are assigned with a different
-variant than they had previously.
-
-# Safety criteria that must be enforced
-
-Whenever a piece of memory is borrowed for lifetime L, there are two
-things which the borrow checker must guarantee.  First, it must
-guarantee that the memory address will remain allocated (and owned by
-the current task) for the entirety of the lifetime L.  Second, it must
-guarantee that the type of the data will not change for the entirety
-of the lifetime L.  In exchange, the region-based type system will
-guarantee that the pointer is not used outside the lifetime L.  These
-guarantees are to some extent independent but are also inter-related.
-
-In some cases, the type of a pointer cannot be invalidated but the
-lifetime can.  For example, imagine a pointer to the interior of
-a shared box like:
-
-    let mut x = @mut {f: 5, g: 6};
-    let y = &mut x.f;
-
-Here, a pointer was created to the interior of a shared box which
-contains a record.  Even if `*x` were to be mutated like so:
-
-    *x = {f: 6, g: 7};
-
-This would cause `*y` to change from 5 to 6, but the pointer pointer
-`y` remains valid.  It still points at an integer even if that integer
-has been overwritten.
-
-However, if we were to reassign `x` itself, like so:
-
-    x = @{f: 6, g: 7};
-
-This could potentially invalidate `y`, because if `x` were the final
-reference to the shared box, then that memory would be released and
-now `y` points at freed memory.  (We will see that to prevent this
-scenario we will *root* shared boxes that reside in mutable memory
-whose contents are borrowed; rooting means that we create a temporary
-to ensure that the box is not collected).
-
-In other cases, like an enum on the stack, the memory cannot be freed
-but its type can change:
-
-    let mut x = Some(5);
-    match x {
-      Some(ref y) => { ... }
-      None => { ... }
-    }
-
-Here as before, the pointer `y` would be invalidated if we were to
-reassign `x` to `none`.  (We will see that this case is prevented
-because borrowck tracks data which resides on the stack and prevents
-variables from reassigned if there may be pointers to their interior)
-
-Finally, in some cases, both dangers can arise.  For example, something
-like the following:
-
-    let mut x = ~some(5);
-    match x {
-      ~some(ref y) => { ... }
-      ~none => { ... }
-    }
-
-In this case, if `x` to be reassigned or `*x` were to be mutated, then
-the pointer `y` would be invalided.  (This case is also prevented by
-borrowck tracking data which is owned by the current stack frame)
-
-# Summary of the safety check
-
-In order to enforce mutability, the borrow check has a few tricks up
-its sleeve:
-
-- When data is owned by the current stack frame, we can identify every
-  possible assignment to a local variable and simply prevent
-  potentially dangerous assignments directly.
-
-- If data is owned by a shared box, we can root the box to increase
-  its lifetime.
-
-- If data is found within a borrowed pointer, we can assume that the
-  data will remain live for the entirety of the borrowed pointer.
-
-- We can rely on the fact that pure actions (such as calling pure
-  functions) do not mutate data which is not owned by the current
-  stack frame.
-
-# Possible future directions
-
-There are numerous ways that the `borrowck` could be strengthened, but
-these are the two most likely:
-
-- flow-sensitivity: we do not currently consider flow at all but only
-  block-scoping.  This means that innocent code like the following is
-  rejected:
-
-      let mut x: int;
-      ...
-      x = 5;
-      let y: &int = &x; // immutable ptr created
-      ...
-
-  The reason is that the scope of the pointer `y` is the entire
-  enclosing block, and the assignment `x = 5` occurs within that
-  block.  The analysis is not smart enough to see that `x = 5` always
-  happens before the immutable pointer is created.  This is relatively
-  easy to fix and will surely be fixed at some point.
-
-- finer-grained purity checks: currently, our fallback for
-  guaranteeing random references into mutable, aliasable memory is to
-  require *total purity*.  This is rather strong.  We could use local
-  type-based alias analysis to distinguish writes that could not
-  possibly invalid the references which must be guaranteed.  This
-  would only work within the function boundaries; function calls would
-  still require total purity.  This seems less likely to be
-  implemented in the short term as it would make the code
-  significantly more complex; there is currently no code to analyze
-  the types and determine the possible impacts of a write.
-
-# How the code works
-
-The borrow check code is divided into several major modules, each of
-which is documented in its own file.
-
-The `gather_loans` and `check_loans` are the two major passes of the
-analysis.  The `gather_loans` pass runs over the IR once to determine
-what memory must remain valid and for how long.  Its name is a bit of
-a misnomer; it does in fact gather up the set of loans which are
-granted, but it also determines when @T pointers must be rooted and
-for which scopes purity must be required.
-
-The `check_loans` pass walks the IR and examines the loans and purity
-requirements computed in `gather_loans`.  It checks to ensure that (a)
-the conditions of all loans are honored; (b) no contradictory loans
-were granted (for example, loaning out the same memory as mutable and
-immutable simultaneously); and (c) any purity requirements are
-honored.
-
-The remaining modules are helper modules used by `gather_loans` and
-`check_loans`:
-
-- `categorization` has the job of analyzing an expression to determine
-  what kind of memory is used in evaluating it (for example, where
-  dereferences occur and what kind of pointer is dereferenced; whether
-  the memory is mutable; etc)
-- `loan` determines when data uniquely tied to the stack frame can be
-  loaned out.
-- `preserve` determines what actions (if any) must be taken to preserve
-  aliasable data.  This is the code which decides when to root
-  an @T pointer or to require purity.
-
-# Maps that are created
-
-Borrowck results in two maps.
-
-- `root_map`: identifies those expressions or patterns whose result
-  needs to be rooted.  Conceptually the root_map maps from an
-  expression or pattern node to a `node_id` identifying the scope for
-  which the expression must be rooted (this `node_id` should identify
-  a block or call).  The actual key to the map is not an expression id,
-  however, but a `root_map_key`, which combines an expression id with a
-  deref count and is used to cope with auto-deref.
-
-- `mutbl_map`: identifies those local variables which are modified or
-  moved. This is used by trans to guarantee that such variables are
-  given a memory location and not used as immediates.
- */
-
-use syntax::ast;
-use syntax::ast::{mutability, m_mutbl, m_imm, m_const};
-use syntax::visit;
-use syntax::ast_util;
-use syntax::ast_map;
-use syntax::codemap::span;
-use util::ppaux::{ty_to_str, region_to_str, explain_region,
-                  expr_repr, note_and_explain_region};
-use std::map::{HashMap, Set};
-use std::list;
-use std::list::{List, Cons, Nil};
-use result::{Result, Ok, Err};
-use syntax::print::pprust;
-use util::common::indenter;
-use ty::to_str;
-use dvec::DVec;
-use mem_categorization::*;
-
-export check_crate, root_map, mutbl_map;
-
-fn check_crate(tcx: ty::ctxt,
-               method_map: typeck::method_map,
-               last_use_map: liveness::last_use_map,
-               crate: @ast::crate) -> (root_map, mutbl_map) {
-
-    let bccx = borrowck_ctxt_(@{tcx: tcx,
-                                method_map: method_map,
-                                last_use_map: last_use_map,
-                                root_map: root_map(),
-                                mutbl_map: HashMap(),
-                                mut loaned_paths_same: 0,
-                                mut loaned_paths_imm: 0,
-                                mut stable_paths: 0,
-                                mut req_pure_paths: 0,
-                                mut guaranteed_paths: 0});
-
-    let req_maps = gather_loans::gather_loans(bccx, crate);
-    check_loans::check_loans(bccx, req_maps, crate);
-
-    if tcx.sess.borrowck_stats() {
-        io::println(~"--- borrowck stats ---");
-        io::println(fmt!("paths requiring guarantees: %u",
-                        bccx.guaranteed_paths));
-        io::println(fmt!("paths requiring loans     : %s",
-                         make_stat(bccx, bccx.loaned_paths_same)));
-        io::println(fmt!("paths requiring imm loans : %s",
-                         make_stat(bccx, bccx.loaned_paths_imm)));
-        io::println(fmt!("stable paths              : %s",
-                         make_stat(bccx, bccx.stable_paths)));
-        io::println(fmt!("paths requiring purity    : %s",
-                         make_stat(bccx, bccx.req_pure_paths)));
-    }
-
-    return (bccx.root_map, bccx.mutbl_map);
-
-    fn make_stat(bccx: borrowck_ctxt, stat: uint) -> ~str {
-        let stat_f = stat as float;
-        let total = bccx.guaranteed_paths as float;
-        fmt!("%u (%.0f%%)", stat  , stat_f * 100f / total)
-    }
-}
-
-// ----------------------------------------------------------------------
-// Type definitions
-
-type borrowck_ctxt_ = {tcx: ty::ctxt,
-                       method_map: typeck::method_map,
-                       last_use_map: liveness::last_use_map,
-                       root_map: root_map,
-                       mutbl_map: mutbl_map,
-
-                       // Statistics:
-                       mut loaned_paths_same: uint,
-                       mut loaned_paths_imm: uint,
-                       mut stable_paths: uint,
-                       mut req_pure_paths: uint,
-                       mut guaranteed_paths: uint};
-
-enum borrowck_ctxt {
-    borrowck_ctxt_(@borrowck_ctxt_)
-}
-
-// a map mapping id's of expressions of gc'd type (@T, @[], etc) where
-// the box needs to be kept live to the id of the scope for which they
-// must stay live.
-type root_map = HashMap<root_map_key, ast::node_id>;
-
-// the keys to the root map combine the `id` of the expression with
-// the number of types that it is autodereferenced.  So, for example,
-// if you have an expression `x.f` and x has type ~@T, we could add an
-// entry {id:x, derefs:0} to refer to `x` itself, `{id:x, derefs:1}`
-// to refer to the deref of the unique pointer, and so on.
-type root_map_key = {id: ast::node_id, derefs: uint};
-
-// set of ids of local vars / formal arguments that are modified / moved.
-// this is used in trans for optimization purposes.
-type mutbl_map = std::map::HashMap<ast::node_id, ()>;
-
-// Errors that can occur"]
-enum bckerr_code {
-    err_mut_uniq,
-    err_mut_variant,
-    err_root_not_permitted,
-    err_mutbl(ast::mutability),
-    err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope
-    err_out_of_scope(ty::Region, ty::Region) // superscope, subscope
-}
-
-impl bckerr_code : cmp::Eq {
-    pure fn eq(&self, other: &bckerr_code) -> bool {
-        match (*self) {
-            err_mut_uniq => {
-                match (*other) {
-                    err_mut_uniq => true,
-                    _ => false
-                }
-            }
-            err_mut_variant => {
-                match (*other) {
-                    err_mut_variant => true,
-                    _ => false
-                }
-            }
-            err_root_not_permitted => {
-                match (*other) {
-                    err_root_not_permitted => true,
-                    _ => false
-                }
-            }
-            err_mutbl(e0a) => {
-                match (*other) {
-                    err_mutbl(e0b) => e0a == e0b,
-                    _ => false
-                }
-            }
-            err_out_of_root_scope(e0a, e1a) => {
-                match (*other) {
-                    err_out_of_root_scope(e0b, e1b) =>
-                        e0a == e0b && e1a == e1b,
-                    _ => false
-                }
-            }
-            err_out_of_scope(e0a, e1a) => {
-                match (*other) {
-                    err_out_of_scope(e0b, e1b) => e0a == e0b && e1a == e1b,
-                    _ => false
-                }
-            }
-        }
-    }
-    pure fn ne(&self, other: &bckerr_code) -> bool { !(*self).eq(other) }
-}
-
-// Combination of an error code and the categorization of the expression
-// that caused it
-type bckerr = {cmt: cmt, code: bckerr_code};
-
-impl bckerr : cmp::Eq {
-    pure fn eq(&self, other: &bckerr) -> bool {
-        (*self).cmt == (*other).cmt && (*self).code == (*other).code
-    }
-    pure fn ne(&self, other: &bckerr) -> bool { !(*self).eq(other) }
-}
-
-// shorthand for something that fails with `bckerr` or succeeds with `T`
-type bckres<T> = Result<T, bckerr>;
-
-/// a complete record of a loan that was granted
-struct Loan {lp: @loan_path, cmt: cmt, mutbl: ast::mutability}
-
-/// maps computed by `gather_loans` that are then used by `check_loans`
-///
-/// - `req_loan_map`: map from each block/expr to the required loans needed
-///   for the duration of that block/expr
-/// - `pure_map`: map from block/expr that must be pure to the error message
-///   that should be reported if they are not pure
-type req_maps = {
-    req_loan_map: HashMap<ast::node_id, @DVec<Loan>>,
-    pure_map: HashMap<ast::node_id, bckerr>
-};
-
-fn save_and_restore<T:Copy,U>(save_and_restore_t: &mut T, f: fn() -> U) -> U {
-    let old_save_and_restore_t = *save_and_restore_t;
-    let u = f();
-    *save_and_restore_t = old_save_and_restore_t;
-    move u
-}
-
-/// Creates and returns a new root_map
-
-impl root_map_key : cmp::Eq {
-    pure fn eq(&self, other: &root_map_key) -> bool {
-        (*self).id == (*other).id && (*self).derefs == (*other).derefs
-    }
-    pure fn ne(&self, other: &root_map_key) -> bool {
-        ! ((*self) == (*other))
-    }
-}
-
-#[cfg(stage0)]
-impl root_map_key : to_bytes::IterBytes {
-    pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
-        to_bytes::iter_bytes_2(&self.id, &self.derefs, lsb0, f);
-    }
-}
-#[cfg(stage1)]
-#[cfg(stage2)]
-impl root_map_key : to_bytes::IterBytes {
-    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
-        to_bytes::iter_bytes_2(&self.id, &self.derefs, lsb0, f);
-    }
-}
-
-fn root_map() -> root_map {
-    return HashMap();
-
-    pure fn root_map_key_eq(k1: &root_map_key, k2: &root_map_key) -> bool {
-        k1.id == k2.id && k1.derefs == k2.derefs
-    }
-
-    pure fn root_map_key_hash(k: &root_map_key) -> uint {
-        (k.id << 4) as uint | k.derefs
-    }
-}
-
-// ___________________________________________________________________________
-// Misc
-
-impl borrowck_ctxt {
-    fn is_subregion_of(r_sub: ty::Region, r_sup: ty::Region) -> bool {
-        region::is_subregion_of(self.tcx.region_map, r_sub, r_sup)
-    }
-
-    fn cat_expr(expr: @ast::expr) -> cmt {
-        cat_expr(self.tcx, self.method_map, expr)
-    }
-
-    fn cat_expr_unadjusted(expr: @ast::expr) -> cmt {
-        cat_expr_unadjusted(self.tcx, self.method_map, expr)
-    }
-
-    fn cat_expr_autoderefd(expr: @ast::expr,
-                           adj: @ty::AutoAdjustment)
-                        -> cmt {
-        cat_expr_autoderefd(self.tcx, self.method_map, expr, adj)
-    }
-
-    fn cat_def(id: ast::node_id,
-               span: span,
-               ty: ty::t,
-               def: ast::def) -> cmt {
-        cat_def(self.tcx, self.method_map, id, span, ty, def)
-    }
-
-    fn cat_variant<N: ast_node>(arg: N,
-                                enum_did: ast::def_id,
-                                cmt: cmt) -> cmt {
-        cat_variant(self.tcx, self.method_map, arg, enum_did, cmt)
-    }
-
-    fn cat_discr(cmt: cmt, alt_id: ast::node_id) -> cmt {
-        return @{cat:cat_discr(cmt, alt_id),.. *cmt};
-    }
-
-    fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) {
-        let mc = &mem_categorization_ctxt {tcx: self.tcx,
-                                           method_map: self.method_map};
-        mc.cat_pattern(cmt, pat, op);
-    }
-
-    fn report_if_err(bres: bckres<()>) {
-        match bres {
-          Ok(()) => (),
-          Err(e) => self.report(e)
-        }
-    }
-
-    fn report(err: bckerr) {
-        self.span_err(
-            err.cmt.span,
-            fmt!("illegal borrow: %s",
-                 self.bckerr_to_str(err)));
-        self.note_and_explain_bckerr(err);
-    }
-
-    fn span_err(s: span, m: ~str) {
-        self.tcx.sess.span_err(s, m);
-    }
-
-    fn span_note(s: span, m: ~str) {
-        self.tcx.sess.span_note(s, m);
-    }
-
-    fn add_to_mutbl_map(cmt: cmt) {
-        match cmt.cat {
-          cat_local(id) | cat_arg(id) => {
-            self.mutbl_map.insert(id, ());
-          }
-          cat_stack_upvar(cmt) => {
-            self.add_to_mutbl_map(cmt);
-          }
-          _ => ()
-        }
-    }
-
-    fn bckerr_to_str(err: bckerr) -> ~str {
-        match err.code {
-            err_mutbl(req) => {
-                fmt!("creating %s alias to %s",
-                     self.mut_to_str(req),
-                     self.cmt_to_str(err.cmt))
-            }
-            err_mut_uniq => {
-                ~"unique value in aliasable, mutable location"
-            }
-            err_mut_variant => {
-                ~"enum variant in aliasable, mutable location"
-            }
-            err_root_not_permitted => {
-                // note: I don't expect users to ever see this error
-                // message, reasons are discussed in attempt_root() in
-                // preserve.rs.
-                ~"rooting is not permitted"
-            }
-            err_out_of_root_scope(*) => {
-                ~"cannot root managed value long enough"
-            }
-            err_out_of_scope(*) => {
-                ~"borrowed value does not live long enough"
-            }
-        }
-    }
-
-    fn note_and_explain_bckerr(err: bckerr) {
-        let code = err.code;
-        match code {
-            err_mutbl(*) | err_mut_uniq | err_mut_variant |
-            err_root_not_permitted => {}
-
-            err_out_of_root_scope(super_scope, sub_scope) => {
-                note_and_explain_region(
-                    self.tcx,
-                    ~"managed value would have to be rooted for ",
-                    sub_scope,
-                    ~"...");
-                note_and_explain_region(
-                    self.tcx,
-                    ~"...but can only be rooted for ",
-                    super_scope,
-                    ~"");
-            }
-
-            err_out_of_scope(super_scope, sub_scope) => {
-                note_and_explain_region(
-                    self.tcx,
-                    ~"borrowed pointer must be valid for ",
-                    sub_scope,
-                    ~"...");
-                note_and_explain_region(
-                    self.tcx,
-                    ~"...but borrowed value is only valid for ",
-                    super_scope,
-                    ~"");
-          }
-        }
-    }
-
-
-    fn cmt_to_str(cmt: cmt) -> ~str {
-        let mc = &mem_categorization_ctxt {tcx: self.tcx,
-                                           method_map: self.method_map};
-        mc.cmt_to_str(cmt)
-    }
-
-    fn cmt_to_repr(cmt: cmt) -> ~str {
-        let mc = &mem_categorization_ctxt {tcx: self.tcx,
-                                           method_map: self.method_map};
-        mc.cmt_to_repr(cmt)
-    }
-
-    fn mut_to_str(mutbl: ast::mutability) -> ~str {
-        let mc = &mem_categorization_ctxt {tcx: self.tcx,
-                                           method_map: self.method_map};
-        mc.mut_to_str(mutbl)
-    }
-
-    fn loan_to_repr(loan: &Loan) -> ~str {
-        fmt!("Loan(lp=%?, cmt=%s, mutbl=%?)",
-             loan.lp, self.cmt_to_repr(loan.cmt), loan.mutbl)
-    }
-}
-
-// The inherent mutability of a component is its default mutability
-// assuming it is embedded in an immutable context.  In general, the
-// mutability can be "overridden" if the component is embedded in a
-// mutable structure.
-fn inherent_mutability(ck: comp_kind) -> mutability {
-    match ck {
-      comp_tuple | comp_anon_field | comp_variant(_) => m_imm,
-      comp_field(_, m) | comp_index(_, m)            => m
-    }
-}
diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs
index c4411008404..6ef80321ec2 100644
--- a/src/librustc/middle/borrowck/mod.rs
+++ b/src/librustc/middle/borrowck/mod.rs
@@ -1,4 +1,239 @@
+/*!
+# Borrow check
+
+This pass is in job of enforcing *memory safety* and *purity*.  As
+memory safety is by far the more complex topic, I'll focus on that in
+this description, but purity will be covered later on. In the context
+of Rust, memory safety means three basic things:
+
+- no writes to immutable memory;
+- all pointers point to non-freed memory;
+- all pointers point to memory of the same type as the pointer.
+
+The last point might seem confusing: after all, for the most part,
+this condition is guaranteed by the type check.  However, there are
+two cases where the type check effectively delegates to borrow check.
+
+The first case has to do with enums.  If there is a pointer to the
+interior of an enum, and the enum is in a mutable location (such as a
+local variable or field declared to be mutable), it is possible that
+the user will overwrite the enum with a new value of a different
+variant, and thus effectively change the type of the memory that the
+pointer is pointing at.
+
+The second case has to do with mutability.  Basically, the type
+checker has only a limited understanding of mutability.  It will allow
+(for example) the user to get an immutable pointer with the address of
+a mutable local variable.  It will also allow a `@mut T` or `~mut T`
+pointer to be borrowed as a `&r.T` pointer.  These seeming oversights
+are in fact intentional; they allow the user to temporarily treat a
+mutable value as immutable.  It is up to the borrow check to guarantee
+that the value in question is not in fact mutated during the lifetime
+`r` of the reference.
+
+# Definition of unstable memory
+
+The primary danger to safety arises due to *unstable memory*.
+Unstable memory is memory whose validity or type may change as a
+result of an assignment, move, or a variable going out of scope.
+There are two cases in Rust where memory is unstable: the contents of
+unique boxes and enums.
+
+Unique boxes are unstable because when the variable containing the
+unique box is re-assigned, moves, or goes out of scope, the unique box
+is freed or---in the case of a move---potentially given to another
+task.  In either case, if there is an extant and usable pointer into
+the box, then safety guarantees would be compromised.
+
+Enum values are unstable because they are reassigned the types of
+their contents may change if they are assigned with a different
+variant than they had previously.
+
+# Safety criteria that must be enforced
+
+Whenever a piece of memory is borrowed for lifetime L, there are two
+things which the borrow checker must guarantee.  First, it must
+guarantee that the memory address will remain allocated (and owned by
+the current task) for the entirety of the lifetime L.  Second, it must
+guarantee that the type of the data will not change for the entirety
+of the lifetime L.  In exchange, the region-based type system will
+guarantee that the pointer is not used outside the lifetime L.  These
+guarantees are to some extent independent but are also inter-related.
+
+In some cases, the type of a pointer cannot be invalidated but the
+lifetime can.  For example, imagine a pointer to the interior of
+a shared box like:
+
+    let mut x = @mut {f: 5, g: 6};
+    let y = &mut x.f;
+
+Here, a pointer was created to the interior of a shared box which
+contains a record.  Even if `*x` were to be mutated like so:
+
+    *x = {f: 6, g: 7};
+
+This would cause `*y` to change from 5 to 6, but the pointer pointer
+`y` remains valid.  It still points at an integer even if that integer
+has been overwritten.
+
+However, if we were to reassign `x` itself, like so:
+
+    x = @{f: 6, g: 7};
+
+This could potentially invalidate `y`, because if `x` were the final
+reference to the shared box, then that memory would be released and
+now `y` points at freed memory.  (We will see that to prevent this
+scenario we will *root* shared boxes that reside in mutable memory
+whose contents are borrowed; rooting means that we create a temporary
+to ensure that the box is not collected).
+
+In other cases, like an enum on the stack, the memory cannot be freed
+but its type can change:
+
+    let mut x = Some(5);
+    match x {
+      Some(ref y) => { ... }
+      None => { ... }
+    }
+
+Here as before, the pointer `y` would be invalidated if we were to
+reassign `x` to `none`.  (We will see that this case is prevented
+because borrowck tracks data which resides on the stack and prevents
+variables from reassigned if there may be pointers to their interior)
+
+Finally, in some cases, both dangers can arise.  For example, something
+like the following:
+
+    let mut x = ~some(5);
+    match x {
+      ~some(ref y) => { ... }
+      ~none => { ... }
+    }
+
+In this case, if `x` to be reassigned or `*x` were to be mutated, then
+the pointer `y` would be invalided.  (This case is also prevented by
+borrowck tracking data which is owned by the current stack frame)
+
+# Summary of the safety check
+
+In order to enforce mutability, the borrow check has a few tricks up
+its sleeve:
+
+- When data is owned by the current stack frame, we can identify every
+  possible assignment to a local variable and simply prevent
+  potentially dangerous assignments directly.
+
+- If data is owned by a shared box, we can root the box to increase
+  its lifetime.
+
+- If data is found within a borrowed pointer, we can assume that the
+  data will remain live for the entirety of the borrowed pointer.
+
+- We can rely on the fact that pure actions (such as calling pure
+  functions) do not mutate data which is not owned by the current
+  stack frame.
+
+# Possible future directions
+
+There are numerous ways that the `borrowck` could be strengthened, but
+these are the two most likely:
+
+- flow-sensitivity: we do not currently consider flow at all but only
+  block-scoping.  This means that innocent code like the following is
+  rejected:
+
+      let mut x: int;
+      ...
+      x = 5;
+      let y: &int = &x; // immutable ptr created
+      ...
+
+  The reason is that the scope of the pointer `y` is the entire
+  enclosing block, and the assignment `x = 5` occurs within that
+  block.  The analysis is not smart enough to see that `x = 5` always
+  happens before the immutable pointer is created.  This is relatively
+  easy to fix and will surely be fixed at some point.
+
+- finer-grained purity checks: currently, our fallback for
+  guaranteeing random references into mutable, aliasable memory is to
+  require *total purity*.  This is rather strong.  We could use local
+  type-based alias analysis to distinguish writes that could not
+  possibly invalid the references which must be guaranteed.  This
+  would only work within the function boundaries; function calls would
+  still require total purity.  This seems less likely to be
+  implemented in the short term as it would make the code
+  significantly more complex; there is currently no code to analyze
+  the types and determine the possible impacts of a write.
+
+# How the code works
+
+The borrow check code is divided into several major modules, each of
+which is documented in its own file.
+
+The `gather_loans` and `check_loans` are the two major passes of the
+analysis.  The `gather_loans` pass runs over the IR once to determine
+what memory must remain valid and for how long.  Its name is a bit of
+a misnomer; it does in fact gather up the set of loans which are
+granted, but it also determines when @T pointers must be rooted and
+for which scopes purity must be required.
+
+The `check_loans` pass walks the IR and examines the loans and purity
+requirements computed in `gather_loans`.  It checks to ensure that (a)
+the conditions of all loans are honored; (b) no contradictory loans
+were granted (for example, loaning out the same memory as mutable and
+immutable simultaneously); and (c) any purity requirements are
+honored.
+
+The remaining modules are helper modules used by `gather_loans` and
+`check_loans`:
+
+- `categorization` has the job of analyzing an expression to determine
+  what kind of memory is used in evaluating it (for example, where
+  dereferences occur and what kind of pointer is dereferenced; whether
+  the memory is mutable; etc)
+- `loan` determines when data uniquely tied to the stack frame can be
+  loaned out.
+- `preserve` determines what actions (if any) must be taken to preserve
+  aliasable data.  This is the code which decides when to root
+  an @T pointer or to require purity.
+
+# Maps that are created
+
+Borrowck results in two maps.
+
+- `root_map`: identifies those expressions or patterns whose result
+  needs to be rooted.  Conceptually the root_map maps from an
+  expression or pattern node to a `node_id` identifying the scope for
+  which the expression must be rooted (this `node_id` should identify
+  a block or call).  The actual key to the map is not an expression id,
+  however, but a `root_map_key`, which combines an expression id with a
+  deref count and is used to cope with auto-deref.
+
+- `mutbl_map`: identifies those local variables which are modified or
+  moved. This is used by trans to guarantee that such variables are
+  given a memory location and not used as immediates.
+ */
+
 #[legacy_exports];
+
+use syntax::ast;
+use syntax::ast::{mutability, m_mutbl, m_imm, m_const};
+use syntax::visit;
+use syntax::ast_util;
+use syntax::ast_map;
+use syntax::codemap::span;
+use util::ppaux::{ty_to_str, region_to_str, explain_region,
+                  expr_repr, note_and_explain_region};
+use std::map::{HashMap, Set};
+use std::list;
+use std::list::{List, Cons, Nil};
+use result::{Result, Ok, Err};
+use syntax::print::pprust;
+use util::common::indenter;
+use ty::to_str;
+use dvec::DVec;
+use mem_categorization::*;
+
 #[legacy_exports]
 mod check_loans;
 #[legacy_exports]
@@ -7,3 +242,388 @@ mod gather_loans;
 mod loan;
 #[legacy_exports]
 mod preserve;
+
+export check_crate, root_map, mutbl_map;
+
+fn check_crate(tcx: ty::ctxt,
+               method_map: typeck::method_map,
+               last_use_map: liveness::last_use_map,
+               crate: @ast::crate) -> (root_map, mutbl_map) {
+
+    let bccx = borrowck_ctxt_(@{tcx: tcx,
+                                method_map: method_map,
+                                last_use_map: last_use_map,
+                                root_map: root_map(),
+                                mutbl_map: HashMap(),
+                                mut loaned_paths_same: 0,
+                                mut loaned_paths_imm: 0,
+                                mut stable_paths: 0,
+                                mut req_pure_paths: 0,
+                                mut guaranteed_paths: 0});
+
+    let req_maps = gather_loans::gather_loans(bccx, crate);
+    check_loans::check_loans(bccx, req_maps, crate);
+
+    if tcx.sess.borrowck_stats() {
+        io::println(~"--- borrowck stats ---");
+        io::println(fmt!("paths requiring guarantees: %u",
+                        bccx.guaranteed_paths));
+        io::println(fmt!("paths requiring loans     : %s",
+                         make_stat(bccx, bccx.loaned_paths_same)));
+        io::println(fmt!("paths requiring imm loans : %s",
+                         make_stat(bccx, bccx.loaned_paths_imm)));
+        io::println(fmt!("stable paths              : %s",
+                         make_stat(bccx, bccx.stable_paths)));
+        io::println(fmt!("paths requiring purity    : %s",
+                         make_stat(bccx, bccx.req_pure_paths)));
+    }
+
+    return (bccx.root_map, bccx.mutbl_map);
+
+    fn make_stat(bccx: borrowck_ctxt, stat: uint) -> ~str {
+        let stat_f = stat as float;
+        let total = bccx.guaranteed_paths as float;
+        fmt!("%u (%.0f%%)", stat  , stat_f * 100f / total)
+    }
+}
+
+// ----------------------------------------------------------------------
+// Type definitions
+
+type borrowck_ctxt_ = {tcx: ty::ctxt,
+                       method_map: typeck::method_map,
+                       last_use_map: liveness::last_use_map,
+                       root_map: root_map,
+                       mutbl_map: mutbl_map,
+
+                       // Statistics:
+                       mut loaned_paths_same: uint,
+                       mut loaned_paths_imm: uint,
+                       mut stable_paths: uint,
+                       mut req_pure_paths: uint,
+                       mut guaranteed_paths: uint};
+
+enum borrowck_ctxt {
+    borrowck_ctxt_(@borrowck_ctxt_)
+}
+
+// a map mapping id's of expressions of gc'd type (@T, @[], etc) where
+// the box needs to be kept live to the id of the scope for which they
+// must stay live.
+type root_map = HashMap<root_map_key, ast::node_id>;
+
+// the keys to the root map combine the `id` of the expression with
+// the number of types that it is autodereferenced.  So, for example,
+// if you have an expression `x.f` and x has type ~@T, we could add an
+// entry {id:x, derefs:0} to refer to `x` itself, `{id:x, derefs:1}`
+// to refer to the deref of the unique pointer, and so on.
+type root_map_key = {id: ast::node_id, derefs: uint};
+
+// set of ids of local vars / formal arguments that are modified / moved.
+// this is used in trans for optimization purposes.
+type mutbl_map = std::map::HashMap<ast::node_id, ()>;
+
+// Errors that can occur"]
+enum bckerr_code {
+    err_mut_uniq,
+    err_mut_variant,
+    err_root_not_permitted,
+    err_mutbl(ast::mutability),
+    err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope
+    err_out_of_scope(ty::Region, ty::Region) // superscope, subscope
+}
+
+impl bckerr_code : cmp::Eq {
+    pure fn eq(&self, other: &bckerr_code) -> bool {
+        match (*self) {
+            err_mut_uniq => {
+                match (*other) {
+                    err_mut_uniq => true,
+                    _ => false
+                }
+            }
+            err_mut_variant => {
+                match (*other) {
+                    err_mut_variant => true,
+                    _ => false
+                }
+            }
+            err_root_not_permitted => {
+                match (*other) {
+                    err_root_not_permitted => true,
+                    _ => false
+                }
+            }
+            err_mutbl(e0a) => {
+                match (*other) {
+                    err_mutbl(e0b) => e0a == e0b,
+                    _ => false
+                }
+            }
+            err_out_of_root_scope(e0a, e1a) => {
+                match (*other) {
+                    err_out_of_root_scope(e0b, e1b) =>
+                        e0a == e0b && e1a == e1b,
+                    _ => false
+                }
+            }
+            err_out_of_scope(e0a, e1a) => {
+                match (*other) {
+                    err_out_of_scope(e0b, e1b) => e0a == e0b && e1a == e1b,
+                    _ => false
+                }
+            }
+        }
+    }
+    pure fn ne(&self, other: &bckerr_code) -> bool { !(*self).eq(other) }
+}
+
+// Combination of an error code and the categorization of the expression
+// that caused it
+type bckerr = {cmt: cmt, code: bckerr_code};
+
+impl bckerr : cmp::Eq {
+    pure fn eq(&self, other: &bckerr) -> bool {
+        (*self).cmt == (*other).cmt && (*self).code == (*other).code
+    }
+    pure fn ne(&self, other: &bckerr) -> bool { !(*self).eq(other) }
+}
+
+// shorthand for something that fails with `bckerr` or succeeds with `T`
+type bckres<T> = Result<T, bckerr>;
+
+/// a complete record of a loan that was granted
+struct Loan {lp: @loan_path, cmt: cmt, mutbl: ast::mutability}
+
+/// maps computed by `gather_loans` that are then used by `check_loans`
+///
+/// - `req_loan_map`: map from each block/expr to the required loans needed
+///   for the duration of that block/expr
+/// - `pure_map`: map from block/expr that must be pure to the error message
+///   that should be reported if they are not pure
+type req_maps = {
+    req_loan_map: HashMap<ast::node_id, @DVec<Loan>>,
+    pure_map: HashMap<ast::node_id, bckerr>
+};
+
+fn save_and_restore<T:Copy,U>(save_and_restore_t: &mut T, f: fn() -> U) -> U {
+    let old_save_and_restore_t = *save_and_restore_t;
+    let u = f();
+    *save_and_restore_t = old_save_and_restore_t;
+    move u
+}
+
+/// Creates and returns a new root_map
+
+impl root_map_key : cmp::Eq {
+    pure fn eq(&self, other: &root_map_key) -> bool {
+        (*self).id == (*other).id && (*self).derefs == (*other).derefs
+    }
+    pure fn ne(&self, other: &root_map_key) -> bool {
+        ! ((*self) == (*other))
+    }
+}
+
+#[cfg(stage0)]
+impl root_map_key : to_bytes::IterBytes {
+    pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) {
+        to_bytes::iter_bytes_2(&self.id, &self.derefs, lsb0, f);
+    }
+}
+#[cfg(stage1)]
+#[cfg(stage2)]
+impl root_map_key : to_bytes::IterBytes {
+    pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
+        to_bytes::iter_bytes_2(&self.id, &self.derefs, lsb0, f);
+    }
+}
+
+fn root_map() -> root_map {
+    return HashMap();
+
+    pure fn root_map_key_eq(k1: &root_map_key, k2: &root_map_key) -> bool {
+        k1.id == k2.id && k1.derefs == k2.derefs
+    }
+
+    pure fn root_map_key_hash(k: &root_map_key) -> uint {
+        (k.id << 4) as uint | k.derefs
+    }
+}
+
+// ___________________________________________________________________________
+// Misc
+
+impl borrowck_ctxt {
+    fn is_subregion_of(r_sub: ty::Region, r_sup: ty::Region) -> bool {
+        region::is_subregion_of(self.tcx.region_map, r_sub, r_sup)
+    }
+
+    fn cat_expr(expr: @ast::expr) -> cmt {
+        cat_expr(self.tcx, self.method_map, expr)
+    }
+
+    fn cat_expr_unadjusted(expr: @ast::expr) -> cmt {
+        cat_expr_unadjusted(self.tcx, self.method_map, expr)
+    }
+
+    fn cat_expr_autoderefd(expr: @ast::expr,
+                           adj: @ty::AutoAdjustment)
+                        -> cmt {
+        cat_expr_autoderefd(self.tcx, self.method_map, expr, adj)
+    }
+
+    fn cat_def(id: ast::node_id,
+               span: span,
+               ty: ty::t,
+               def: ast::def) -> cmt {
+        cat_def(self.tcx, self.method_map, id, span, ty, def)
+    }
+
+    fn cat_variant<N: ast_node>(arg: N,
+                                enum_did: ast::def_id,
+                                cmt: cmt) -> cmt {
+        cat_variant(self.tcx, self.method_map, arg, enum_did, cmt)
+    }
+
+    fn cat_discr(cmt: cmt, alt_id: ast::node_id) -> cmt {
+        return @{cat:cat_discr(cmt, alt_id),.. *cmt};
+    }
+
+    fn cat_pattern(cmt: cmt, pat: @ast::pat, op: fn(cmt, @ast::pat)) {
+        let mc = &mem_categorization_ctxt {tcx: self.tcx,
+                                           method_map: self.method_map};
+        mc.cat_pattern(cmt, pat, op);
+    }
+
+    fn report_if_err(bres: bckres<()>) {
+        match bres {
+          Ok(()) => (),
+          Err(e) => self.report(e)
+        }
+    }
+
+    fn report(err: bckerr) {
+        self.span_err(
+            err.cmt.span,
+            fmt!("illegal borrow: %s",
+                 self.bckerr_to_str(err)));
+        self.note_and_explain_bckerr(err);
+    }
+
+    fn span_err(s: span, m: ~str) {
+        self.tcx.sess.span_err(s, m);
+    }
+
+    fn span_note(s: span, m: ~str) {
+        self.tcx.sess.span_note(s, m);
+    }
+
+    fn add_to_mutbl_map(cmt: cmt) {
+        match cmt.cat {
+          cat_local(id) | cat_arg(id) => {
+            self.mutbl_map.insert(id, ());
+          }
+          cat_stack_upvar(cmt) => {
+            self.add_to_mutbl_map(cmt);
+          }
+          _ => ()
+        }
+    }
+
+    fn bckerr_to_str(err: bckerr) -> ~str {
+        match err.code {
+            err_mutbl(req) => {
+                fmt!("creating %s alias to %s",
+                     self.mut_to_str(req),
+                     self.cmt_to_str(err.cmt))
+            }
+            err_mut_uniq => {
+                ~"unique value in aliasable, mutable location"
+            }
+            err_mut_variant => {
+                ~"enum variant in aliasable, mutable location"
+            }
+            err_root_not_permitted => {
+                // note: I don't expect users to ever see this error
+                // message, reasons are discussed in attempt_root() in
+                // preserve.rs.
+                ~"rooting is not permitted"
+            }
+            err_out_of_root_scope(*) => {
+                ~"cannot root managed value long enough"
+            }
+            err_out_of_scope(*) => {
+                ~"borrowed value does not live long enough"
+            }
+        }
+    }
+
+    fn note_and_explain_bckerr(err: bckerr) {
+        let code = err.code;
+        match code {
+            err_mutbl(*) | err_mut_uniq | err_mut_variant |
+            err_root_not_permitted => {}
+
+            err_out_of_root_scope(super_scope, sub_scope) => {
+                note_and_explain_region(
+                    self.tcx,
+                    ~"managed value would have to be rooted for ",
+                    sub_scope,
+                    ~"...");
+                note_and_explain_region(
+                    self.tcx,
+                    ~"...but can only be rooted for ",
+                    super_scope,
+                    ~"");
+            }
+
+            err_out_of_scope(super_scope, sub_scope) => {
+                note_and_explain_region(
+                    self.tcx,
+                    ~"borrowed pointer must be valid for ",
+                    sub_scope,
+                    ~"...");
+                note_and_explain_region(
+                    self.tcx,
+                    ~"...but borrowed value is only valid for ",
+                    super_scope,
+                    ~"");
+          }
+        }
+    }
+
+
+    fn cmt_to_str(cmt: cmt) -> ~str {
+        let mc = &mem_categorization_ctxt {tcx: self.tcx,
+                                           method_map: self.method_map};
+        mc.cmt_to_str(cmt)
+    }
+
+    fn cmt_to_repr(cmt: cmt) -> ~str {
+        let mc = &mem_categorization_ctxt {tcx: self.tcx,
+                                           method_map: self.method_map};
+        mc.cmt_to_repr(cmt)
+    }
+
+    fn mut_to_str(mutbl: ast::mutability) -> ~str {
+        let mc = &mem_categorization_ctxt {tcx: self.tcx,
+                                           method_map: self.method_map};
+        mc.mut_to_str(mutbl)
+    }
+
+    fn loan_to_repr(loan: &Loan) -> ~str {
+        fmt!("Loan(lp=%?, cmt=%s, mutbl=%?)",
+             loan.lp, self.cmt_to_repr(loan.cmt), loan.mutbl)
+    }
+}
+
+// The inherent mutability of a component is its default mutability
+// assuming it is embedded in an immutable context.  In general, the
+// mutability can be "overridden" if the component is embedded in a
+// mutable structure.
+fn inherent_mutability(ck: comp_kind) -> mutability {
+    match ck {
+      comp_tuple | comp_anon_field | comp_variant(_) => m_imm,
+      comp_field(_, m) | comp_index(_, m)            => m
+    }
+}
diff --git a/src/librustc/middle/typeck.rs b/src/librustc/middle/typeck.rs
deleted file mode 100644
index 421c68fa9a2..00000000000
--- a/src/librustc/middle/typeck.rs
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
-
-typeck.rs, an introduction
-
-The type checker is responsible for:
-
-1. Determining the type of each expression
-2. Resolving methods and traits
-3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
-   Well, dear reader, read on)
-
-The main entry point is `check_crate()`.  Type checking operates in two major
-phases: collect and check.  The collect phase passes over all items and
-determines their type, without examining their "innards".  The check phase
-then checks function bodies and so forth.
-
-Within the check phase, we check each function body one at a time (bodies of
-function expressions are checked as part of the containing function).
-Inference is used to supply types wherever they are unknown. The actual
-checking of a function itself has several phases (check, regionck, writeback),
-as discussed in the documentation for the `check` module.
-
-The type checker is defined into various submodules which are documented
-independently:
-
-- astconv: converts the AST representation of types
-  into the `ty` representation
-
-- collect: computes the types of each top-level item and enters them into
-  the `cx.tcache` table for later use
-
-- check: walks over function bodies and type checks them, inferring types for
-  local variables, type parameters, etc as necessary.
-
-- infer: finds the types to use for each type variable such that
-  all subtyping and assignment constraints are met.  In essence, the check
-  module specifies the constraints, and the infer module solves them.
-
-*/
-
-use result::Result;
-use syntax::{ast, ast_util, ast_map};
-use ast::spanned;
-use ast::{required, provided};
-use syntax::ast_map::node_id_to_str;
-use syntax::ast_util::{local_def, respan, split_trait_methods};
-use syntax::visit;
-use metadata::csearch;
-use util::common::{block_query, loop_query};
-use syntax::codemap::span;
-use pat_util::{pat_id_map, PatIdMap};
-use middle::ty;
-use middle::ty::{arg, field, node_type_table, mk_nil, ty_param_bounds_and_ty};
-use middle::ty::{ty_param_substs_and_ty, vstore_uniq};
-use std::smallintmap;
-use std::map;
-use std::map::HashMap;
-use syntax::print::pprust::*;
-use util::ppaux::{ty_to_str, tys_to_str, region_to_str,
-                  bound_region_to_str, vstore_to_str, expr_repr};
-use util::common::{indent, indenter};
-use std::list;
-use list::{List, Nil, Cons};
-use dvec::DVec;
-
-export check;
-export check_crate;
-export infer;
-export method_map;
-export method_origin;
-export method_map_entry;
-export vtable_map;
-export vtable_res;
-export vtable_origin;
-export method_static, method_param, method_trait, method_self;
-export vtable_static, vtable_param, vtable_trait;
-export provided_methods_map;
-
-#[auto_serialize]
-#[auto_deserialize]
-enum method_origin {
-    // fully statically resolved method
-    method_static(ast::def_id),
-
-    // method invoked on a type parameter with a bounded trait
-    method_param(method_param),
-
-    // method invoked on a trait instance
-    method_trait(ast::def_id, uint, ty::vstore),
-
-    // method invoked on "self" inside a default method
-    method_self(ast::def_id, uint),
-}
-
-// details for a method invoked with a receiver whose type is a type parameter
-// with a bounded trait.
-#[auto_serialize]
-#[auto_deserialize]
-type method_param = {
-    // the trait containing the method to be invoked
-    trait_id: ast::def_id,
-
-    // index of the method to be invoked amongst the trait's methods
-    method_num: uint,
-
-    // index of the type parameter (from those that are in scope) that is
-    // the type of the receiver
-    param_num: uint,
-
-    // index of the bound for this type parameter which specifies the trait
-    bound_num: uint
-};
-
-type method_map_entry = {
-    // the type and mode of the self parameter, which is not reflected
-    // in the fn type (FIXME #3446)
-    self_arg: ty::arg,
-
-    // method details being invoked
-    origin: method_origin
-};
-
-// maps from an expression id that corresponds to a method call to the details
-// of the method to be invoked
-type method_map = HashMap<ast::node_id, method_map_entry>;
-
-// Resolutions for bounds of all parameters, left to right, for a given path.
-type vtable_res = @~[vtable_origin];
-
-enum vtable_origin {
-    /*
-      Statically known vtable. def_id gives the class or impl item
-      from whence comes the vtable, and tys are the type substs.
-      vtable_res is the vtable itself
-     */
-    vtable_static(ast::def_id, ~[ty::t], vtable_res),
-    /*
-      Dynamic vtable, comes from a parameter that has a bound on it:
-      fn foo<T: quux, baz, bar>(a: T) -- a's vtable would have a
-      vtable_param origin
-
-      The first uint is the param number (identifying T in the example),
-      and the second is the bound number (identifying baz)
-     */
-    vtable_param(uint, uint),
-    /*
-      Dynamic vtable, comes from something known to have a trait
-      type. def_id refers to the trait item, tys are the substs
-     */
-    vtable_trait(ast::def_id, ~[ty::t]),
-}
-
-impl vtable_origin {
-    fn to_str(tcx: ty::ctxt) -> ~str {
-        match self {
-            vtable_static(def_id, ref tys, ref vtable_res) => {
-                fmt!("vtable_static(%?:%s, %?, %?)",
-                     def_id, ty::item_path_str(tcx, def_id),
-                     tys,
-                     vtable_res.map(|o| o.to_str(tcx)))
-            }
-
-            vtable_param(x, y) => {
-                fmt!("vtable_param(%?, %?)", x, y)
-            }
-
-            vtable_trait(def_id, ref tys) => {
-                fmt!("vtable_trait(%?:%s, %?)",
-                     def_id, ty::item_path_str(tcx, def_id),
-                     tys.map(|t| ty_to_str(tcx, *t)))
-            }
-        }
-    }
-}
-
-type vtable_map = HashMap<ast::node_id, vtable_res>;
-
-type crate_ctxt_ = {// A mapping from method call sites to traits that have
-                    // that method.
-                    trait_map: resolve::TraitMap,
-                    method_map: method_map,
-                    vtable_map: vtable_map,
-                    coherence_info: @coherence::CoherenceInfo,
-                    tcx: ty::ctxt};
-
-enum crate_ctxt {
-    crate_ctxt_(crate_ctxt_)
-}
-
-// Functions that write types into the node type table
-fn write_ty_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t) {
-    debug!("write_ty_to_tcx(%d, %s)", node_id, ty_to_str(tcx, ty));
-    smallintmap::insert(*tcx.node_types, node_id as uint, ty);
-}
-fn write_substs_to_tcx(tcx: ty::ctxt,
-                       node_id: ast::node_id,
-                       +substs: ~[ty::t]) {
-    if substs.len() > 0u {
-        debug!("write_substs_to_tcx(%d, %?)", node_id,
-               substs.map(|t| ty_to_str(tcx, *t)));
-        tcx.node_type_substs.insert(node_id, substs);
-    }
-}
-
-fn lookup_def_tcx(tcx: ty::ctxt, sp: span, id: ast::node_id) -> ast::def {
-    match tcx.def_map.find(id) {
-      Some(x) => x,
-      _ => {
-        tcx.sess.span_fatal(sp, ~"internal error looking up a definition")
-      }
-    }
-}
-
-fn lookup_def_ccx(ccx: @crate_ctxt, sp: span, id: ast::node_id) -> ast::def {
-    lookup_def_tcx(ccx.tcx, sp, id)
-}
-
-fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty {
-    {bounds: @~[], region_param: None, ty: t}
-}
-
-fn require_same_types(
-    tcx: ty::ctxt,
-    maybe_infcx: Option<infer::infer_ctxt>,
-    t1_is_expected: bool,
-    span: span,
-    t1: ty::t,
-    t2: ty::t,
-    msg: fn() -> ~str) -> bool {
-
-    let l_tcx, l_infcx;
-    match maybe_infcx {
-      None => {
-        l_tcx = tcx;
-        l_infcx = infer::new_infer_ctxt(tcx);
-      }
-      Some(i) => {
-        l_tcx = i.tcx;
-        l_infcx = i;
-      }
-    }
-
-    match infer::mk_eqty(l_infcx, t1_is_expected, span, t1, t2) {
-        result::Ok(()) => true,
-        result::Err(ref terr) => {
-            l_tcx.sess.span_err(span, msg() + ~": " +
-                                ty::type_err_to_str(l_tcx, terr));
-            ty::note_and_explain_type_err(l_tcx, terr);
-            false
-        }
-    }
-}
-
-// a list of mapping from in-scope-region-names ("isr") to the
-// corresponding ty::Region
-type isr_alist = @List<(ty::bound_region, ty::Region)>;
-
-trait get_and_find_region {
-    fn get(br: ty::bound_region) -> ty::Region;
-    fn find(br: ty::bound_region) -> Option<ty::Region>;
-}
-
-impl isr_alist: get_and_find_region {
-    fn get(br: ty::bound_region) -> ty::Region {
-        self.find(br).get()
-    }
-
-    fn find(br: ty::bound_region) -> Option<ty::Region> {
-        for list::each(self) |isr| {
-            let (isr_br, isr_r) = *isr;
-            if isr_br == br { return Some(isr_r); }
-        }
-        return None;
-    }
-}
-
-fn arg_is_argv_ty(tcx: ty::ctxt, a: ty::arg) -> bool {
-    match ty::resolved_mode(tcx, a.mode) {
-        ast::by_val => { /*ok*/ }
-        _ => {
-            return false;
-        }
-    }
-
-    match ty::get(a.ty).sty {
-      ty::ty_evec(mt, vstore_uniq) => {
-        if mt.mutbl != ast::m_imm { return false; }
-        match ty::get(mt.ty).sty {
-          ty::ty_estr(vstore_uniq) => return true,
-          _ => return false
-        }
-      }
-      _ => return false
-    }
-}
-
-fn check_main_fn_ty(ccx: @crate_ctxt,
-                    main_id: ast::node_id,
-                    main_span: span) {
-
-    let tcx = ccx.tcx;
-    let main_t = ty::node_id_to_type(tcx, main_id);
-    match ty::get(main_t).sty {
-        ty::ty_fn(fn_ty) => {
-            match tcx.items.find(main_id) {
-                Some(ast_map::node_item(it,_)) => {
-                    match it.node {
-                        ast::item_fn(_,_,ps,_) if vec::is_not_empty(ps) => {
-                            tcx.sess.span_err(
-                                main_span,
-                                ~"main function is not allowed \
-                                  to have type parameters");
-                            return;
-                        }
-                        _ => ()
-                    }
-                }
-                _ => ()
-            }
-            let mut ok = ty::type_is_nil(fn_ty.sig.output);
-            let num_args = vec::len(fn_ty.sig.inputs);
-            ok &= num_args == 0u;
-            if !ok {
-                tcx.sess.span_err(
-                    main_span,
-                    fmt!("Wrong type in main function: found `%s`, \
-                          expected `fn() -> ()`",
-                         ty_to_str(tcx, main_t)));
-            }
-        }
-        _ => {
-            tcx.sess.span_bug(main_span,
-                              ~"main has a non-function type: found `" +
-                              ty_to_str(tcx, main_t) + ~"`");
-        }
-    }
-}
-
-fn check_for_main_fn(ccx: @crate_ctxt) {
-    let tcx = ccx.tcx;
-    if !tcx.sess.building_library {
-        match copy tcx.sess.main_fn {
-          Some((id, sp)) => check_main_fn_ty(ccx, id, sp),
-          None => tcx.sess.err(~"main function not found")
-        }
-    }
-}
-
-fn check_crate(tcx: ty::ctxt,
-               trait_map: resolve::TraitMap,
-               crate: @ast::crate)
-            -> (method_map, vtable_map) {
-
-    let ccx = @crate_ctxt_({trait_map: trait_map,
-                            method_map: std::map::HashMap(),
-                            vtable_map: std::map::HashMap(),
-                            coherence_info: @coherence::CoherenceInfo(),
-                            tcx: tcx});
-    collect::collect_item_types(ccx, crate);
-    coherence::check_coherence(ccx, crate);
-    deriving::check_deriving(ccx, crate);
-
-    check::check_item_types(ccx, crate);
-    check_for_main_fn(ccx);
-    tcx.sess.abort_if_errors();
-    (ccx.method_map, ccx.vtable_map)
-}
-//
-// Local Variables:
-// mode: rust
-// fill-column: 78;
-// indent-tabs-mode: nil
-// c-basic-offset: 4
-// buffer-file-coding-system: utf-8-unix
-// End:
-//
diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs
index 11077081d91..6241cac2f5d 100644
--- a/src/librustc/middle/typeck/mod.rs
+++ b/src/librustc/middle/typeck/mod.rs
@@ -1,5 +1,83 @@
+/*
+
+typeck.rs, an introduction
+
+The type checker is responsible for:
+
+1. Determining the type of each expression
+2. Resolving methods and traits
+3. Guaranteeing that most type rules are met ("most?", you say, "why most?"
+   Well, dear reader, read on)
+
+The main entry point is `check_crate()`.  Type checking operates in two major
+phases: collect and check.  The collect phase passes over all items and
+determines their type, without examining their "innards".  The check phase
+then checks function bodies and so forth.
+
+Within the check phase, we check each function body one at a time (bodies of
+function expressions are checked as part of the containing function).
+Inference is used to supply types wherever they are unknown. The actual
+checking of a function itself has several phases (check, regionck, writeback),
+as discussed in the documentation for the `check` module.
+
+The type checker is defined into various submodules which are documented
+independently:
+
+- astconv: converts the AST representation of types
+  into the `ty` representation
+
+- collect: computes the types of each top-level item and enters them into
+  the `cx.tcache` table for later use
+
+- check: walks over function bodies and type checks them, inferring types for
+  local variables, type parameters, etc as necessary.
+
+- infer: finds the types to use for each type variable such that
+  all subtyping and assignment constraints are met.  In essence, the check
+  module specifies the constraints, and the infer module solves them.
+
+*/
+
 #[legacy_exports];
 
+use result::Result;
+use syntax::{ast, ast_util, ast_map};
+use ast::spanned;
+use ast::{required, provided};
+use syntax::ast_map::node_id_to_str;
+use syntax::ast_util::{local_def, respan, split_trait_methods};
+use syntax::visit;
+use metadata::csearch;
+use util::common::{block_query, loop_query};
+use syntax::codemap::span;
+use pat_util::{pat_id_map, PatIdMap};
+use middle::ty;
+use middle::ty::{arg, field, node_type_table, mk_nil, ty_param_bounds_and_ty};
+use middle::ty::{ty_param_substs_and_ty, vstore_uniq};
+use std::smallintmap;
+use std::map;
+use std::map::HashMap;
+use syntax::print::pprust::*;
+use util::ppaux::{ty_to_str, tys_to_str, region_to_str,
+                  bound_region_to_str, vstore_to_str, expr_repr};
+use util::common::{indent, indenter};
+use std::list;
+use list::{List, Nil, Cons};
+use dvec::DVec;
+
+export check;
+export check_crate;
+export infer;
+export method_map;
+export method_origin;
+export method_map_entry;
+export vtable_map;
+export vtable_res;
+export vtable_origin;
+export method_static, method_param, method_trait, method_self;
+export vtable_static, vtable_param, vtable_trait;
+export provided_methods_map;
+
 #[legacy_exports]
 #[merge = "check/mod.rs"]
 pub mod check;
@@ -14,3 +92,302 @@ mod collect;
 #[legacy_exports]
 mod coherence;
 mod deriving;
+
+#[auto_serialize]
+#[auto_deserialize]
+enum method_origin {
+    // fully statically resolved method
+    method_static(ast::def_id),
+
+    // method invoked on a type parameter with a bounded trait
+    method_param(method_param),
+
+    // method invoked on a trait instance
+    method_trait(ast::def_id, uint, ty::vstore),
+
+    // method invoked on "self" inside a default method
+    method_self(ast::def_id, uint),
+}
+
+// details for a method invoked with a receiver whose type is a type parameter
+// with a bounded trait.
+#[auto_serialize]
+#[auto_deserialize]
+type method_param = {
+    // the trait containing the method to be invoked
+    trait_id: ast::def_id,
+
+    // index of the method to be invoked amongst the trait's methods
+    method_num: uint,
+
+    // index of the type parameter (from those that are in scope) that is
+    // the type of the receiver
+    param_num: uint,
+
+    // index of the bound for this type parameter which specifies the trait
+    bound_num: uint
+};
+
+type method_map_entry = {
+    // the type and mode of the self parameter, which is not reflected
+    // in the fn type (FIXME #3446)
+    self_arg: ty::arg,
+
+    // method details being invoked
+    origin: method_origin
+};
+
+// maps from an expression id that corresponds to a method call to the details
+// of the method to be invoked
+type method_map = HashMap<ast::node_id, method_map_entry>;
+
+// Resolutions for bounds of all parameters, left to right, for a given path.
+type vtable_res = @~[vtable_origin];
+
+enum vtable_origin {
+    /*
+      Statically known vtable. def_id gives the class or impl item
+      from whence comes the vtable, and tys are the type substs.
+      vtable_res is the vtable itself
+     */
+    vtable_static(ast::def_id, ~[ty::t], vtable_res),
+    /*
+      Dynamic vtable, comes from a parameter that has a bound on it:
+      fn foo<T: quux, baz, bar>(a: T) -- a's vtable would have a
+      vtable_param origin
+
+      The first uint is the param number (identifying T in the example),
+      and the second is the bound number (identifying baz)
+     */
+    vtable_param(uint, uint),
+    /*
+      Dynamic vtable, comes from something known to have a trait
+      type. def_id refers to the trait item, tys are the substs
+     */
+    vtable_trait(ast::def_id, ~[ty::t]),
+}
+
+impl vtable_origin {
+    fn to_str(tcx: ty::ctxt) -> ~str {
+        match self {
+            vtable_static(def_id, ref tys, ref vtable_res) => {
+                fmt!("vtable_static(%?:%s, %?, %?)",
+                     def_id, ty::item_path_str(tcx, def_id),
+                     tys,
+                     vtable_res.map(|o| o.to_str(tcx)))
+            }
+
+            vtable_param(x, y) => {
+                fmt!("vtable_param(%?, %?)", x, y)
+            }
+
+            vtable_trait(def_id, ref tys) => {
+                fmt!("vtable_trait(%?:%s, %?)",
+                     def_id, ty::item_path_str(tcx, def_id),
+                     tys.map(|t| ty_to_str(tcx, *t)))
+            }
+        }
+    }
+}
+
+type vtable_map = HashMap<ast::node_id, vtable_res>;
+
+type crate_ctxt_ = {// A mapping from method call sites to traits that have
+                    // that method.
+                    trait_map: resolve::TraitMap,
+                    method_map: method_map,
+                    vtable_map: vtable_map,
+                    coherence_info: @coherence::CoherenceInfo,
+                    tcx: ty::ctxt};
+
+enum crate_ctxt {
+    crate_ctxt_(crate_ctxt_)
+}
+
+// Functions that write types into the node type table
+fn write_ty_to_tcx(tcx: ty::ctxt, node_id: ast::node_id, ty: ty::t) {
+    debug!("write_ty_to_tcx(%d, %s)", node_id, ty_to_str(tcx, ty));
+    smallintmap::insert(*tcx.node_types, node_id as uint, ty);
+}
+fn write_substs_to_tcx(tcx: ty::ctxt,
+                       node_id: ast::node_id,
+                       +substs: ~[ty::t]) {
+    if substs.len() > 0u {
+        debug!("write_substs_to_tcx(%d, %?)", node_id,
+               substs.map(|t| ty_to_str(tcx, *t)));
+        tcx.node_type_substs.insert(node_id, substs);
+    }
+}
+
+fn lookup_def_tcx(tcx: ty::ctxt, sp: span, id: ast::node_id) -> ast::def {
+    match tcx.def_map.find(id) {
+      Some(x) => x,
+      _ => {
+        tcx.sess.span_fatal(sp, ~"internal error looking up a definition")
+      }
+    }
+}
+
+fn lookup_def_ccx(ccx: @crate_ctxt, sp: span, id: ast::node_id) -> ast::def {
+    lookup_def_tcx(ccx.tcx, sp, id)
+}
+
+fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty {
+    {bounds: @~[], region_param: None, ty: t}
+}
+
+fn require_same_types(
+    tcx: ty::ctxt,
+    maybe_infcx: Option<infer::infer_ctxt>,
+    t1_is_expected: bool,
+    span: span,
+    t1: ty::t,
+    t2: ty::t,
+    msg: fn() -> ~str) -> bool {
+
+    let l_tcx, l_infcx;
+    match maybe_infcx {
+      None => {
+        l_tcx = tcx;
+        l_infcx = infer::new_infer_ctxt(tcx);
+      }
+      Some(i) => {
+        l_tcx = i.tcx;
+        l_infcx = i;
+      }
+    }
+
+    match infer::mk_eqty(l_infcx, t1_is_expected, span, t1, t2) {
+        result::Ok(()) => true,
+        result::Err(ref terr) => {
+            l_tcx.sess.span_err(span, msg() + ~": " +
+                                ty::type_err_to_str(l_tcx, terr));
+            ty::note_and_explain_type_err(l_tcx, terr);
+            false
+        }
+    }
+}
+
+// a list of mapping from in-scope-region-names ("isr") to the
+// corresponding ty::Region
+type isr_alist = @List<(ty::bound_region, ty::Region)>;
+
+trait get_and_find_region {
+    fn get(br: ty::bound_region) -> ty::Region;
+    fn find(br: ty::bound_region) -> Option<ty::Region>;
+}
+
+impl isr_alist: get_and_find_region {
+    fn get(br: ty::bound_region) -> ty::Region {
+        self.find(br).get()
+    }
+
+    fn find(br: ty::bound_region) -> Option<ty::Region> {
+        for list::each(self) |isr| {
+            let (isr_br, isr_r) = *isr;
+            if isr_br == br { return Some(isr_r); }
+        }
+        return None;
+    }
+}
+
+fn arg_is_argv_ty(tcx: ty::ctxt, a: ty::arg) -> bool {
+    match ty::resolved_mode(tcx, a.mode) {
+        ast::by_val => { /*ok*/ }
+        _ => {
+            return false;
+        }
+    }
+
+    match ty::get(a.ty).sty {
+      ty::ty_evec(mt, vstore_uniq) => {
+        if mt.mutbl != ast::m_imm { return false; }
+        match ty::get(mt.ty).sty {
+          ty::ty_estr(vstore_uniq) => return true,
+          _ => return false
+        }
+      }
+      _ => return false
+    }
+}
+
+fn check_main_fn_ty(ccx: @crate_ctxt,
+                    main_id: ast::node_id,
+                    main_span: span) {
+
+    let tcx = ccx.tcx;
+    let main_t = ty::node_id_to_type(tcx, main_id);
+    match ty::get(main_t).sty {
+        ty::ty_fn(fn_ty) => {
+            match tcx.items.find(main_id) {
+                Some(ast_map::node_item(it,_)) => {
+                    match it.node {
+                        ast::item_fn(_,_,ps,_) if vec::is_not_empty(ps) => {
+                            tcx.sess.span_err(
+                                main_span,
+                                ~"main function is not allowed \
+                                  to have type parameters");
+                            return;
+                        }
+                        _ => ()
+                    }
+                }
+                _ => ()
+            }
+            let mut ok = ty::type_is_nil(fn_ty.sig.output);
+            let num_args = vec::len(fn_ty.sig.inputs);
+            ok &= num_args == 0u;
+            if !ok {
+                tcx.sess.span_err(
+                    main_span,
+                    fmt!("Wrong type in main function: found `%s`, \
+                          expected `fn() -> ()`",
+                         ty_to_str(tcx, main_t)));
+            }
+        }
+        _ => {
+            tcx.sess.span_bug(main_span,
+                              ~"main has a non-function type: found `" +
+                              ty_to_str(tcx, main_t) + ~"`");
+        }
+    }
+}
+
+fn check_for_main_fn(ccx: @crate_ctxt) {
+    let tcx = ccx.tcx;
+    if !tcx.sess.building_library {
+        match copy tcx.sess.main_fn {
+          Some((id, sp)) => check_main_fn_ty(ccx, id, sp),
+          None => tcx.sess.err(~"main function not found")
+        }
+    }
+}
+
+fn check_crate(tcx: ty::ctxt,
+               trait_map: resolve::TraitMap,
+               crate: @ast::crate)
+            -> (method_map, vtable_map) {
+
+    let ccx = @crate_ctxt_({trait_map: trait_map,
+                            method_map: std::map::HashMap(),
+                            vtable_map: std::map::HashMap(),
+                            coherence_info: @coherence::CoherenceInfo(),
+                            tcx: tcx});
+    collect::collect_item_types(ccx, crate);
+    coherence::check_coherence(ccx, crate);
+    deriving::check_deriving(ccx, crate);
+
+    check::check_item_types(ccx, crate);
+    check_for_main_fn(ccx);
+    tcx.sess.abort_if_errors();
+    (ccx.method_map, ccx.vtable_map)
+}
+//
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
+//
diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc
index 80592fea500..14af4bc443e 100644
--- a/src/librustc/rustc.rc
+++ b/src/librustc/rustc.rc
@@ -122,8 +122,7 @@ mod middle {
     #[legacy_exports]
     #[path = "middle/resolve.rs"]
     mod resolve;
-    #[path = "middle/typeck.rs"]
-    #[merge = "middle/typeck/mod.rs"]
+    #[path = "middle/typeck/mod.rs"]
     pub mod typeck;
     #[legacy_exports]
     #[path = "middle/check_loop.rs"]
@@ -137,8 +136,7 @@ mod middle {
     #[legacy_exports]
     #[path = "middle/lint.rs"]
     mod lint;
-    #[path = "middle/borrowck.rs"]
-    #[merge = "middle/borrowck/mod.rs"]
+    #[path = "middle/borrowck/mod.rs"]
     mod borrowck;
     #[legacy_exports]
     #[path = "middle/mem_categorization.rs"]
@@ -216,10 +214,10 @@ mod back {
     mod target_strs;
 }
 
-#[merge = "metadata/mod.rs"]
+#[path = "metadata/mod.rs"]
 mod metadata;
 
-#[merge = "driver/mod.rs"]
+#[path = "driver/mod.rs"]
 mod driver;
 
 mod util {