Switch the code to use De Bruijn indices rather than binder-ids.
This commit is contained in:
parent
23652efffb
commit
4ab0c588ff
|
@ -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}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 @@ 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"),
|
||||
}
|
||||
|
|
|
@ -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<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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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 type UpvarBorrowMap = FnvHashMap<UpvarId, 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 @@ 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<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 @@ 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<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 }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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 @@ impl<T:TypeFoldable> TypeFoldable for 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 @@ impl<T:TypeFoldable> TypeFoldable for 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 @@ 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<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 @@ 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<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 => {}
|
||||
}
|
||||
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<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)
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
@ -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}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<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),
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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}
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -125,4 +125,8 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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<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 @@ 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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 @@ impl<A:Repr,B:Repr> Repr for (A,B) {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T:Repr> Repr for ty::Binder<T> {
|
||||
fn repr(&self, tcx: &ctxt) -> String {
|
||||
format!("Binder({})", self.value.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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 @@ 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);
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue