]> git.lizzy.rs Git - rust.git/commitdiff
Switch the code to use De Bruijn indices rather than binder-ids.
authorNiko Matsakis <niko@alum.mit.edu>
Sat, 15 Nov 2014 21:47:59 +0000 (16:47 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Tue, 18 Nov 2014 17:27:35 +0000 (12:27 -0500)
22 files changed:
src/librustc/metadata/tydecode.rs
src/librustc/metadata/tyencode.rs
src/librustc/middle/astencode.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/middle/subst.rs
src/librustc/middle/ty.rs
src/librustc/middle/ty_fold.rs
src/librustc/middle/typeck/astconv.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/check/regionmanip.rs
src/librustc/middle/typeck/check/wf.rs
src/librustc/middle/typeck/collect.rs
src/librustc/middle/typeck/infer/combine.rs
src/librustc/middle/typeck/infer/glb.rs
src/librustc/middle/typeck/infer/mod.rs
src/librustc/middle/typeck/infer/region_inference/mod.rs
src/librustc/middle/typeck/mod.rs
src/librustc/middle/typeck/rscope.rs
src/librustc/util/ppaux.rs
src/librustc_trans/test.rs
src/librustc_trans/trans/callee.rs
src/librustc_trans/trans/meth.rs

index e1b0797e9825375c7eea4c9090b2f6fe04c845d1..69be2e34915265666f65db69851240ddf570b53d 100644 (file)
@@ -294,7 +294,7 @@ fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region {
     match next(st) {
       'b' => {
         assert_eq!(next(st), '[');
-        let id = parse_uint(st) as ast::NodeId;
+        let id = ty::DebruijnIndex::new(parse_uint(st));
         assert_eq!(next(st), '|');
         let br = parse_bound_region(st, |x,y| conv(x,y));
         assert_eq!(next(st), ']');
@@ -579,8 +579,6 @@ fn parse_bare_fn_ty(st: &mut PState, conv: conv_did) -> ty::BareFnTy {
 
 fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig {
     assert_eq!(next(st), '[');
-    let id = parse_uint(st) as ast::NodeId;
-    assert_eq!(next(st), '|');
     let mut inputs = Vec::new();
     while peek(st) != ']' {
         inputs.push(parse_ty(st, |x,y| conv(x,y)));
@@ -598,8 +596,7 @@ fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig {
         }
         _ => ty::FnConverging(parse_ty(st, |x,y| conv(x,y)))
     };
-    ty::FnSig {binder_id: id,
-               inputs: inputs,
+    ty::FnSig {inputs: inputs,
                output: output,
                variadic: variadic}
 }
index 3242d3961467a153efd2fd0ad223a6dffe8c224d..a53f5fa187df28b74fc7141533817eca439b5f24 100644 (file)
@@ -130,7 +130,7 @@ fn enc_region_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::Regio
 pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
     match r {
         ty::ReLateBound(id, br) => {
-            mywrite!(w, "b[{}|", id);
+            mywrite!(w, "b[{}|", id.depth);
             enc_bound_region(w, cx, br);
             mywrite!(w, "]");
         }
@@ -331,7 +331,7 @@ pub fn enc_closure_ty(w: &mut SeekableMemWriter, cx: &ctxt, ft: &ty::ClosureTy)
 }
 
 fn enc_fn_sig(w: &mut SeekableMemWriter, cx: &ctxt, fsig: &ty::FnSig) {
-    mywrite!(w, "[{}|", fsig.binder_id);
+    mywrite!(w, "[");
     for ty in fsig.inputs.iter() {
         enc_ty(w, cx, *ty);
     }
index 20dcf094b66209a1d84d5d26af43a88fadc7b426..ff6965574be922cf528048edd135b9c4a64518cf 100644 (file)
@@ -483,8 +483,8 @@ fn tr(&self, dcx: &DecodeContext) -> def::Def {
 impl tr for ty::Region {
     fn tr(&self, dcx: &DecodeContext) -> ty::Region {
         match *self {
-            ty::ReLateBound(id, br) => {
-                ty::ReLateBound(dcx.tr_id(id), br.tr(dcx))
+            ty::ReLateBound(debruijn, br) => {
+                ty::ReLateBound(debruijn, br.tr(dcx))
             }
             ty::ReEarlyBound(id, space, index, ident) => {
                 ty::ReEarlyBound(dcx.tr_id(id), space, index, ident)
index 4077629f76dad12bf602beea584f2f7c32e35962..7b2ff6d4b7db42b8817e621a57411874f33bbf89 100644 (file)
@@ -39,8 +39,7 @@ pub enum DefRegion {
     DefEarlyBoundRegion(/* space */ subst::ParamSpace,
                         /* index */ uint,
                         /* lifetime decl */ ast::NodeId),
-    DefLateBoundRegion(/* binder_id */ ast::NodeId,
-                       /* depth */ uint,
+    DefLateBoundRegion(ty::DebruijnIndex,
                        /* lifetime decl */ ast::NodeId),
     DefFreeRegion(/* block scope */ ast::NodeId,
                   /* lifetime decl */ ast::NodeId),
@@ -60,9 +59,9 @@ enum ScopeChain<'a> {
     /// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound
     /// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc.
     EarlyScope(subst::ParamSpace, &'a Vec<ast::LifetimeDef>, Scope<'a>),
-    /// LateScope(binder_id, ['a, 'b, ...], s) extends s with late-bound
+    /// LateScope(['a, 'b, ...], s) extends s with late-bound
     /// lifetimes introduced by the declaration binder_id.
-    LateScope(ast::NodeId, &'a Vec<ast::LifetimeDef>, Scope<'a>),
+    LateScope(&'a Vec<ast::LifetimeDef>, Scope<'a>),
     /// lifetimes introduced by items within a code block are scoped
     /// to that block.
     BlockScope(ast::NodeId, Scope<'a>),
@@ -115,12 +114,12 @@ fn visit_item(&mut self, item: &ast::Item) {
     }
 
     fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
-                b: &'v ast::Block, s: Span, n: ast::NodeId) {
+                b: &'v ast::Block, s: Span, _: ast::NodeId) {
         match fk {
             visit::FkItemFn(_, generics, _, _) |
             visit::FkMethod(_, generics, _) => {
                 self.visit_early_late(
-                    subst::FnSpace, n, generics,
+                    subst::FnSpace, generics,
                     |this| visit::walk_fn(this, fk, fd, b, s))
             }
             visit::FkFnBlock(..) => {
@@ -130,21 +129,37 @@ fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl,
     }
 
     fn visit_ty(&mut self, ty: &ast::Ty) {
-        let lifetimes = match ty.node {
-            ast::TyClosure(ref c) | ast::TyProc(ref c) => &c.lifetimes,
-            ast::TyBareFn(ref c) => &c.lifetimes,
-            _ => return visit::walk_ty(self, ty)
-        };
-
-        self.with(LateScope(ty.id, lifetimes, self.scope), |this| {
-            this.check_lifetime_defs(lifetimes);
-            visit::walk_ty(this, ty);
-        });
+        match ty.node {
+            ast::TyClosure(ref c) | ast::TyProc(ref c) => {
+                // Careful, the bounds on a closure/proc are *not* within its binder.
+                visit::walk_ty_param_bounds_helper(self, &c.bounds);
+                visit::walk_lifetime_decls_helper(self, &c.lifetimes);
+                self.with(LateScope(&c.lifetimes, self.scope), |this| {
+                    this.check_lifetime_defs(&c.lifetimes);
+                    for argument in c.decl.inputs.iter() {
+                        this.visit_ty(&*argument.ty)
+                    }
+                    visit::walk_fn_ret_ty(this, &c.decl.output);
+                });
+            }
+            ast::TyBareFn(ref c) => {
+                visit::walk_lifetime_decls_helper(self, &c.lifetimes);
+                self.with(LateScope(&c.lifetimes, self.scope), |this| {
+                    // a bare fn has no bounds, so everything
+                    // contained within is scoped within its binder.
+                    this.check_lifetime_defs(&c.lifetimes);
+                    visit::walk_ty(this, ty);
+                });
+            }
+            _ => {
+                visit::walk_ty(self, ty)
+            }
+        }
     }
 
     fn visit_ty_method(&mut self, m: &ast::TypeMethod) {
         self.visit_early_late(
-            subst::FnSpace, m.id, &m.generics,
+            subst::FnSpace, &m.generics,
             |this| visit::walk_ty_method(this, m))
     }
 
@@ -216,11 +231,25 @@ fn visit_poly_trait_ref(&mut self, trait_ref: &ast::PolyTraitRef) {
     fn visit_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
         self.visit_path(&trait_ref.path, trait_ref.ref_id);
     }
+}
+
+impl<'a> LifetimeContext<'a> {
+    fn with(&mut self, wrap_scope: ScopeChain, f: |&mut LifetimeContext|) {
+        let LifetimeContext {sess, ref mut named_region_map, ..} = *self;
+        let mut this = LifetimeContext {
+            sess: sess,
+            named_region_map: *named_region_map,
+            scope: &wrap_scope,
+            def_map: self.def_map,
+        };
+        debug!("entering scope {}", this.scope);
+        f(&mut this);
+        debug!("exiting scope {}", this.scope);
+    }
 
     /// Visits self by adding a scope and handling recursive walk over the contents with `walk`.
     fn visit_early_late(&mut self,
                         early_space: subst::ParamSpace,
-                        binder_id: ast::NodeId,
                         generics: &ast::Generics,
                         walk: |&mut LifetimeContext|) {
         /*!
@@ -249,15 +278,14 @@ fn visit_early_late(&mut self,
 
         let referenced_idents = early_bound_lifetime_names(generics);
 
-        debug!("visit_early_late: binder_id={} referenced_idents={}",
-               binder_id,
+        debug!("visit_early_late: referenced_idents={}",
                referenced_idents);
 
         let (early, late) = generics.lifetimes.clone().partition(
             |l| referenced_idents.iter().any(|&i| i == l.lifetime.name));
 
         self.with(EarlyScope(early_space, &early, self.scope), |this| {
-            this.with(LateScope(binder_id, &late, this.scope), |this| {
+            this.with(LateScope(&late, this.scope), |this| {
                 this.check_lifetime_defs(&generics.lifetimes);
                 walk(this);
             });
@@ -271,7 +299,7 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
         // block, then the lifetime is not bound but free, so switch
         // over to `resolve_free_lifetime_ref()` to complete the
         // search.
-        let mut depth = 0;
+        let mut late_depth = 0;
         let mut scope = self.scope;
         loop {
             match *scope {
@@ -291,22 +319,22 @@ fn resolve_lifetime_ref(&mut self, lifetime_ref: &ast::Lifetime) {
                             return;
                         }
                         None => {
-                            depth += 1;
                             scope = s;
                         }
                     }
                 }
 
-                LateScope(binder_id, lifetimes, s) => {
+                LateScope(lifetimes, s) => {
                     match search_lifetimes(lifetimes, lifetime_ref) {
                         Some((_index, decl_id)) => {
-                            let def = DefLateBoundRegion(binder_id, depth, decl_id);
+                            let debruijn = ty::DebruijnIndex::new(late_depth + 1);
+                            let def = DefLateBoundRegion(debruijn, decl_id);
                             self.insert_lifetime(lifetime_ref, def);
                             return;
                         }
 
                         None => {
-                            depth += 1;
+                            late_depth += 1;
                             scope = s;
                         }
                     }
@@ -339,7 +367,7 @@ fn resolve_free_lifetime_ref(&mut self,
                 }
 
                 EarlyScope(_, lifetimes, s) |
-                LateScope(_, lifetimes, s) => {
+                LateScope(lifetimes, s) => {
                     search_result = search_lifetimes(lifetimes, lifetime_ref);
                     if search_result.is_some() {
                         break;
@@ -517,7 +545,7 @@ impl<'a> fmt::Show for ScopeChain<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             EarlyScope(space, defs, _) => write!(fmt, "EarlyScope({}, {})", space, defs),
-            LateScope(id, defs, _) => write!(fmt, "LateScope({}, {})", id, defs),
+            LateScope(defs, _) => write!(fmt, "LateScope({})", defs),
             BlockScope(id, _) => write!(fmt, "BlockScope({})", id),
             RootScope => write!(fmt, "RootScope"),
         }
index 520209257f5b827064871ef85d4bf8106543b573..ae7cb8645e112ea00e541d7d68b7a6cc7bb5a83e 100644 (file)
@@ -14,8 +14,7 @@
 pub use self::RegionSubsts::*;
 
 use middle::ty;
-use middle::ty_fold;
-use middle::ty_fold::{TypeFoldable, TypeFolder};
+use middle::ty_fold::{mod, TypeFoldable, TypeFolder};
 use util::ppaux::Repr;
 
 use std::fmt;
@@ -506,11 +505,22 @@ struct SubstFolder<'a, 'tcx: 'a> {
 
     // Depth of type stack
     ty_stack_depth: uint,
+
+    // Number of region binders we have passed through while doing the substitution
+    region_binders_passed: uint,
 }
 
 impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
     fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx }
 
+    fn enter_region_binder(&mut self) {
+        self.region_binders_passed += 1;
+    }
+
+    fn exit_region_binder(&mut self) {
+        self.region_binders_passed -= 1;
+    }
+
     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
         // Note: This routine only handles regions that are bound on
         // type declarations and other outer declarations, not those
@@ -524,7 +534,9 @@ fn fold_region(&mut self, r: ty::Region) -> ty::Region {
                     ErasedRegions => ty::ReStatic,
                     NonerasedRegions(ref regions) =>
                         match regions.opt_get(space, i) {
-                            Some(t) => *t,
+                            Some(&r) => {
+                                self.shift_region_through_binders(r)
+                            }
                             None => {
                                 let span = self.span.unwrap_or(DUMMY_SP);
                                 self.tcx().sess.span_bug(
@@ -557,12 +569,7 @@ fn fold_ty(&mut self, t: ty::t) -> ty::t {
 
         let t1 = match ty::get(t).sty {
             ty::ty_param(p) => {
-                check(self,
-                      p,
-                      t,
-                      self.substs.types.opt_get(p.space, p.idx),
-                      p.space,
-                      p.idx)
+                self.ty_for_param(p, t)
             }
             _ => {
                 ty_fold::super_fold_ty(self, t)
@@ -576,30 +583,100 @@ fn fold_ty(&mut self, t: ty::t) -> ty::t {
         }
 
         return t1;
+    }
+}
 
-        fn check(this: &SubstFolder,
-                 p: ty::ParamTy,
-                 source_ty: ty::t,
-                 opt_ty: Option<&ty::t>,
-                 space: ParamSpace,
-                 index: uint)
-                 -> ty::t {
-            match opt_ty {
-                Some(t) => *t,
-                None => {
-                    let span = this.span.unwrap_or(DUMMY_SP);
-                    this.tcx().sess.span_bug(
-                        span,
-                        format!("Type parameter `{}` ({}/{}/{}) out of range \
+impl<'a,'tcx> SubstFolder<'a,'tcx> {
+    fn ty_for_param(&self, p: ty::ParamTy, source_ty: ty::t) -> ty::t {
+        // Look up the type in the substitutions. It really should be in there.
+        let opt_ty = self.substs.types.opt_get(p.space, p.idx);
+        let ty = match opt_ty {
+            Some(t) => *t,
+            None => {
+                let span = self.span.unwrap_or(DUMMY_SP);
+                self.tcx().sess.span_bug(
+                    span,
+                    format!("Type parameter `{}` ({}/{}/{}) out of range \
                                  when substituting (root type={}) substs={}",
-                                p.repr(this.tcx()),
-                                source_ty.repr(this.tcx()),
-                                space,
-                                index,
-                                this.root_ty.repr(this.tcx()),
-                                this.substs.repr(this.tcx())).as_slice());
-                }
+                            p.repr(self.tcx()),
+                            source_ty.repr(self.tcx()),
+                            p.space,
+                            p.idx,
+                            self.root_ty.repr(self.tcx()),
+                            self.substs.repr(self.tcx())).as_slice());
             }
+        };
+
+        self.shift_regions_through_binders(ty)
+    }
+
+    fn shift_regions_through_binders(&self, ty: ty::t) -> ty::t {
+        /*!
+         * It is sometimes necessary to adjust the debruijn indices
+         * during substitution. This occurs when we are substituting a
+         * type with escaping regions into a context where we have
+         * passed through region binders. That's quite a
+         * mouthful. Let's see an example:
+         *
+         * ```
+         * type Func<A> = fn(A);
+         * type MetaFunc = for<'a> fn(Func<&'a int>)
+         * ```
+         *
+         * The type `MetaFunc`, when fully expanded, will be
+         *
+         *     for<'a> fn(fn(&'a int))
+         *             ^~ ^~ ^~~
+         *             |  |  |
+         *             |  |  DebruijnIndex of 2
+         *             Binders
+         *
+         * Here the `'a` lifetime is bound in the outer function, but
+         * appears as an argument of the inner one. Therefore, that
+         * appearance will have a DebruijnIndex of 2, because we must
+         * skip over the inner binder (remember that we count Debruijn
+         * indices from 1). However, in the definition of `MetaFunc`,
+         * the binder is not visible, so the type `&'a int` will have
+         * a debruijn index of 1. It's only during the substitution
+         * that we can see we must increase the depth by 1 to account
+         * for the binder that we passed through.
+         *
+         * As a second example, consider this twist:
+         *
+         * ```
+         * type FuncTuple<A> = (A,fn(A));
+         * type MetaFuncTuple = for<'a> fn(FuncTuple<&'a int>)
+         * ```
+         *
+         * Here the final type will be:
+         *
+         *     for<'a> fn((&'a int, fn(&'a int)))
+         *                 ^~~         ^~~
+         *                 |           |
+         *          DebruijnIndex of 1 |
+         *                      DebruijnIndex of 2
+         *
+         * As indicated in the diagram, here the same type `&'a int`
+         * is substituted once, but in the first case we do not
+         * increase the Debruijn index and in the second case we
+         * do. The reason is that only in the second case have we
+         * passed through a fn binder.
+         */
+
+        debug!("shift_regions(ty={}, region_binders_passed={}, type_has_escaping_regions={})",
+               ty.repr(self.tcx()), self.region_binders_passed, ty::type_has_escaping_regions(ty));
+
+        if self.region_binders_passed == 0 || !ty::type_has_escaping_regions(ty) {
+            return ty;
         }
+
+        let result = ty_fold::shift_regions(self.tcx(), self.region_binders_passed, &ty);
+        debug!("shift_regions: shifted result = {}", result.repr(self.tcx()));
+
+        result
+    }
+
+    fn shift_region_through_binders(&self, region: ty::Region) -> ty::Region {
+        ty_fold::shift_region(region, self.region_binders_passed)
     }
 }
index 5ec89ffb9e7e2a76a0437017ee10648f7c728800..a322fcb3fa118481f65ee30e50d32be3752466a7 100644 (file)
@@ -53,7 +53,7 @@
 use middle::traits;
 use middle::ty;
 use middle::typeck;
-use middle::ty_fold::{mod, TypeFoldable,TypeFolder};
+use middle::ty_fold::{mod, TypeFoldable, TypeFolder, HigherRankedFoldable};
 use middle;
 use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string};
 use util::ppaux::{trait_store_to_string, ty_to_string};
@@ -609,13 +609,14 @@ pub struct ctxt<'tcx> {
 // recursing over the type itself.
 bitflags! {
     flags TypeFlags: u32 {
-        const NO_TYPE_FLAGS = 0b0,
-        const HAS_PARAMS    = 0b1,
-        const HAS_SELF      = 0b10,
-        const HAS_TY_INFER  = 0b100,
-        const HAS_RE_INFER  = 0b1000,
-        const HAS_REGIONS   = 0b10000,
-        const HAS_TY_ERR    = 0b100000,
+        const NO_TYPE_FLAGS       = 0b0,
+        const HAS_PARAMS          = 0b1,
+        const HAS_SELF            = 0b10,
+        const HAS_TY_INFER        = 0b100,
+        const HAS_RE_INFER        = 0b1000,
+        const HAS_RE_LATE_BOUND   = 0b10000,
+        const HAS_REGIONS         = 0b100000,
+        const HAS_TY_ERR          = 0b1000000,
         const NEEDS_SUBST   = HAS_PARAMS.bits | HAS_SELF.bits | HAS_REGIONS.bits,
     }
 }
@@ -626,6 +627,9 @@ pub struct ctxt<'tcx> {
 pub struct t_box_ {
     pub sty: sty,
     pub flags: TypeFlags,
+
+    // the maximal depth of any bound regions appearing in this type.
+    region_depth: uint,
 }
 
 impl fmt::Show for TypeFlags {
@@ -670,6 +674,50 @@ pub fn type_needs_infer(t: t) -> bool {
     tbox_has_flag(get(t), HAS_TY_INFER | HAS_RE_INFER)
 }
 
+pub fn type_has_late_bound_regions(ty: t) -> bool {
+    get(ty).flags.intersects(HAS_RE_LATE_BOUND)
+}
+
+pub fn type_has_escaping_regions(t: t) -> bool {
+    /*!
+     * An "escaping region" is a bound region whose binder is not part of `t`.
+     *
+     * So, for example, consider a type like the following, which has two
+     * binders:
+     *
+     *    for<'a> fn(x: for<'b> fn(&'a int, &'b int))
+     *    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
+     *                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~  inner scope
+     *
+     * This type has *bound regions* (`'a`, `'b`), but it does not
+     * have escaping regions, because the binders of both `'a` and
+     * `'b` are part of the type itself. However, if we consider the
+     * *inner fn type*, that type has an escaping region: `'a`.
+     *
+     * Note that what I'm calling an "escaping region" is often just
+     * called a "free region". However, we already use the term "free
+     * region". It refers to the regions that we use to represent
+     * bound regions on a fn definition while we are typechecking its
+     * body.
+     *
+     * To clarify, conceptually there is no particular difference
+     * between an "escaping" region and a "free" region. However,
+     * there is a big difference in practice. Basically, when
+     * "entering" a binding level, one is generally required to do
+     * some sort of processing to a bound region, such as replacing it
+     * with a fresh/skolemized region, or making an entry in the
+     * environment to represent the scope to which it is attached,
+     * etc. An escaping region represents a bound region for which
+     * this processing has not yet been done.
+     */
+
+    type_escapes_depth(t, 0)
+}
+
+pub fn type_escapes_depth(t: t, depth: uint) -> bool {
+    get(t).region_depth > depth
+}
+
 #[deriving(Clone, PartialEq, Eq, Hash, Show)]
 pub struct BareFnTy {
     pub fn_style: ast::FnStyle,
@@ -706,17 +754,16 @@ pub fn unwrap(&self) -> ty::t {
  * Signature of a function type, which I have arbitrarily
  * decided to use to refer to the input/output types.
  *
- * - `binder_id` is the node id where this fn type appeared;
- *   it is used to identify all the bound regions appearing
- *   in the input/output types that are bound by this fn type
- *   (vs some enclosing or enclosed fn type)
  * - `inputs` is the list of arguments and their modes.
  * - `output` is the return type.
  * - `variadic` indicates whether this is a varidic function. (only true for foreign fns)
+ *
+ * Note that a `FnSig` introduces a level of region binding, to
+ * account for late-bound parameters that appear in the types of the
+ * fn's arguments or the fn's return type.
  */
 #[deriving(Clone, PartialEq, Eq, Hash)]
 pub struct FnSig {
-    pub binder_id: ast::NodeId,
     pub inputs: Vec<t>,
     pub output: FnOutput,
     pub variadic: bool
@@ -729,6 +776,54 @@ pub struct ParamTy {
     pub def_id: DefId
 }
 
+/**
+ * A [De Bruijn index][dbi] is a standard means of representing
+ * regions (and perhaps later types) in a higher-ranked setting. In
+ * particular, imagine a type like this:
+ *
+ *     for<'a> fn(for<'b> fn(&'b int, &'a int), &'a char)
+ *     ^          ^            |        |         |
+ *     |          |            |        |         |
+ *     |          +------------+ 1      |         |
+ *     |                                |         |
+ *     +--------------------------------+ 2       |
+ *     |                                          |
+ *     +------------------------------------------+ 1
+ *
+ * In this type, there are two binders (the outer fn and the inner
+ * fn). We need to be able to determine, for any given region, which
+ * fn type it is bound by, the inner or the outer one. There are
+ * various ways you can do this, but a De Bruijn index is one of the
+ * more convenient and has some nice properties. The basic idea is to
+ * count the number of binders, inside out. Some examples should help
+ * clarify what I mean.
+ *
+ * Let's start with the reference type `&'b int` that is the first
+ * argument to the inner function. This region `'b` is assigned a De
+ * Bruijn index of 1, meaning "the innermost binder" (in this case, a
+ * fn). The region `'a` that appears in the second argument type (`&'a
+ * int`) would then be assigned a De Bruijn index of 2, meaning "the
+ * second-innermost binder". (These indices are written on the arrays
+ * in the diagram).
+ *
+ * What is interesting is that De Bruijn index attached to a particular
+ * variable will vary depending on where it appears. For example,
+ * the final type `&'a char` also refers to the region `'a` declared on
+ * the outermost fn. But this time, this reference is not nested within
+ * any other binders (i.e., it is not an argument to the inner fn, but
+ * rather the outer one). Therefore, in this case, it is assigned a
+ * De Bruijn index of 1, because the innermost binder in that location
+ * is the outer fn.
+ *
+ * [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index
+ */
+#[deriving(Clone, PartialEq, Eq, Hash, Encodable, Decodable, Show)]
+pub struct DebruijnIndex {
+    // We maintain the invariant that this is never 0. So 1 indicates
+    // the innermost binder. To ensure this, create with `DebruijnIndex::new`.
+    pub depth: uint,
+}
+
 /// Representation of regions:
 #[deriving(Clone, PartialEq, Eq, Hash, Encodable, Decodable, Show)]
 pub enum Region {
@@ -741,9 +836,8 @@ pub enum Region {
                  ast::Name),
 
     // Region bound in a function scope, which will be substituted when the
-    // function is called. The first argument must be the `binder_id` of
-    // some enclosing function signature.
-    ReLateBound(/* binder_id */ ast::NodeId, BoundRegion),
+    // function is called.
+    ReLateBound(DebruijnIndex, BoundRegion),
 
     /// When checking a function body, the types of all arguments and so forth
     /// that refer to bound region parameters are modified to refer to free
@@ -885,12 +979,19 @@ pub struct UpvarBorrow {
 
 impl Region {
     pub fn is_bound(&self) -> bool {
-        match self {
-            &ty::ReEarlyBound(..) => true,
-            &ty::ReLateBound(..) => true,
+        match *self {
+            ty::ReEarlyBound(..) => true,
+            ty::ReLateBound(..) => true,
             _ => false
         }
     }
+
+    pub fn escapes_depth(&self, depth: uint) -> bool {
+        match *self {
+            ty::ReLateBound(debruijn, _) => debruijn.depth > depth,
+            _ => false,
+        }
+    }
 }
 
 #[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)]
@@ -928,6 +1029,7 @@ macro_rules! def_prim_ty(
             pub static $name: t_box_ = t_box_ {
                 sty: $sty,
                 flags: super::NO_TYPE_FLAGS,
+                region_depth: 0,
             };
         )
     )
@@ -950,6 +1052,7 @@ macro_rules! def_prim_ty(
     pub static TY_ERR: t_box_ = t_box_ {
         sty: super::ty_err,
         flags: super::HAS_TY_ERR,
+        region_depth: 0,
     };
 }
 
@@ -1008,6 +1111,23 @@ pub struct TraitRef {
     pub substs: Substs,
 }
 
+/**
+ * Binder serves as a synthetic binder for lifetimes. It is used when
+ * we wish to replace the escaping higher-ranked lifetimes in a type
+ * or something else that is not itself a binder (this is because the
+ * `replace_late_bound_regions` function replaces all lifetimes bound
+ * by the binder supplied to it; but a type is not a binder, so you
+ * must introduce an artificial one).
+ */
+#[deriving(Clone, PartialEq, Eq, Hash, Show)]
+pub struct Binder<T> {
+    pub value: T
+}
+
+pub fn bind<T>(value: T) -> Binder<T> {
+    Binder { value: value }
+}
+
 #[deriving(Clone, PartialEq)]
 pub enum IntVarValue {
     IntType(ast::IntTy),
@@ -1597,99 +1717,12 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
         _ => ()
     }
 
-    let mut flags = NO_TYPE_FLAGS;
-    fn rflags(r: Region) -> TypeFlags {
-        HAS_REGIONS | {
-            match r {
-              ty::ReInfer(_) => HAS_RE_INFER,
-              _ => NO_TYPE_FLAGS,
-            }
-        }
-    }
-    fn sflags(substs: &Substs) -> TypeFlags {
-        let mut f = NO_TYPE_FLAGS;
-        let mut i = substs.types.iter();
-        for tt in i {
-            f = f | get(*tt).flags;
-        }
-        match substs.regions {
-            subst::ErasedRegions => {}
-            subst::NonerasedRegions(ref regions) => {
-                for r in regions.iter() {
-                    f = f | rflags(*r)
-                }
-            }
-        }
-        return f;
-    }
-    fn flags_for_bounds(bounds: &ExistentialBounds) -> TypeFlags {
-        rflags(bounds.region_bound)
-    }
-    match &st {
-      &ty_bool | &ty_char | &ty_int(_) | &ty_float(_) | &ty_uint(_) |
-      &ty_str => {}
-      // You might think that we could just return ty_err for
-      // any type containing ty_err as a component, and get
-      // rid of the HAS_TY_ERR flag -- likewise for ty_bot (with
-      // the exception of function types that return bot).
-      // But doing so caused sporadic memory corruption, and
-      // neither I (tjc) nor nmatsakis could figure out why,
-      // so we're doing it this way.
-      &ty_err => flags = flags | HAS_TY_ERR,
-      &ty_param(ref p) => {
-          if p.space == subst::SelfSpace {
-              flags = flags | HAS_SELF;
-          } else {
-              flags = flags | HAS_PARAMS;
-          }
-      }
-      &ty_unboxed_closure(_, ref region, ref substs) => {
-          flags = flags | rflags(*region);
-          flags = flags | sflags(substs);
-      }
-      &ty_infer(_) => flags = flags | HAS_TY_INFER,
-      &ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
-          flags = flags | sflags(substs);
-      }
-      &ty_trait(box TyTrait { ref principal, ref bounds }) => {
-          flags = flags | sflags(&principal.substs);
-          flags = flags | flags_for_bounds(bounds);
-      }
-      &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => {
-        flags = flags | get(tt).flags
-      }
-      &ty_ptr(ref m) => {
-        flags = flags | get(m.ty).flags;
-      }
-      &ty_rptr(r, ref m) => {
-        flags = flags | rflags(r);
-        flags = flags | get(m.ty).flags;
-      }
-      &ty_tup(ref ts) => for tt in ts.iter() { flags = flags | get(*tt).flags; },
-      &ty_bare_fn(ref f) => {
-        for a in f.sig.inputs.iter() { flags = flags | get(*a).flags; }
-        if let ty::FnConverging(output) = f.sig.output {
-            flags = flags | get(output).flags;
-        }
-      }
-      &ty_closure(ref f) => {
-        match f.store {
-            RegionTraitStore(r, _) => {
-                flags = flags | rflags(r);
-            }
-            _ => {}
-        }
-        for a in f.sig.inputs.iter() { flags = flags | get(*a).flags; }
-        if let ty::FnConverging(output) = f.sig.output {
-            flags = flags | get(output).flags;
-        }
-        flags = flags | flags_for_bounds(&f.bounds);
-      }
-    }
+    let flags = FlagComputation::for_sty(&st);
 
     let t = cx.type_arena.alloc(t_box_ {
         sty: st,
-        flags: flags,
+        flags: flags.flags,
+        region_depth: flags.depth,
     });
 
     let sty_ptr = &t.sty as *const sty;
@@ -1705,6 +1738,185 @@ fn flags_for_bounds(bounds: &ExistentialBounds) -> TypeFlags {
     }
 }
 
+struct FlagComputation {
+    flags: TypeFlags,
+
+    // maximum depth of any bound region that we have seen thus far
+    depth: uint,
+}
+
+impl FlagComputation {
+    fn new() -> FlagComputation {
+        FlagComputation { flags: NO_TYPE_FLAGS, depth: 0 }
+    }
+
+    fn for_sty(st: &sty) -> FlagComputation {
+        let mut result = FlagComputation::new();
+        result.add_sty(st);
+        result
+    }
+
+    fn add_flags(&mut self, flags: TypeFlags) {
+        self.flags = self.flags | flags;
+    }
+
+    fn add_depth(&mut self, depth: uint) {
+        if depth > self.depth {
+            self.depth = depth;
+        }
+    }
+
+    fn add_bound_computation(&mut self, computation: &FlagComputation) {
+        /*!
+         * Adds the flags/depth from a set of types that appear within
+         * the current type, but within a region binder.
+         */
+
+        self.add_flags(computation.flags);
+
+        // The types that contributed to `computation` occured within
+        // a region binder, so subtract one from the region depth
+        // within when adding the depth to `self`.
+        let depth = computation.depth;
+        if depth > 0 {
+            self.add_depth(depth - 1);
+        }
+    }
+
+    fn add_sty(&mut self, st: &sty) {
+        match st {
+            &ty_bool |
+            &ty_char |
+            &ty_int(_) |
+            &ty_float(_) |
+            &ty_uint(_) |
+            &ty_str => {
+            }
+
+            // You might think that we could just return ty_err for
+            // any type containing ty_err as a component, and get
+            // rid of the HAS_TY_ERR flag -- likewise for ty_bot (with
+            // the exception of function types that return bot).
+            // But doing so caused sporadic memory corruption, and
+            // neither I (tjc) nor nmatsakis could figure out why,
+            // so we're doing it this way.
+            &ty_err => {
+                self.add_flags(HAS_TY_ERR)
+            }
+
+            &ty_param(ref p) => {
+                if p.space == subst::SelfSpace {
+                    self.add_flags(HAS_SELF);
+                } else {
+                    self.add_flags(HAS_PARAMS);
+                }
+            }
+
+            &ty_unboxed_closure(_, ref region, ref substs) => {
+                self.add_region(*region);
+                self.add_substs(substs);
+            }
+
+            &ty_infer(_) => {
+                self.add_flags(HAS_TY_INFER)
+            }
+
+            &ty_enum(_, ref substs) | &ty_struct(_, ref substs) => {
+                self.add_substs(substs);
+            }
+
+            &ty_trait(box TyTrait { ref principal, ref bounds }) => {
+                self.add_substs(&principal.substs);
+                self.add_bounds(bounds);
+            }
+
+            &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => {
+                self.add_ty(tt)
+            }
+
+            &ty_ptr(ref m) => {
+                self.add_ty(m.ty);
+            }
+
+            &ty_rptr(r, ref m) => {
+                self.add_region(r);
+                self.add_ty(m.ty);
+            }
+
+            &ty_tup(ref ts) => {
+                self.add_tys(ts[]);
+            }
+
+            &ty_bare_fn(ref f) => {
+                self.add_fn_sig(&f.sig);
+            }
+
+            &ty_closure(ref f) => {
+                match f.store {
+                    RegionTraitStore(r, _) => {
+                        self.add_region(r);
+                    }
+                    _ => {}
+                }
+                self.add_fn_sig(&f.sig);
+                self.add_bounds(&f.bounds);
+            }
+        }
+    }
+
+    fn add_ty(&mut self, t: t) {
+        let t_box = get(t);
+        self.add_flags(t_box.flags);
+        self.add_depth(t_box.region_depth);
+    }
+
+    fn add_tys(&mut self, tys: &[t]) {
+        for &ty in tys.iter() {
+            self.add_ty(ty);
+        }
+    }
+
+    fn add_fn_sig(&mut self, fn_sig: &FnSig) {
+        let mut computation = FlagComputation::new();
+
+        computation.add_tys(fn_sig.inputs[]);
+
+        if let ty::FnConverging(output) = fn_sig.output {
+            computation.add_ty(output);
+        }
+
+        self.add_bound_computation(&computation);
+    }
+
+    fn add_region(&mut self, r: Region) {
+        self.add_flags(HAS_REGIONS);
+        match r {
+            ty::ReInfer(_) => { self.add_flags(HAS_RE_INFER); }
+            ty::ReLateBound(debruijn, _) => {
+                self.add_flags(HAS_RE_LATE_BOUND);
+                self.add_depth(debruijn.depth);
+            }
+            _ => { }
+        }
+    }
+
+    fn add_substs(&mut self, substs: &Substs) {
+        self.add_tys(substs.types.as_slice());
+        match substs.regions {
+            subst::ErasedRegions => {}
+            subst::NonerasedRegions(ref regions) => {
+                for &r in regions.iter() {
+                    self.add_region(r);
+                }
+            }
+        }
+    }
+
+    fn add_bounds(&mut self, bounds: &ExistentialBounds) {
+        self.add_region(bounds.region_bound);
+    }
+}
+
 #[inline]
 pub fn mk_prim_t(primitive: &'static t_box_) -> t {
     unsafe {
@@ -1855,7 +2067,6 @@ pub fn mk_bare_fn(cx: &ctxt, fty: BareFnTy) -> t {
 }
 
 pub fn mk_ctor_fn(cx: &ctxt,
-                  binder_id: ast::NodeId,
                   input_tys: &[ty::t],
                   output: ty::t) -> t {
     let input_args = input_tys.iter().map(|t| *t).collect();
@@ -1864,7 +2075,6 @@ pub fn mk_ctor_fn(cx: &ctxt,
                    fn_style: ast::NormalFn,
                    abi: abi::Rust,
                    sig: FnSig {
-                    binder_id: binder_id,
                     inputs: input_args,
                     output: ty::FnConverging(output),
                     variadic: false
@@ -4783,13 +4993,12 @@ fn fold_substs(&mut self,
                             types: substs.types.fold_with(self) }
         }
 
-        fn fold_sig(&mut self,
-                    sig: &ty::FnSig)
-                    -> ty::FnSig {
+        fn fold_fn_sig(&mut self,
+                       sig: &ty::FnSig)
+                       -> ty::FnSig {
             // The binder-id is only relevant to bound regions, which
             // are erased at trans time.
             ty::FnSig {
-                binder_id: ast::DUMMY_NODE_ID,
                 inputs: sig.inputs.fold_with(self),
                 output: sig.output.fold_with(self),
                 variadic: sig.variadic,
@@ -5589,3 +5798,85 @@ pub fn is_identity(&self) -> bool {
         self.autoderefs == 0 && self.autoref.is_none()
     }
 }
+
+pub fn liberate_late_bound_regions<HR>(
+    tcx: &ty::ctxt,
+    scope_id: ast::NodeId,
+    value: &HR)
+    -> HR
+    where HR : HigherRankedFoldable
+{
+    /*!
+     * Replace any late-bound regions bound in `value` with free variants
+     * attached to scope-id `scope_id`.
+     */
+
+    replace_late_bound_regions(
+        tcx, value,
+        |br, _| ty::ReFree(ty::FreeRegion{scope_id: scope_id, bound_region: br})).0
+}
+
+pub fn erase_late_bound_regions<HR>(
+    tcx: &ty::ctxt,
+    value: &HR)
+    -> HR
+    where HR : HigherRankedFoldable
+{
+    /*!
+     * Replace any late-bound regions bound in `value` with `'static`.
+     * Useful in trans.
+     */
+
+    replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic).0
+}
+
+pub fn replace_late_bound_regions<HR>(
+    tcx: &ty::ctxt,
+    value: &HR,
+    mapf: |BoundRegion, DebruijnIndex| -> ty::Region)
+    -> (HR, FnvHashMap<ty::BoundRegion,ty::Region>)
+    where HR : HigherRankedFoldable
+{
+    /*!
+     * Replaces the late-bound-regions in `value` that are bound by `value`.
+     */
+
+    debug!("replace_late_bound_regions({})", value.repr(tcx));
+
+    let mut map = FnvHashMap::new();
+    let value = {
+        let mut f = ty_fold::RegionFolder::new(tcx, |region, current_depth| {
+            debug!("region={}", region.repr(tcx));
+            match region {
+                ty::ReLateBound(debruijn, br) if debruijn.depth == current_depth => {
+                    * match map.entry(br) {
+                        Vacant(entry) => entry.set(mapf(br, debruijn)),
+                        Occupied(entry) => entry.into_mut(),
+                    }
+                }
+                _ => {
+                    region
+                }
+            }
+        });
+
+        // Note: use `fold_contents` not `fold_with`. If we used
+        // `fold_with`, it would consider the late-bound regions bound
+        // by `value` to be bound, but we want to consider them as
+        // `free`.
+        value.fold_contents(&mut f)
+    };
+    debug!("resulting map: {} value: {}", map, value.repr(tcx));
+    (value, map)
+}
+
+impl DebruijnIndex {
+    pub fn new(depth: uint) -> DebruijnIndex {
+        assert!(depth > 0);
+        DebruijnIndex { depth: depth }
+    }
+
+    pub fn shifted(&self, amount: uint) -> DebruijnIndex {
+        DebruijnIndex { depth: self.depth + amount }
+    }
+}
index 6d8d03aa0ab7af9c724593b935dfa14c174298d2..c0686e1c8fcc35880706f6732169ca14877b2bf7 100644 (file)
@@ -63,6 +63,17 @@ pub trait TypeFoldable {
 pub trait TypeFolder<'tcx> {
     fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
 
+    /// Invoked by the `super_*` routines when we enter a region
+    /// binding level (for example, when entering a function
+    /// signature). This is used by clients that want to track the
+    /// Debruijn index nesting level.
+    fn enter_region_binder(&mut self) { }
+
+    /// Invoked by the `super_*` routines when we exit a region
+    /// binding level. This is used by clients that want to
+    /// track the Debruijn index nesting level.
+    fn exit_region_binder(&mut self) { }
+
     fn fold_ty(&mut self, t: ty::t) -> ty::t {
         super_fold_ty(self, t)
     }
@@ -85,10 +96,10 @@ fn fold_substs(&mut self,
         super_fold_substs(self, substs)
     }
 
-    fn fold_sig(&mut self,
+    fn fold_fn_sig(&mut self,
                 sig: &ty::FnSig)
                 -> ty::FnSig {
-        super_fold_sig(self, sig)
+        super_fold_fn_sig(self, sig)
     }
 
     fn fold_output(&mut self,
@@ -153,6 +164,12 @@ fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, _: &mut F) -> () {
     }
 }
 
+impl<T:TypeFoldable,U:TypeFoldable> TypeFoldable for (T, U) {
+    fn fold_with<'tcx, F:TypeFolder<'tcx>>(&self, folder: &mut F) -> (T, U) {
+        (self.0.fold_with(folder), self.1.fold_with(folder))
+    }
+}
+
 impl<T:TypeFoldable> TypeFoldable for Option<T> {
     fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Option<T> {
         self.as_ref().map(|t| t.fold_with(folder))
@@ -171,6 +188,15 @@ fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Vec<T> {
     }
 }
 
+impl<T:TypeFoldable> TypeFoldable for ty::Binder<T> {
+    fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
+        folder.enter_region_binder();
+        let result = ty::bind(self.value.fold_with(folder));
+        folder.exit_region_binder();
+        result
+    }
+}
+
 impl<T:TypeFoldable> TypeFoldable for OwnedSlice<T> {
     fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> OwnedSlice<T> {
         self.iter().map(|t| t.fold_with(folder)).collect()
@@ -179,7 +205,24 @@ fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> OwnedSlice<T>
 
 impl<T:TypeFoldable> TypeFoldable for VecPerParamSpace<T> {
     fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> VecPerParamSpace<T> {
-        self.map(|t| t.fold_with(folder))
+
+        // Things in the Fn space take place under an additional level
+        // of region binding relative to the other spaces. This is
+        // because those entries are attached to a method, and methods
+        // always introduce a level of region binding.
+
+        let result = self.map_enumerated(|(space, index, elem)| {
+            if space == subst::FnSpace && index == 0 {
+                // enter new level when/if we reach the first thing in fn space
+                folder.enter_region_binder();
+            }
+            elem.fold_with(folder)
+        });
+        if result.len(subst::FnSpace) > 0 {
+            // if there was anything in fn space, exit the region binding level
+            folder.exit_region_binder();
+        }
+        result
     }
 }
 
@@ -221,7 +264,7 @@ fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnOutput {
 
 impl TypeFoldable for ty::FnSig {
     fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnSig {
-        folder.fold_sig(self)
+        folder.fold_fn_sig(self)
     }
 }
 
@@ -457,11 +500,21 @@ pub fn super_fold_substs<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
                     types: substs.types.fold_with(this) }
 }
 
-pub fn super_fold_sig<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
-                                                 sig: &ty::FnSig)
-                                                 -> ty::FnSig {
-    ty::FnSig { binder_id: sig.binder_id,
-                inputs: sig.inputs.fold_with(this),
+pub fn super_fold_fn_sig<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
+                                                    sig: &ty::FnSig)
+                                                    -> ty::FnSig
+{
+    this.enter_region_binder();
+    let result = super_fold_fn_sig_contents(this, sig);
+    this.exit_region_binder();
+    result
+}
+
+pub fn super_fold_fn_sig_contents<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
+                                                             sig: &ty::FnSig)
+                                                             -> ty::FnSig
+{
+    ty::FnSig { inputs: sig.inputs.fold_with(this),
                 output: sig.output.fold_with(this),
                 variadic: sig.variadic }
 }
@@ -622,6 +675,27 @@ pub fn super_fold_obligation<'tcx, T:TypeFolder<'tcx>>(this: &mut T,
 }
 
 ///////////////////////////////////////////////////////////////////////////
+// Higher-ranked things
+
+/**
+ * Designates a "binder" for late-bound regions.
+ */
+pub trait HigherRankedFoldable : Repr {
+    /// Folds the contents of `self`, ignoring the region binder created
+    /// by `self`.
+    fn fold_contents<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self;
+}
+
+impl HigherRankedFoldable for ty::FnSig {
+    fn fold_contents<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::FnSig {
+        super_fold_fn_sig_contents(folder, self)
+    }
+}
+impl<T:TypeFoldable+Repr> HigherRankedFoldable for ty::Binder<T> {
+    fn fold_contents<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder<T> {
+        ty::bind(self.value.fold_with(folder))
+    }
+}
 // Some sample folders
 
 pub struct BottomUpFolder<'a, 'tcx: 'a> {
@@ -655,77 +729,43 @@ fn fold_ty(&mut self, ty: ty::t) -> ty::t {
 /// current position of the fold.)
 pub struct RegionFolder<'a, 'tcx: 'a> {
     tcx: &'a ty::ctxt<'tcx>,
-    fld_t: |ty::t|: 'a -> ty::t,
-    fld_r: |ty::Region|: 'a -> ty::Region,
-    within_binder_ids: Vec<ast::NodeId>,
+    current_depth: uint,
+    fld_r: |ty::Region, uint|: 'a -> ty::Region,
 }
 
 impl<'a, 'tcx> RegionFolder<'a, 'tcx> {
-    pub fn general(tcx: &'a ty::ctxt<'tcx>,
-                   fld_r: |ty::Region|: 'a -> ty::Region,
-                   fld_t: |ty::t|: 'a -> ty::t)
-                   -> RegionFolder<'a, 'tcx> {
+    pub fn new(tcx: &'a ty::ctxt<'tcx>, fld_r: |ty::Region, uint|: 'a -> ty::Region)
+               -> RegionFolder<'a, 'tcx> {
         RegionFolder {
             tcx: tcx,
-            fld_t: fld_t,
+            current_depth: 1,
             fld_r: fld_r,
-            within_binder_ids: vec![],
         }
     }
-
-    pub fn regions(tcx: &'a ty::ctxt<'tcx>, fld_r: |ty::Region|: 'a -> ty::Region)
-                   -> RegionFolder<'a, 'tcx> {
-        fn noop(t: ty::t) -> ty::t { t }
-
-        RegionFolder {
-            tcx: tcx,
-            fld_t: noop,
-            fld_r: fld_r,
-            within_binder_ids: vec![],
-        }
-    }
-}
-
-/// If `ty` has `FnSig` (i.e. closure or fn), return its binder_id;
-/// else None.
-fn opt_binder_id_of_function(t: ty::t) -> Option<ast::NodeId> {
-    match ty::get(t).sty {
-        ty::ty_closure(ref f) => Some(f.sig.binder_id),
-        ty::ty_bare_fn(ref f) => Some(f.sig.binder_id),
-        _                     => None,
-    }
 }
 
 impl<'a, 'tcx> TypeFolder<'tcx> for RegionFolder<'a, 'tcx> {
     fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx }
 
-    fn fold_ty(&mut self, ty: ty::t) -> ty::t {
-        debug!("RegionFolder.fold_ty({})", ty.repr(self.tcx()));
-        let opt_binder_id = opt_binder_id_of_function(ty);
-        match opt_binder_id {
-            Some(binder_id) => self.within_binder_ids.push(binder_id),
-            None => {}
-        }
-
-        let t1 = super_fold_ty(self, ty);
-        let ret = (self.fld_t)(t1);
-
-        if opt_binder_id.is_some() {
-            self.within_binder_ids.pop();
-        }
+    fn enter_region_binder(&mut self) {
+        self.current_depth += 1;
+    }
 
-        ret
+    fn exit_region_binder(&mut self) {
+        self.current_depth -= 1;
     }
 
     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
         match r {
-            ty::ReLateBound(binder_id, _) if self.within_binder_ids.contains(&binder_id) => {
-                debug!("RegionFolder.fold_region({}) skipped bound region", r.repr(self.tcx()));
+            ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => {
+                debug!("RegionFolder.fold_region({}) skipped bound region (current depth={})",
+                       r.repr(self.tcx()), self.current_depth);
                 r
             }
             _ => {
-                debug!("RegionFolder.fold_region({}) folding free region", r.repr(self.tcx()));
-                (self.fld_r)(r)
+                debug!("RegionFolder.fold_region({}) folding free region (current_depth={})",
+                       r.repr(self.tcx()), self.current_depth);
+                (self.fld_r)(r, self.current_depth)
             }
         }
     }
@@ -755,3 +795,33 @@ fn fold_region(&mut self, r: ty::Region) -> ty::Region {
         }
     }
 }
+
+///////////////////////////////////////////////////////////////////////////
+// Region shifter
+//
+// Shifts the De Bruijn indices on all escaping bound regions by a
+// fixed amount. Useful in substitution or when otherwise introducing
+// a binding level that is not intended to capture the existing bound
+// regions. See comment on `shift_regions_through_binders` method in
+// `subst.rs` for more details.
+
+pub fn shift_region(region: ty::Region, amount: uint) -> ty::Region {
+    match region {
+        ty::ReLateBound(debruijn, br) => {
+            ty::ReLateBound(debruijn.shifted(amount), br)
+        }
+        _ => {
+            region
+        }
+    }
+}
+
+pub fn shift_regions<T:TypeFoldable+Repr>(tcx: &ty::ctxt, amount: uint, value: &T) -> T {
+    debug!("shift_regions(value={}, amount={})",
+           value.repr(tcx), amount);
+
+    value.fold_with(&mut RegionFolder::new(tcx, |region, _current_depth| {
+        shift_region(region, amount)
+    }))
+}
+
index 3ef9a59d8adb4560db95f12e3688aeb7b79f67d1..3cb3494fb305b7edfe642784f5379a430dadf725 100644 (file)
@@ -106,9 +106,8 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
             ty::ReStatic
         }
 
-        Some(&rl::DefLateBoundRegion(binder_id, _, id)) => {
-            ty::ReLateBound(binder_id, ty::BrNamed(ast_util::local_def(id),
-                                                   lifetime.name))
+        Some(&rl::DefLateBoundRegion(debruijn, id)) => {
+            ty::ReLateBound(debruijn, ty::BrNamed(ast_util::local_def(id), lifetime.name))
         }
 
         Some(&rl::DefEarlyBoundRegion(space, index, id)) => {
@@ -210,8 +209,7 @@ fn ast_path_substs<'tcx,AC,RS>(
     decl_generics: &ty::Generics,
     self_ty: Option<ty::t>,
     associated_ty: Option<ty::t>,
-    path: &ast::Path,
-    binder_id: ast::NodeId)
+    path: &ast::Path)
     -> Substs
     where AC: AstConv<'tcx>, RS: RegionScope
 {
@@ -463,8 +461,7 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
     this: &AC,
     rscope: &RS,
     did: ast::DefId,
-    path: &ast::Path,
-    binder_id: ast::NodeId)
+    path: &ast::Path)
     -> TypeAndSubsts
 {
     let tcx = this.tcx();
@@ -473,14 +470,13 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
         ty: decl_ty
     } = this.get_item_ty(did);
 
-    let substs = ast_path_substs(this,
-                                 rscope,
-                                 did,
-                                 &generics,
-                                 None,
-                                 None,
-                                 path,
-                                 binder_id);
+    let substs = ast_path_substs_for_ty(this,
+                                        rscope,
+                                        did,
+                                        &generics,
+                                        None,
+                                        None,
+                                        path);
     let ty = decl_ty.subst(tcx, &substs);
     TypeAndSubsts { substs: substs, ty: ty }
 }
@@ -494,8 +490,7 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>(
     this: &AC,
     rscope: &RS,
     did: ast::DefId,
-    path: &ast::Path,
-    binder_id: ast::NodeId)
+    path: &ast::Path)
     -> TypeAndSubsts
     where AC : AstConv<'tcx>, RS : RegionScope
 {
@@ -521,7 +516,7 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>(
         Substs::new(VecPerParamSpace::params_from_type(type_params),
                     VecPerParamSpace::params_from_type(region_params))
     } else {
-        ast_path_substs(this, rscope, did, &generics, None, None, path, binder_id)
+        ast_path_substs_for_ty(this, rscope, did, &generics, None, None, path)
     };
 
     let ty = decl_ty.subst(tcx, &substs);
@@ -628,7 +623,7 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
             match a_def {
                 def::DefTy(did, _) |
                 def::DefStruct(did) if Some(did) == this.tcx().lang_items.owned_box() => {
-                    let ty = ast_path_to_ty(this, rscope, did, path, id).ty;
+                    let ty = ast_path_to_ty(this, rscope, did, path).ty;
                     match ty::get(ty).sty {
                         ty::ty_struct(struct_def_id, ref substs) => {
                             assert_eq!(struct_def_id, did);
@@ -689,8 +684,7 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                                                        trait_def_id,
                                                        None,
                                                        None,
-                                                       path,
-                                                       id);
+                                                       path);
                     let empty_vec = [];
                     let bounds = match *opt_bounds { None => empty_vec.as_slice(),
                                                      Some(ref bounds) => bounds.as_slice() };
@@ -752,12 +746,7 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC,
                                           trait_did,
                                           None,
                                           Some(for_type),
-                                          trait_path,
-                                          ast::DUMMY_NODE_ID); // *see below
-
-    // * The trait in a qualified path cannot be "higher-ranked" and
-    // hence cannot use the parenthetical sugar, so the binder-id is
-    // irrelevant.
+                                          trait_path);
 
     debug!("associated_ty_to_ty(trait_ref={})",
            trait_ref.repr(this.tcx()));
@@ -830,8 +819,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                     tcx.sess.span_err(ast_ty.span,
                                       "variadic function must have C calling convention");
                 }
-                ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.fn_style,
-                                                  bf.abi, &*bf.decl))
+                ty::mk_bare_fn(tcx, ty_of_bare_fn(this, bf.fn_style, bf.abi, &*bf.decl))
             }
             ast::TyClosure(ref f) => {
                 // Use corresponding trait store to figure out default bounds
@@ -842,7 +830,6 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                                                      [].as_slice(),
                                                      f.bounds.as_slice());
                 let fn_decl = ty_of_closure(this,
-                                            ast_ty.id,
                                             f.fn_style,
                                             f.onceness,
                                             bounds,
@@ -863,7 +850,6 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                                                      f.bounds.as_slice());
 
                 let fn_decl = ty_of_closure(this,
-                                            ast_ty.id,
                                             f.fn_style,
                                             f.onceness,
                                             bounds,
@@ -910,8 +896,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                                                            trait_def_id,
                                                            None,
                                                            None,
-                                                           path,
-                                                           id);
+                                                           path);
                         let empty_bounds: &[ast::TyParamBound] = &[];
                         let ast_bounds = match *bounds {
                             Some(ref b) => b.as_slice(),
@@ -927,7 +912,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
                                      bounds)
                     }
                     def::DefTy(did, _) | def::DefStruct(did) => {
-                        ast_path_to_ty(this, rscope, did, path, id).ty
+                        ast_path_to_ty(this, rscope, did, path).ty
                     }
                     def::DefTyParam(space, id, n) => {
                         check_path_args(tcx, path, NO_TPS | NO_REGIONS);
@@ -1056,7 +1041,6 @@ struct SelfInfo<'a> {
 
 pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>(
                     this: &AC,
-                    id: ast::NodeId,
                     fn_style: ast::FnStyle,
                     untransformed_self_ty: ty::t,
                     explicit_self: &ast::ExplicitSelf,
@@ -1069,7 +1053,6 @@ pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>(
     });
     let (bare_fn_ty, optional_explicit_self_category) =
         ty_of_method_or_bare_fn(this,
-                                id,
                                 fn_style,
                                 abi,
                                 self_info,
@@ -1077,17 +1060,14 @@ pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>(
     (bare_fn_ty, optional_explicit_self_category.unwrap())
 }
 
-pub fn ty_of_bare_fn<'tcx, AC: AstConv<'tcx>>(this: &AC, id: ast::NodeId,
-                                              fn_style: ast::FnStyle, abi: abi::Abi,
+pub fn ty_of_bare_fn<'tcx, AC: AstConv<'tcx>>(this: &AC, fn_style: ast::FnStyle, abi: abi::Abi,
                                               decl: &ast::FnDecl) -> ty::BareFnTy {
-    let (bare_fn_ty, _) =
-        ty_of_method_or_bare_fn(this, id, fn_style, abi, None, decl);
+    let (bare_fn_ty, _) = ty_of_method_or_bare_fn(this, fn_style, abi, None, decl);
     bare_fn_ty
 }
 
 fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
                            this: &AC,
-                           id: ast::NodeId,
                            fn_style: ast::FnStyle,
                            abi: abi::Abi,
                            opt_self_info: Option<SelfInfo>,
@@ -1098,7 +1078,7 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
 
     // New region names that appear inside of the arguments of the function
     // declaration are bound to that function type.
-    let rb = rscope::BindingRscope::new(id);
+    let rb = rscope::BindingRscope::new();
 
     // `implied_output_region` is the region that will be assumed for any
     // region parameters in the return type. In accordance with the rules for
@@ -1114,7 +1094,9 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
                 determine_explicit_self_category(this, &rb, &self_info);
             explicit_self_category_result = Some(explicit_self_category);
             match explicit_self_category {
-                ty::StaticExplicitSelfCategory => (None, None),
+                ty::StaticExplicitSelfCategory => {
+                    (None, None)
+                }
                 ty::ByValueExplicitSelfCategory => {
                     (Some(self_info.untransformed_self_ty), None)
                 }
@@ -1205,7 +1187,6 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
         fn_style: fn_style,
         abi: abi,
         sig: ty::FnSig {
-            binder_id: id,
             inputs: self_and_input_tys,
             output: output_ty,
             variadic: decl.variadic
@@ -1290,7 +1271,6 @@ fn determine_explicit_self_category<'tcx, AC: AstConv<'tcx>,
 
 pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>(
     this: &AC,
-    id: ast::NodeId,
     fn_style: ast::FnStyle,
     onceness: ast::Onceness,
     bounds: ty::ExistentialBounds,
@@ -1300,13 +1280,14 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>(
     expected_sig: Option<ty::FnSig>)
     -> ty::ClosureTy
 {
-    debug!("ty_of_fn_decl");
+    debug!("ty_of_closure(expected_sig={})",
+           expected_sig.repr(this.tcx()));
 
     // new region names that appear inside of the fn decl are bound to
     // that function type
-    let rb = rscope::BindingRscope::new(id);
+    let rb = rscope::BindingRscope::new();
 
-    let input_tys = decl.inputs.iter().enumerate().map(|(i, a)| {
+    let input_tys: Vec<_> = decl.inputs.iter().enumerate().map(|(i, a)| {
         let expected_arg_ty = expected_sig.as_ref().and_then(|e| {
             // no guarantee that the correct number of expected args
             // were supplied
@@ -1331,14 +1312,16 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>(
         ast::NoReturn(_) => ty::FnDiverging
     };
 
+    debug!("ty_of_closure: input_tys={}", input_tys.repr(this.tcx()));
+    debug!("ty_of_closure: output_ty={}", output_ty.repr(this.tcx()));
+
     ty::ClosureTy {
         fn_style: fn_style,
         onceness: onceness,
         store: store,
         bounds: bounds,
         abi: abi,
-        sig: ty::FnSig {binder_id: id,
-                        inputs: input_tys,
+        sig: ty::FnSig {inputs: input_tys,
                         output: output_ty,
                         variadic: decl.variadic}
     }
index 33705343dabe7de07788db0c4ce3504934ee5540..c7598eadaab9224f23f2aee2ac6238b9bf86f837 100644 (file)
@@ -528,9 +528,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
 
     // First, we have to replace any bound regions in the fn type with free ones.
     // The free region references will be bound the node_id of the body block.
-    let (_, fn_sig) = replace_late_bound_regions(tcx, fn_sig.binder_id, fn_sig, |br| {
-        ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
-    });
+    let fn_sig = liberate_late_bound_regions(tcx, body.id, fn_sig);
 
     let arg_tys = fn_sig.inputs.as_slice();
     let ret_ty = fn_sig.output;
@@ -3031,7 +3029,6 @@ fn check_call<'a>(fcx: &FnCtxt,
         // In that case, we check each argument against "error" in order to
         // set up all the node type bindings.
         let error_fn_sig = FnSig {
-            binder_id: ast::CRATE_NODE_ID,
             inputs: err_args(args.len()),
             output: ty::FnConverging(ty::mk_err()),
             variadic: false
@@ -3051,11 +3048,9 @@ fn check_call<'a>(fcx: &FnCtxt,
         // Replace any bound regions that appear in the function
         // signature with region variables
         let fn_sig =
-            fcx.infcx().replace_late_bound_regions_with_fresh_var(
-                fn_sig.binder_id,
-                call_expr.span,
-                infer::FnCall,
-                fn_sig).0;
+            fcx.infcx().replace_late_bound_regions_with_fresh_var(call_expr.span,
+                                                                  infer::FnCall,
+                                                                  fn_sig).0;
 
         // Call the generic checker.
         check_argument_types(fcx,
@@ -3437,7 +3432,6 @@ fn check_unboxed_closure(fcx: &FnCtxt,
                              body: &ast::Block) {
         let mut fn_ty = astconv::ty_of_closure(
             fcx,
-            expr.id,
             ast::NormalFn,
             ast::Many,
 
@@ -3508,6 +3502,10 @@ fn check_expr_fn(fcx: &FnCtxt,
                      expected: Expectation) {
         let tcx = fcx.ccx.tcx;
 
+        debug!("check_expr_fn(expr={}, expected={})",
+               expr.repr(tcx),
+               expected.repr(tcx));
+
         // Find the expected input/output types (if any). Substitute
         // fresh bound regions for any bound regions we find in the
         // expected types so as to avoid capture.
@@ -3517,10 +3515,11 @@ fn check_expr_fn(fcx: &FnCtxt,
              expected_bounds) = {
             match expected_sty {
                 Some(ty::ty_closure(ref cenv)) => {
-                    let (_, sig) =
+                    let (sig, _) =
                         replace_late_bound_regions(
-                            tcx, cenv.sig.binder_id, &cenv.sig,
-                            |_| fcx.inh.infcx.fresh_bound_region(expr.id));
+                            tcx,
+                            &cenv.sig,
+                            |_, debruijn| fcx.inh.infcx.fresh_bound_region(debruijn));
                     let onceness = match (&store, &cenv.store) {
                         // As the closure type and onceness go, only three
                         // combinations are legit:
@@ -3561,7 +3560,6 @@ fn check_expr_fn(fcx: &FnCtxt,
 
         // construct the function type
         let fn_ty = astconv::ty_of_closure(fcx,
-                                           expr.id,
                                            ast::NormalFn,
                                            expected_onceness,
                                            expected_bounds,
@@ -5943,7 +5941,6 @@ fn param(ccx: &CrateCtxt, n: uint) -> ty::t {
         fn_style: ast::UnsafeFn,
         abi: abi::RustIntrinsic,
         sig: FnSig {
-            binder_id: it.id,
             inputs: inputs,
             output: output,
             variadic: false,
index b7710ab7bf9b9da90fab1ae43c8b8335386201cd..2e727a8ef9aa594901f3b86bfc1a46dc163ca061 100644 (file)
 
 use middle::subst::{ParamSpace, Subst, Substs};
 use middle::ty;
-use middle::ty_fold;
-use middle::ty_fold::{TypeFolder, TypeFoldable};
+use middle::ty_fold::{TypeFolder};
 
 use syntax::ast;
 
-use std::collections::hash_map::{Occupied, Vacant};
-use util::nodemap::FnvHashMap;
 use util::ppaux::Repr;
 
 // Helper functions related to manipulating region types.
 
-pub fn replace_late_bound_regions<T>(
-    tcx: &ty::ctxt,
-    binder_id: ast::NodeId,
-    value: &T,
-    map_fn: |ty::BoundRegion| -> ty::Region)
-    -> (FnvHashMap<ty::BoundRegion,ty::Region>, T)
-    where T : TypeFoldable + Repr
-{
-    debug!("replace_late_bound_regions(binder_id={}, value={})",
-           binder_id, value.repr(tcx));
-
-    let mut map = FnvHashMap::new();
-    let new_value = {
-        let mut folder = ty_fold::RegionFolder::regions(tcx, |r| {
-            match r {
-                ty::ReLateBound(s, br) if s == binder_id => {
-                    match map.entry(br) {
-                        Vacant(entry) => *entry.set(map_fn(br)),
-                        Occupied(entry) => *entry.into_mut(),
-                    }
-                }
-                _ => r
-            }
-        });
-        value.fold_with(&mut folder)
-    };
-    debug!("resulting map: {}", map);
-    (map, new_value)
-}
-
 pub enum WfConstraint {
     RegionSubRegionConstraint(Option<ty::t>, ty::Region, ty::Region),
     RegionSubParamConstraint(Option<ty::t>, ty::Region, ty::ParamTy),
index b3449d658f6d6e556da15cb8914a003960f97e7f..254f46f846676361584709789ddb2eedd44478c1 100644 (file)
@@ -372,16 +372,12 @@ fn fold_ty(&mut self, t: ty::t) -> ty::t {
             ty::ty_closure(box ty::ClosureTy{sig: ref fn_sig, ..}) => {
                 self.binding_count += 1;
 
-                let (_, fn_sig) =
-                    replace_late_bound_regions(
-                        self.fcx.tcx(), fn_sig.binder_id, fn_sig,
-                        |br| ty::ReFree(ty::FreeRegion{scope_id: self.scope_id,
-                                                       bound_region: br}));
+                let fn_sig = liberate_late_bound_regions(self.fcx.tcx(), self.scope_id, fn_sig);
 
                 debug!("late-bound regions replaced: {}",
                        fn_sig.repr(self.tcx()));
 
-                self.fold_sig(&fn_sig);
+                self.fold_fn_sig(&fn_sig);
 
                 self.binding_count -= 1;
             }
index a5ca5179f08b00372b6b1a6ec36fbd86c788ffea..3f90f59247393f01143442b0df82ed4e7a4568e4 100644 (file)
@@ -214,12 +214,11 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt,
     for variant in variants.iter() {
         // Nullary enum constructors get turned into constants; n-ary enum
         // constructors get turned into functions.
-        let scope = variant.node.id;
         let result_ty = match variant.node.kind {
             ast::TupleVariantKind(ref args) if args.len() > 0 => {
                 let rs = ExplicitRscope;
                 let input_tys: Vec<_> = args.iter().map(|va| ccx.to_ty(&rs, &*va.ty)).collect();
-                ty::mk_ctor_fn(tcx, scope, input_tys.as_slice(), enum_ty)
+                ty::mk_ctor_fn(tcx, input_tys.as_slice(), enum_ty)
             }
 
             ast::TupleVariantKind(_) => {
@@ -403,7 +402,6 @@ fn ty_method_of_trait_method(ccx: &CrateCtxt,
             let trait_self_ty = ty::mk_self_type(tmcx.tcx(),
                                                  local_def(trait_id));
             astconv::ty_of_method(&tmcx,
-                                  *m_id,
                                   *m_fn_style,
                                   trait_self_ty,
                                   m_explicit_self,
@@ -588,7 +586,6 @@ fn ty_of_method(ccx: &CrateCtxt,
                     method_generics: &m_ty_generics,
                 };
                 astconv::ty_of_method(&imcx,
-                                      m.id,
                                       m.pe_fn_style(),
                                       untransformed_rcvr_ty,
                                       m.pe_explicit_self(),
@@ -603,7 +600,6 @@ fn ty_of_method(ccx: &CrateCtxt,
                     method_generics: &m_ty_generics,
                 };
                 astconv::ty_of_method(&tmcx,
-                                      m.id,
                                       m.pe_fn_style(),
                                       untransformed_rcvr_ty,
                                       m.pe_explicit_self(),
@@ -1294,7 +1290,6 @@ pub fn convert_struct(ccx: &CrateCtxt,
                         |field| (*tcx.tcache.borrow())[
                             local_def(field.node.id)].ty).collect();
                 let ctor_fn_ty = ty::mk_ctor_fn(tcx,
-                                                ctor_id,
                                                 inputs.as_slice(),
                                                 selfty);
                 write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty);
@@ -1465,11 +1460,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::Item)
                     ccx: ccx,
                     generics: &ty_generics,
                 };
-                astconv::ty_of_bare_fn(&fcx,
-                                       it.id,
-                                       fn_style,
-                                       abi,
-                                       &**decl)
+                astconv::ty_of_bare_fn(&fcx, fn_style, abi, &**decl)
             };
             let pty = Polytype {
                 generics: ty_generics,
@@ -2091,7 +2082,7 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
             ast_generics,
             ty::Generics::empty(),
             DontCreateTypeParametersForAssociatedTypes);
-    let rb = BindingRscope::new(def_id.node);
+    let rb = BindingRscope::new();
     let input_tys = decl.inputs
                         .iter()
                         .map(|a| ty_of_arg(ccx, &rb, a, None))
@@ -2109,8 +2100,7 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt,
         ty::BareFnTy {
             abi: abi,
             fn_style: ast::UnsafeFn,
-            sig: ty::FnSig {binder_id: def_id.node,
-                            inputs: input_tys,
+            sig: ty::FnSig {inputs: input_tys,
                             output: output,
                             variadic: decl.variadic}
         });
index 078a2c10bcb3514b8adb7c87c8046b32f1bd3c21..f0d480c719a9bdeb047db015681f0978a961bee9 100644 (file)
@@ -334,48 +334,6 @@ pub fn expected_found<'tcx, C: Combine<'tcx>, T>(
     }
 }
 
-pub fn super_fn_sigs<'tcx, C: Combine<'tcx>>(this: &C,
-                                             a: &ty::FnSig,
-                                             b: &ty::FnSig)
-                                             -> cres<ty::FnSig> {
-
-    fn argvecs<'tcx, C: Combine<'tcx>>(this: &C,
-                                       a_args: &[ty::t],
-                                       b_args: &[ty::t])
-                                       -> cres<Vec<ty::t>> {
-        if a_args.len() == b_args.len() {
-            a_args.iter().zip(b_args.iter())
-                  .map(|(a, b)| this.args(*a, *b)).collect()
-        } else {
-            Err(ty::terr_arg_count)
-        }
-    }
-
-    if a.variadic != b.variadic {
-        return Err(ty::terr_variadic_mismatch(expected_found(this, a.variadic, b.variadic)));
-    }
-
-    let inputs = try!(argvecs(this,
-                                a.inputs.as_slice(),
-                                b.inputs.as_slice()));
-
-    let output = try!(match (a.output, b.output) {
-        (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) =>
-            Ok(ty::FnConverging(try!(this.tys(a_ty, b_ty)))),
-        (ty::FnDiverging, ty::FnDiverging) =>
-            Ok(ty::FnDiverging),
-        (a, b) =>
-            Err(ty::terr_convergence_mismatch(
-                expected_found(this, a != ty::FnDiverging, b != ty::FnDiverging)
-            )),
-    });
-
-    Ok(FnSig {binder_id: a.binder_id,
-              inputs: inputs,
-              output: output,
-              variadic: a.variadic})
-}
-
 pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
 
     let tcx = this.infcx().tcx;
index bb8c59f0259776dd4cf735af4c87cf10d186ab2f..287a5cfba9e34aabd4316b9aa5b2bc7205c6e11f 100644 (file)
@@ -125,4 +125,8 @@ fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> {
     fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres<ty::FnSig> {
         self.higher_ranked_glb(a, b)
     }
+
+    fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres<ty::TraitRef> {
+        self.higher_ranked_glb(a, b)
+    }
 }
index 12807f9050e49a4b781c2a327095f515d369fdb4..6f75192e6019d750be432da354d7b6d56cb9d0d1 100644 (file)
@@ -797,8 +797,8 @@ pub fn fresh_substs_for_trait(&self,
         subst::Substs::new_trait(type_parameters, regions, assoc_type_parameters, self_ty)
     }
 
-    pub fn fresh_bound_region(&self, binder_id: ast::NodeId) -> ty::Region {
-        self.region_vars.new_bound(binder_id)
+    pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region {
+        self.region_vars.new_bound(debruijn)
     }
 
     pub fn resolve_regions_and_report_errors(&self) {
@@ -968,30 +968,19 @@ pub fn report_mismatched_types(&self,
 
     pub fn replace_late_bound_regions_with_fresh_var<T>(
         &self,
-        binder_id: ast::NodeId,
         span: Span,
         lbrct: LateBoundRegionConversionTime,
         value: &T)
         -> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
-        where T : TypeFoldable + Repr
+        where T : HigherRankedFoldable
     {
-        let (map, value) =
-            replace_late_bound_regions(
-                self.tcx,
-                binder_id,
-                value,
-                |br| self.next_region_var(LateBoundRegion(span, br, lbrct)));
-        (value, map)
+        ty::replace_late_bound_regions(
+            self.tcx,
+            value,
+            |br, _| self.next_region_var(LateBoundRegion(span, br, lbrct)))
     }
 }
 
-pub fn fold_regions_in_sig(tcx: &ty::ctxt,
-                           fn_sig: &ty::FnSig,
-                           fldr: |r: ty::Region| -> ty::Region)
-                           -> ty::FnSig {
-    ty_fold::RegionFolder::regions(tcx, fldr).fold_sig(fn_sig)
-}
-
 impl TypeTrace {
     pub fn span(&self) -> Span {
         self.origin.span()
index c65a930195c7f0488665c930d366649a507b1879..54fb7872f3b03ccab1be84f4c66904c71dbf8d62 100644 (file)
@@ -332,7 +332,7 @@ pub fn new_skolemized(&self, br: ty::BoundRegion) -> Region {
         ReInfer(ReSkolemized(sc, br))
     }
 
-    pub fn new_bound(&self, binder_id: ast::NodeId) -> Region {
+    pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region {
         // Creates a fresh bound variable for use in GLB computations.
         // See discussion of GLB computation in the large comment at
         // the top of this file for more details.
@@ -358,7 +358,7 @@ pub fn new_bound(&self, binder_id: ast::NodeId) -> Region {
             self.tcx.sess.bug("rollover in RegionInference new_bound()");
         }
 
-        ReLateBound(binder_id, BrFresh(sc))
+        ReLateBound(debruijn, BrFresh(sc))
     }
 
     fn values_are_none(&self) -> bool {
index 634b153a9ce341332cfa770b691aa48b668ba063..24d11b25a60f2c3df05ced17d6568b3dcba8702a 100644 (file)
@@ -383,7 +383,6 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
                 fn_style: ast::NormalFn,
                 abi: abi::Rust,
                 sig: ty::FnSig {
-                    binder_id: main_id,
                     inputs: Vec::new(),
                     output: ty::FnConverging(ty::mk_nil(tcx)),
                     variadic: false
@@ -432,7 +431,6 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
                 fn_style: ast::NormalFn,
                 abi: abi::Rust,
                 sig: ty::FnSig {
-                    binder_id: start_id,
                     inputs: vec!(
                         ty::mk_int(),
                         ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, ty::mk_u8()))
index 2845e3954b5c6c6f2fb514cb212bf7c8b9b4acdb..745c76eb77f581831c47ab3aa0952705487a8b75 100644 (file)
@@ -104,14 +104,12 @@ fn anon_regions(&self,
 /// A scope in which we generate anonymous, late-bound regions for
 /// omitted regions. This occurs in function signatures.
 pub struct BindingRscope {
-    binder_id: ast::NodeId,
     anon_bindings: Cell<uint>,
 }
 
 impl BindingRscope {
-    pub fn new(binder_id: ast::NodeId) -> BindingRscope {
+    pub fn new() -> BindingRscope {
         BindingRscope {
-            binder_id: binder_id,
             anon_bindings: Cell::new(0),
         }
     }
@@ -119,7 +117,7 @@ pub fn new(binder_id: ast::NodeId) -> BindingRscope {
     fn next_region(&self) -> ty::Region {
         let idx = self.anon_bindings.get();
         self.anon_bindings.set(idx + 1);
-        ty::ReLateBound(self.binder_id, ty::BrAnon(idx))
+        ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(idx))
     }
 }
 
index e6015bfc074ec028dae25e92627187fbe88a3037..ec8b49c108cd168353325fc58aeee6b15b275b4c 100644 (file)
@@ -252,8 +252,7 @@ pub fn vec_map_to_string<T>(ts: &[T], f: |t: &T| -> String) -> String {
 }
 
 pub fn fn_sig_to_string(cx: &ctxt, typ: &ty::FnSig) -> String {
-    format!("fn{}{} -> {}", typ.binder_id, typ.inputs.repr(cx),
-            typ.output.repr(cx))
+    format!("fn{} -> {}", typ.inputs.repr(cx), typ.output.repr(cx))
 }
 
 pub fn trait_ref_to_string(cx: &ctxt, trait_ref: &ty::TraitRef) -> String {
@@ -262,11 +261,11 @@ pub fn trait_ref_to_string(cx: &ctxt, trait_ref: &ty::TraitRef) -> String {
 
 pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
     fn bare_fn_to_string(cx: &ctxt,
-                      fn_style: ast::FnStyle,
-                      abi: abi::Abi,
-                      ident: Option<ast::Ident>,
-                      sig: &ty::FnSig)
-                      -> String {
+                         fn_style: ast::FnStyle,
+                         abi: abi::Abi,
+                         ident: Option<ast::Ident>,
+                         sig: &ty::FnSig)
+                         -> String {
         let mut s = String::new();
         match fn_style {
             ast::NormalFn => {}
@@ -1301,3 +1300,8 @@ fn repr(&self, tcx: &ctxt) -> String {
     }
 }
 
+impl<T:Repr> Repr for ty::Binder<T> {
+    fn repr(&self, tcx: &ctxt) -> String {
+        format!("Binder({})", self.value.repr(tcx))
+    }
+}
index 4648021cc5fd7dbf3b358f43a7768cb6f63cb40a..c063c22b234d0411d7dceecced940c81bffb694d 100644 (file)
@@ -14,9 +14,6 @@
 
 */
 
-// This is only used by tests, hence allow dead code.
-#![allow(dead_code)]
-
 use driver::diagnostic;
 use driver::diagnostic::Emitter;
 use driver::driver;
 use middle::resolve;
 use middle::resolve_lifetime;
 use middle::stability;
+use middle::subst;
+use middle::subst::Subst;
 use middle::ty;
 use middle::typeck::infer::combine::Combine;
 use middle::typeck::infer;
 use middle::typeck::infer::lub::Lub;
 use middle::typeck::infer::glb::Glb;
-use session::{mod, config};
+use session::{mod,config};
+use syntax::{abi, ast, ast_map, ast_util};
 use syntax::codemap;
 use syntax::codemap::{Span, CodeMap, DUMMY_SP};
 use syntax::diagnostic::{Level, RenderSpan, Bug, Fatal, Error, Warning, Note, Help};
-use syntax::{ast, ast_map};
-use util::ppaux::{ty_to_string, UserString};
+use syntax::parse::token;
+use util::ppaux::{ty_to_string, Repr, UserString};
 
 use arena::TypedArena;
 
@@ -97,12 +97,12 @@ fn errors(msgs: &[&str]) -> (Box<Emitter+Send>, uint) {
     (box ExpectErrorEmitter { messages: v } as Box<Emitter+Send>, msgs.len())
 }
 
-fn test_env(_test_name: &str,
-            source_string: &str,
+fn test_env(source_string: &str,
             (emitter, expected_err_count): (Box<Emitter+Send>, uint),
             body: |Env|) {
-    let options =
+    let mut options =
         config::basic_options();
+    options.debugging_opts |= config::VERBOSE;
     let codemap =
         CodeMap::new();
     let diagnostic_handler =
@@ -125,7 +125,7 @@ fn test_env(_test_name: &str,
     let lang_items = lang_items::collect_language_items(krate, &sess);
     let resolve::CrateMap { def_map, freevars, capture_mode_map, .. } =
         resolve::resolve_crate(&sess, &lang_items, krate);
-    let named_region_map = resolve_lifetime::krate(&sess, krate);
+    let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
     let region_map = region::resolve_crate(&sess, krate);
     let stability_index = stability::Index::build(krate);
     let type_arena = TypedArena::new();
@@ -164,6 +164,7 @@ pub fn create_simple_region_hierarchy(&self) {
                             sub: &[]}]});
     }
 
+    #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now
     pub fn lookup_item(&self, names: &[String]) -> ast::NodeId {
         return match search_mod(self, &self.infcx.tcx.map.krate().module, 0, names) {
             Some(id) => id,
@@ -237,14 +238,6 @@ pub fn assert_subtype(&self, a: ty::t, b: ty::t) {
         }
     }
 
-    pub fn assert_not_subtype(&self, a: ty::t, b: ty::t) {
-        if self.is_subtype(a, b) {
-            panic!("{} is a subtype of {}, but it shouldn't be",
-                  self.ty_to_string(a),
-                  self.ty_to_string(b));
-        }
-    }
-
     pub fn assert_eq(&self, a: ty::t, b: ty::t) {
         self.assert_subtype(a, b);
         self.assert_subtype(b, a);
@@ -255,36 +248,91 @@ pub fn ty_to_string(&self, a: ty::t) -> String {
     }
 
     pub fn t_fn(&self,
-                binder_id: ast::NodeId,
                 input_tys: &[ty::t],
                 output_ty: ty::t)
                 -> ty::t
     {
-        ty::mk_ctor_fn(self.infcx.tcx, binder_id, input_tys, output_ty)
+        ty::mk_ctor_fn(self.infcx.tcx, input_tys, output_ty)
+    }
+
+    pub fn t_nil(&self) -> ty::t {
+        ty::mk_nil(self.infcx.tcx)
+    }
+
+    pub fn t_pair(&self, ty1: ty::t, ty2: ty::t) -> ty::t
+    {
+        ty::mk_tup(self.infcx.tcx, vec![ty1, ty2])
+    }
+
+    pub fn t_closure(&self,
+                     input_tys: &[ty::t],
+                     output_ty: ty::t,
+                     region_bound: ty::Region)
+                     -> ty::t
+    {
+        ty::mk_closure(self.infcx.tcx, ty::ClosureTy {
+            fn_style: ast::NormalFn,
+            onceness: ast::Many,
+            store: ty::RegionTraitStore(region_bound, ast::MutMutable),
+            bounds: ty::region_existential_bound(region_bound),
+            sig: ty::FnSig {
+                inputs: input_tys.to_vec(),
+                output: ty::FnConverging(output_ty),
+                variadic: false,
+            },
+            abi: abi::Rust,
+        })
+    }
+
+    pub fn t_param(&self, space: subst::ParamSpace, index: uint) -> ty::t {
+        ty::mk_param(self.infcx.tcx, space, index, ast_util::local_def(ast::DUMMY_NODE_ID))
+    }
+
+    pub fn re_early_bound(&self,
+                          space: subst::ParamSpace,
+                          index: uint,
+                          name: &'static str)
+                          -> ty::Region
+    {
+        let name = token::intern(name);
+        ty::ReEarlyBound(ast::DUMMY_NODE_ID, space, index, name)
+    }
+
+    pub fn re_late_bound_with_debruijn(&self, id: uint, debruijn: ty::DebruijnIndex) -> ty::Region {
+        ty::ReLateBound(debruijn, ty::BrAnon(id))
+    }
+
+    pub fn t_rptr(&self, r: ty::Region) -> ty::t {
+        ty::mk_imm_rptr(self.infcx.tcx, r, ty::mk_int())
     }
 
-    pub fn t_int(&self) -> ty::t {
-        ty::mk_int()
+    pub fn t_rptr_late_bound(&self, id: uint) -> ty::t {
+        ty::mk_imm_rptr(self.infcx.tcx,
+                        self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1)),
+                        ty::mk_int())
     }
 
-    pub fn t_rptr_late_bound(&self, binder_id: ast::NodeId, id: uint) -> ty::t {
-        ty::mk_imm_rptr(self.infcx.tcx, ty::ReLateBound(binder_id, ty::BrAnon(id)),
-                        self.t_int())
+    pub fn t_rptr_late_bound_with_debruijn(&self, id: uint, debruijn: ty::DebruijnIndex) -> ty::t {
+        ty::mk_imm_rptr(self.infcx.tcx,
+                        self.re_late_bound_with_debruijn(id, debruijn),
+                        ty::mk_int())
     }
 
     pub fn t_rptr_scope(&self, id: ast::NodeId) -> ty::t {
-        ty::mk_imm_rptr(self.infcx.tcx, ty::ReScope(id), self.t_int())
+        ty::mk_imm_rptr(self.infcx.tcx, ty::ReScope(id), ty::mk_int())
+    }
+
+    pub fn re_free(&self, nid: ast::NodeId, id: uint) -> ty::Region {
+        ty::ReFree(ty::FreeRegion {scope_id: nid,
+                                   bound_region: ty::BrAnon(id)})
     }
 
     pub fn t_rptr_free(&self, nid: ast::NodeId, id: uint) -> ty::t {
-        ty::mk_imm_rptr(self.infcx.tcx,
-                        ty::ReFree(ty::FreeRegion {scope_id: nid,
-                                                    bound_region: ty::BrAnon(id)}),
-                        self.t_int())
+        ty::mk_imm_rptr(self.infcx.tcx, self.re_free(nid, id), ty::mk_int())
     }
 
     pub fn t_rptr_static(&self) -> ty::t {
-        ty::mk_imm_rptr(self.infcx.tcx, ty::ReStatic, self.t_int())
+        ty::mk_imm_rptr(self.infcx.tcx, ty::ReStatic, ty::mk_int())
     }
 
     pub fn dummy_type_trace(&self) -> infer::TypeTrace {
@@ -301,10 +349,6 @@ pub fn glb(&self) -> Glb<'a, 'tcx> {
         Glb(self.infcx.combine_fields(true, trace))
     }
 
-    pub fn resolve_regions(&self) {
-        self.infcx.resolve_regions_and_report_errors();
-    }
-
     pub fn make_lub_ty(&self, t1: ty::t, t2: ty::t) -> ty::t {
         match self.lub().tys(t1, t2) {
             Ok(t) => t,
@@ -345,31 +389,11 @@ pub fn check_glb(&self, t1: ty::t, t2: ty::t, t_glb: ty::t) {
             }
         }
     }
-
-    /// Checks that `LUB(t1,t2)` is undefined
-    pub fn check_no_lub(&self, t1: ty::t, t2: ty::t) {
-        match self.lub().tys(t1, t2) {
-            Err(_) => {}
-            Ok(t) => {
-                panic!("unexpected success computing LUB: {}", self.ty_to_string(t))
-            }
-        }
-    }
-
-    /// Checks that `GLB(t1,t2)` is undefined
-    pub fn check_no_glb(&self, t1: ty::t, t2: ty::t) {
-        match self.glb().tys(t1, t2) {
-            Err(_) => {}
-            Ok(t) => {
-                panic!("unexpected success computing GLB: {}", self.ty_to_string(t))
-            }
-        }
-    }
 }
 
 #[test]
 fn contravariant_region_ptr_ok() {
-    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
         env.create_simple_region_hierarchy();
         let t_rptr1 = env.t_rptr_scope(1);
         let t_rptr10 = env.t_rptr_scope(10);
@@ -381,8 +405,7 @@ fn contravariant_region_ptr_ok() {
 
 #[test]
 fn contravariant_region_ptr_err() {
-    test_env("contravariant_region_ptr",
-             EMPTY_SOURCE_STR,
+    test_env(EMPTY_SOURCE_STR,
              errors(&["lifetime mismatch"]),
              |env| {
                  env.create_simple_region_hierarchy();
@@ -398,114 +421,273 @@ fn contravariant_region_ptr_err() {
 
 #[test]
 fn lub_bound_bound() {
-    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
-        let t_rptr_bound2 = env.t_rptr_late_bound(22, 2);
-        env.check_lub(env.t_fn(22, &[t_rptr_bound1], env.t_int()),
-                      env.t_fn(22, &[t_rptr_bound2], env.t_int()),
-                      env.t_fn(22, &[t_rptr_bound1], env.t_int()));
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(1);
+        let t_rptr_bound2 = env.t_rptr_late_bound(2);
+        env.check_lub(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_bound2], ty::mk_int()),
+                      env.t_fn(&[t_rptr_bound1], ty::mk_int()));
     })
 }
 
 #[test]
 fn lub_bound_free() {
-    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(1);
         let t_rptr_free1 = env.t_rptr_free(0, 1);
-        env.check_lub(env.t_fn(22, &[t_rptr_bound1], env.t_int()),
-                      env.t_fn(22, &[t_rptr_free1], env.t_int()),
-                      env.t_fn(22, &[t_rptr_free1], env.t_int()));
+        env.check_lub(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_free1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_free1], ty::mk_int()));
     })
 }
 
 #[test]
 fn lub_bound_static() {
-    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(1);
         let t_rptr_static = env.t_rptr_static();
-        env.check_lub(env.t_fn(22, &[t_rptr_bound1], env.t_int()),
-                      env.t_fn(22, &[t_rptr_static], env.t_int()),
-                      env.t_fn(22, &[t_rptr_static], env.t_int()));
+        env.check_lub(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_static], ty::mk_int()),
+                      env.t_fn(&[t_rptr_static], ty::mk_int()));
     })
 }
 
 #[test]
 fn lub_bound_bound_inverse_order() {
-    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
-        let t_rptr_bound2 = env.t_rptr_late_bound(22, 2);
-        env.check_lub(env.t_fn(22, &[t_rptr_bound1, t_rptr_bound2], t_rptr_bound1),
-                      env.t_fn(22, &[t_rptr_bound2, t_rptr_bound1], t_rptr_bound1),
-                      env.t_fn(22, &[t_rptr_bound1, t_rptr_bound1], t_rptr_bound1));
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(1);
+        let t_rptr_bound2 = env.t_rptr_late_bound(2);
+        env.check_lub(env.t_fn(&[t_rptr_bound1, t_rptr_bound2], t_rptr_bound1),
+                      env.t_fn(&[t_rptr_bound2, t_rptr_bound1], t_rptr_bound1),
+                      env.t_fn(&[t_rptr_bound1, t_rptr_bound1], t_rptr_bound1));
     })
 }
 
 #[test]
 fn lub_free_free() {
-    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
         let t_rptr_free1 = env.t_rptr_free(0, 1);
         let t_rptr_free2 = env.t_rptr_free(0, 2);
         let t_rptr_static = env.t_rptr_static();
-        env.check_lub(env.t_fn(22, &[t_rptr_free1], env.t_int()),
-                      env.t_fn(22, &[t_rptr_free2], env.t_int()),
-                      env.t_fn(22, &[t_rptr_static], env.t_int()));
+        env.check_lub(env.t_fn(&[t_rptr_free1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_free2], ty::mk_int()),
+                      env.t_fn(&[t_rptr_static], ty::mk_int()));
     })
 }
 
 #[test]
 fn lub_returning_scope() {
-    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR,
+    test_env(EMPTY_SOURCE_STR,
              errors(&["cannot infer an appropriate lifetime"]), |env| {
                  let t_rptr_scope10 = env.t_rptr_scope(10);
                  let t_rptr_scope11 = env.t_rptr_scope(11);
 
                  // this should generate an error when regions are resolved
-                 env.make_lub_ty(env.t_fn(22, &[], t_rptr_scope10),
-                                 env.t_fn(22, &[], t_rptr_scope11));
+                 env.make_lub_ty(env.t_fn(&[], t_rptr_scope10),
+                                 env.t_fn(&[], t_rptr_scope11));
              })
 }
 
 #[test]
 fn glb_free_free_with_common_scope() {
-    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors(&[]), |env| {
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
         let t_rptr_free1 = env.t_rptr_free(0, 1);
         let t_rptr_free2 = env.t_rptr_free(0, 2);
         let t_rptr_scope = env.t_rptr_scope(0);
-        env.check_glb(env.t_fn(22, &[t_rptr_free1], env.t_int()),
-                      env.t_fn(22, &[t_rptr_free2], env.t_int()),
-                      env.t_fn(22, &[t_rptr_scope], env.t_int()));
+        env.check_glb(env.t_fn(&[t_rptr_free1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_free2], ty::mk_int()),
+                      env.t_fn(&[t_rptr_scope], ty::mk_int()));
     })
 }
 
 #[test]
 fn glb_bound_bound() {
-    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
-        let t_rptr_bound2 = env.t_rptr_late_bound(22, 2);
-        env.check_glb(env.t_fn(22, &[t_rptr_bound1], env.t_int()),
-                      env.t_fn(22, &[t_rptr_bound2], env.t_int()),
-                      env.t_fn(22, &[t_rptr_bound1], env.t_int()));
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(1);
+        let t_rptr_bound2 = env.t_rptr_late_bound(2);
+        env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_bound2], ty::mk_int()),
+                      env.t_fn(&[t_rptr_bound1], ty::mk_int()));
     })
 }
 
 #[test]
 fn glb_bound_free() {
-    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(1);
         let t_rptr_free1 = env.t_rptr_free(0, 1);
-        env.check_glb(env.t_fn(22, &[t_rptr_bound1], env.t_int()),
-                      env.t_fn(22, &[t_rptr_free1], env.t_int()),
-                      env.t_fn(22, &[t_rptr_bound1], env.t_int()));
+        env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_free1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_bound1], ty::mk_int()));
     })
 }
 
 #[test]
 fn glb_bound_static() {
-    test_env("contravariant_region_ptr", EMPTY_SOURCE_STR, errors(&[]), |env| {
-        let t_rptr_bound1 = env.t_rptr_late_bound(22, 1);
+    test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+        let t_rptr_bound1 = env.t_rptr_late_bound(1);
         let t_rptr_static = env.t_rptr_static();
-        env.check_glb(env.t_fn(22, &[t_rptr_bound1], env.t_int()),
-                      env.t_fn(22, &[t_rptr_static], env.t_int()),
-                      env.t_fn(22, &[t_rptr_bound1], env.t_int()));
+        env.check_glb(env.t_fn(&[t_rptr_bound1], ty::mk_int()),
+                      env.t_fn(&[t_rptr_static], ty::mk_int()),
+                      env.t_fn(&[t_rptr_bound1], ty::mk_int()));
     })
 }
+
+#[test]
+fn subst_ty_renumber_bound() {
+    /*!
+     * Test substituting a bound region into a function, which introduces another
+     * level of binding. This requires adjusting the Debruijn index.
+     */
+
+    test_env(EMPTY_SOURCE_STR, errors([]), |env| {
+        // Situation:
+        // Theta = [A -> &'a foo]
+
+        let t_rptr_bound1 = env.t_rptr_late_bound(1);
+
+        // t_source = fn(A)
+        let t_source = {
+            let t_param = env.t_param(subst::TypeSpace, 0);
+            env.t_fn([t_param], env.t_nil())
+        };
+
+        let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]);
+        let t_substituted = t_source.subst(env.infcx.tcx, &substs);
+
+        // t_expected = fn(&'a int)
+        let t_expected = {
+            let t_ptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
+            env.t_fn([t_ptr_bound2], env.t_nil())
+        };
+
+        debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
+               t_source.repr(env.infcx.tcx),
+               substs.repr(env.infcx.tcx),
+               t_substituted.repr(env.infcx.tcx),
+               t_expected.repr(env.infcx.tcx));
+
+        assert_eq!(t_substituted, t_expected);
+    })
+}
+
+#[test]
+fn subst_ty_renumber_some_bounds() {
+    /*!
+     * Test substituting a bound region into a function, which introduces another
+     * level of binding. This requires adjusting the Debruijn index.
+     */
+
+    test_env(EMPTY_SOURCE_STR, errors([]), |env| {
+        // Situation:
+        // Theta = [A -> &'a foo]
+
+        let t_rptr_bound1 = env.t_rptr_late_bound(1);
+
+        // t_source = (A, fn(A))
+        let t_source = {
+            let t_param = env.t_param(subst::TypeSpace, 0);
+            env.t_pair(t_param, env.t_fn([t_param], env.t_nil()))
+        };
+
+        let substs = subst::Substs::new_type(vec![t_rptr_bound1], vec![]);
+        let t_substituted = t_source.subst(env.infcx.tcx, &substs);
+
+        // t_expected = (&'a int, fn(&'a int))
+        //
+        // but not that the Debruijn index is different in the different cases.
+        let t_expected = {
+            let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
+            env.t_pair(t_rptr_bound1, env.t_fn([t_rptr_bound2], env.t_nil()))
+        };
+
+        debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
+               t_source.repr(env.infcx.tcx),
+               substs.repr(env.infcx.tcx),
+               t_substituted.repr(env.infcx.tcx),
+               t_expected.repr(env.infcx.tcx));
+
+        assert_eq!(t_substituted, t_expected);
+    })
+}
+
+#[test]
+fn escaping() {
+    /*!
+     * Test that we correctly compute whether a type has escaping
+     * regions or not.
+     */
+
+    test_env(EMPTY_SOURCE_STR, errors([]), |env| {
+        // Situation:
+        // Theta = [A -> &'a foo]
+
+        assert!(!ty::type_has_escaping_regions(env.t_nil()));
+
+        let t_rptr_free1 = env.t_rptr_free(0, 1);
+        assert!(!ty::type_has_escaping_regions(t_rptr_free1));
+
+        let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
+        assert!(ty::type_has_escaping_regions(t_rptr_bound1));
+
+        let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
+        assert!(ty::type_has_escaping_regions(t_rptr_bound2));
+
+        // t_fn = fn(A)
+        let t_param = env.t_param(subst::TypeSpace, 0);
+        assert!(!ty::type_has_escaping_regions(t_param));
+        let t_fn = env.t_fn([t_param], env.t_nil());
+        assert!(!ty::type_has_escaping_regions(t_fn));
+
+        // t_fn = |&int|+'a
+        let t_fn = env.t_closure([t_rptr_bound1], env.t_nil(), env.re_free(0, 1));
+        assert!(!ty::type_has_escaping_regions(t_fn));
+
+        // t_fn = |&int|+'a (where &int has depth 2)
+        let t_fn = env.t_closure([t_rptr_bound2], env.t_nil(), env.re_free(0, 1));
+        assert!(ty::type_has_escaping_regions(t_fn));
+
+        // t_fn = |&int|+&int
+        let t_fn = env.t_closure([t_rptr_bound1], env.t_nil(),
+                                 env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)));
+        assert!(ty::type_has_escaping_regions(t_fn));
+    })
+}
+
+#[test]
+fn subst_region_renumber_region() {
+    /*!
+     * Test applying a substitution where the value being substituted
+     * for an early-bound region is a late-bound region.
+     */
+
+    test_env(EMPTY_SOURCE_STR, errors([]), |env| {
+        let re_bound1 = env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1));
+
+        // type t_source<'a> = fn(&'a int)
+        let t_source = {
+            let re_early = env.re_early_bound(subst::TypeSpace, 0, "'a");
+            env.t_fn([env.t_rptr(re_early)], env.t_nil())
+        };
+
+        let substs = subst::Substs::new_type(vec![], vec![re_bound1]);
+        let t_substituted = t_source.subst(env.infcx.tcx, &substs);
+
+        // t_expected = fn(&'a int)
+        //
+        // but not that the Debruijn index is different in the different cases.
+        let t_expected = {
+            let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2));
+            env.t_fn([t_rptr_bound2], env.t_nil())
+        };
+
+        debug!("subst_bound: t_source={} substs={} t_substituted={} t_expected={}",
+               t_source.repr(env.infcx.tcx),
+               substs.repr(env.infcx.tcx),
+               t_substituted.repr(env.infcx.tcx),
+               t_expected.repr(env.infcx.tcx));
+
+        assert_eq!(t_substituted, t_expected);
+    })
+}
+
index 0544c9d43a811e70b0f7566420df78a0071e8dc3..8e3ae6ee3599f819bca0e1564283008c3b723489 100644 (file)
@@ -269,7 +269,6 @@ pub fn trans_unboxing_shim(bcx: Block,
     let self_type = fty.sig.inputs[0];
     let boxed_self_type = ty::mk_uniq(tcx, self_type);
     let boxed_function_type = ty::FnSig {
-        binder_id: fty.sig.binder_id,
         inputs: fty.sig.inputs.iter().enumerate().map(|(i, typ)| {
             if i == 0 {
                 boxed_self_type
@@ -294,7 +293,6 @@ pub fn trans_unboxing_shim(bcx: Block,
             // RustCall so the untupled arguments can be passed
             // through verbatim.  This is kind of ugly.
             let fake_ty = ty::FnSig {
-                binder_id: fty.sig.binder_id,
                 inputs: type_of::untuple_arguments_if_necessary(ccx,
                                                                 fty.sig.inputs.as_slice(),
                                                                 fty.abi),
index 55ecd8a6554a64738b8a5c3dd55f04a206896f08..a2510cbfa2774ecee2a3265a95bbd3d38186b123 100644 (file)
@@ -609,9 +609,6 @@ pub fn get_vtable(bcx: Block,
                             fn_style: closure_info.closure_type.fn_style,
                             abi: Rust,
                             sig: ty::FnSig {
-                                binder_id: closure_info.closure_type
-                                                       .sig
-                                                       .binder_id,
                                 inputs: new_inputs,
                                 output: new_output,
                                 variadic: false,