diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index e1b0797e982..69be2e34915 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -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} } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 3242d396146..a53f5fa187d 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -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); } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 20dcf094b66..ff6965574be 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -483,8 +483,8 @@ impl tr for 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) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 4077629f76d..7b2ff6d4b7d 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -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, 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, Scope<'a>), + LateScope(&'a Vec, Scope<'a>), /// lifetimes introduced by items within a code block are scoped /// to that block. BlockScope(ast::NodeId, Scope<'a>), @@ -115,12 +114,12 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { } 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 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { } 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 @@ impl<'a> LifetimeContext<'a> { 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 @@ impl<'a> LifetimeContext<'a> { 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 @@ impl<'a> LifetimeContext<'a> { // 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 @@ impl<'a> LifetimeContext<'a> { 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 @@ impl<'a> LifetimeContext<'a> { } 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"), } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 520209257f5..ae7cb8645e1 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -14,8 +14,7 @@ pub use self::ParamSpace::*; 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 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { 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 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { 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 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { } 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 \ - 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()); - } - } - } + } +} + +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(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 = 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,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) } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 5ec89ffb9e7..a322fcb3fa1 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -53,7 +53,7 @@ use middle::subst::{mod, Subst, Substs, VecPerParamSpace}; 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 type t_box = &'static t_box_; 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 @@ impl FnOutput { * 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, 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 type UpvarBorrowMap = FnvHashMap; 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 @@ mod primitives { pub static $name: t_box_ = t_box_ { sty: $sty, flags: super::NO_TYPE_FLAGS, + region_depth: 0, }; ) ) @@ -950,6 +1052,7 @@ mod primitives { 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 { + pub value: T +} + +pub fn bind(value: T) -> Binder { + 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 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t { } } +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 @@ pub fn normalize_ty(cx: &ctxt, t: t) -> t { 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 @@ impl AutoDerefRef { self.autoderefs == 0 && self.autoref.is_none() } } + +pub fn liberate_late_bound_regions
( + 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
( + 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
( + tcx: &ty::ctxt, + value: &HR, + mapf: |BoundRegion, DebruijnIndex| -> ty::Region) + -> (HR, FnvHashMap) + 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 } + } +} diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 6d8d03aa0ab..c0686e1c8fc 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -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 @@ pub trait TypeFolder<'tcx> { 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 @@ impl TypeFoldable for () { } } +impl 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 TypeFoldable for Option { fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Option { self.as_ref().map(|t| t.fold_with(folder)) @@ -171,6 +188,15 @@ impl TypeFoldable for Vec { } } +impl TypeFoldable for ty::Binder { + fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder { + folder.enter_region_binder(); + let result = ty::bind(self.value.fold_with(folder)); + folder.exit_region_binder(); + result + } +} + impl TypeFoldable for OwnedSlice { fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> OwnedSlice { self.iter().map(|t| t.fold_with(folder)).collect() @@ -179,7 +205,24 @@ impl TypeFoldable for OwnedSlice { impl TypeFoldable for VecPerParamSpace { fn fold_with<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> VecPerParamSpace { - 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 @@ impl TypeFoldable for 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 HigherRankedFoldable for ty::Binder { + fn fold_contents<'tcx, F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::Binder { + ty::bind(self.value.fold_with(folder)) + } +} // Some sample folders pub struct BottomUpFolder<'a, 'tcx: 'a> { @@ -655,77 +729,43 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BottomUpFolder<'a, 'tcx> { /// 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, + 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 { - 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 => {} - } + fn enter_region_binder(&mut self) { + self.current_depth += 1; + } - let t1 = super_fold_ty(self, ty); - let ret = (self.fld_t)(t1); - - if opt_binder_id.is_some() { - self.within_binder_ids.pop(); - } - - 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 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionEraser<'a, 'tcx> { } } } + +/////////////////////////////////////////////////////////////////////////// +// 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(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) + })) +} + diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 3ef9a59d8ad..3cb3494fb30 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -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, associated_ty: Option, - 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, @@ -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::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} } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 33705343dab..c7598eadaab 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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_expr_with_unifier(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_expr_with_unifier(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_expr_with_unifier(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_with_unifier(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_with_unifier(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_with_unifier(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 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &ast::ForeignItem) { fn_style: ast::UnsafeFn, abi: abi::RustIntrinsic, sig: FnSig { - binder_id: it.id, inputs: inputs, output: output, variadic: false, diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index b7710ab7bf9..2e727a8ef9a 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -14,47 +14,14 @@ pub use self::WfConstraint::*; 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( - tcx: &ty::ctxt, - binder_id: ast::NodeId, - value: &T, - map_fn: |ty::BoundRegion| -> ty::Region) - -> (FnvHashMap, 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::Region, ty::Region), RegionSubParamConstraint(Option, ty::Region, ty::ParamTy), diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs index b3449d658f6..254f46f8466 100644 --- a/src/librustc/middle/typeck/check/wf.rs +++ b/src/librustc/middle/typeck/check/wf.rs @@ -372,16 +372,12 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { 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; } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index a5ca5179f08..3f90f592473 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -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 collect_trait_methods(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 convert_methods<'a,I>(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 convert_methods<'a,I>(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} }); diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index 078a2c10bcb..f0d480c719a 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -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 { - - fn argvecs<'tcx, C: Combine<'tcx>>(this: &C, - a_args: &[ty::t], - b_args: &[ty::t]) - -> cres> { - 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 { let tcx = this.infcx().tcx; diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index bb8c59f0259..287a5cfba9e 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -125,4 +125,8 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { fn fn_sigs(&self, a: &ty::FnSig, b: &ty::FnSig) -> cres { self.higher_ranked_glb(a, b) } + + fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres { + self.higher_ranked_glb(a, b) + } } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 12807f9050e..6f75192e601 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -797,8 +797,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn replace_late_bound_regions_with_fresh_var( &self, - binder_id: ast::NodeId, span: Span, lbrct: LateBoundRegionConversionTime, value: &T) -> (T, FnvHashMap) - 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() diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index c65a930195c..54fb7872f3b 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -332,7 +332,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { 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 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { self.tcx.sess.bug("rollover in RegionInference new_bound()"); } - ReLateBound(binder_id, BrFresh(sc)) + ReLateBound(debruijn, BrFresh(sc)) } fn values_are_none(&self) -> bool { diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 634b153a9ce..24d11b25a60 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -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())) diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index 2845e3954b5..745c76eb77f 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -104,14 +104,12 @@ impl RegionScope for SpecificRscope { /// 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, } 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 @@ impl 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)) } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index e6015bfc074..ec8b49c108c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -252,8 +252,7 @@ pub fn vec_map_to_string(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, - sig: &ty::FnSig) - -> String { + fn_style: ast::FnStyle, + abi: abi::Abi, + ident: Option, + sig: &ty::FnSig) + -> String { let mut s = String::new(); match fn_style { ast::NormalFn => {} @@ -1301,3 +1300,8 @@ impl Repr for (A,B) { } } +impl Repr for ty::Binder { + fn repr(&self, tcx: &ctxt) -> String { + format!("Binder({})", self.value.repr(tcx)) + } +} diff --git a/src/librustc_trans/test.rs b/src/librustc_trans/test.rs index 4648021cc5f..c063c22b234 100644 --- a/src/librustc_trans/test.rs +++ b/src/librustc_trans/test.rs @@ -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; @@ -25,17 +22,20 @@ use middle::region; 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, uint) { (box ExpectErrorEmitter { messages: v } as Box, msgs.len()) } -fn test_env(_test_name: &str, - source_string: &str, +fn test_env(source_string: &str, (emitter, expected_err_count): (Box, 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 @@ impl<'a, 'tcx> Env<'a, 'tcx> { 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 @@ impl<'a, 'tcx> Env<'a, 'tcx> { } } - 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 @@ impl<'a, 'tcx> Env<'a, 'tcx> { } 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_int(&self) -> ty::t { - ty::mk_int() + pub fn t_nil(&self) -> ty::t { + ty::mk_nil(self.infcx.tcx) } - 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_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_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_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 @@ impl<'a, 'tcx> Env<'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 @@ impl<'a, 'tcx> Env<'a, 'tcx> { } } } - - /// 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); + }) +} + diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 0544c9d43a8..8e3ae6ee359 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -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), diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 55ecd8a6554..a2510cbfa27 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -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,