Switch the code to use De Bruijn indices rather than binder-ids.

This commit is contained in:
Niko Matsakis 2014-11-15 16:47:59 -05:00
parent 23652efffb
commit 4ab0c588ff
22 changed files with 1075 additions and 551 deletions

View File

@ -294,7 +294,7 @@ fn parse_region(st: &mut PState, conv: conv_did) -> ty::Region {
match next(st) {
'b' => {
assert_eq!(next(st), '[');
let id = parse_uint(st) as ast::NodeId;
let id = ty::DebruijnIndex::new(parse_uint(st));
assert_eq!(next(st), '|');
let br = parse_bound_region(st, |x,y| conv(x,y));
assert_eq!(next(st), ']');
@ -579,8 +579,6 @@ fn parse_bare_fn_ty(st: &mut PState, conv: conv_did) -> ty::BareFnTy {
fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig {
assert_eq!(next(st), '[');
let id = parse_uint(st) as ast::NodeId;
assert_eq!(next(st), '|');
let mut inputs = Vec::new();
while peek(st) != ']' {
inputs.push(parse_ty(st, |x,y| conv(x,y)));
@ -598,8 +596,7 @@ fn parse_sig(st: &mut PState, conv: conv_did) -> ty::FnSig {
}
_ => ty::FnConverging(parse_ty(st, |x,y| conv(x,y)))
};
ty::FnSig {binder_id: id,
inputs: inputs,
ty::FnSig {inputs: inputs,
output: output,
variadic: variadic}
}

View File

@ -130,7 +130,7 @@ fn enc_region_substs(w: &mut SeekableMemWriter, cx: &ctxt, substs: &subst::Regio
pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
match r {
ty::ReLateBound(id, br) => {
mywrite!(w, "b[{}|", id);
mywrite!(w, "b[{}|", id.depth);
enc_bound_region(w, cx, br);
mywrite!(w, "]");
}
@ -331,7 +331,7 @@ pub fn enc_closure_ty(w: &mut SeekableMemWriter, cx: &ctxt, ft: &ty::ClosureTy)
}
fn enc_fn_sig(w: &mut SeekableMemWriter, cx: &ctxt, fsig: &ty::FnSig) {
mywrite!(w, "[{}|", fsig.binder_id);
mywrite!(w, "[");
for ty in fsig.inputs.iter() {
enc_ty(w, cx, *ty);
}

View File

@ -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)

View File

@ -39,8 +39,7 @@ pub enum DefRegion {
DefEarlyBoundRegion(/* space */ subst::ParamSpace,
/* index */ uint,
/* lifetime decl */ ast::NodeId),
DefLateBoundRegion(/* binder_id */ ast::NodeId,
/* depth */ uint,
DefLateBoundRegion(ty::DebruijnIndex,
/* lifetime decl */ ast::NodeId),
DefFreeRegion(/* block scope */ ast::NodeId,
/* lifetime decl */ ast::NodeId),
@ -60,9 +59,9 @@ enum ScopeChain<'a> {
/// EarlyScope(i, ['a, 'b, ...], s) extends s with early-bound
/// lifetimes, assigning indexes 'a => i, 'b => i+1, ... etc.
EarlyScope(subst::ParamSpace, &'a Vec<ast::LifetimeDef>, Scope<'a>),
/// LateScope(binder_id, ['a, 'b, ...], s) extends s with late-bound
/// LateScope(['a, 'b, ...], s) extends s with late-bound
/// lifetimes introduced by the declaration binder_id.
LateScope(ast::NodeId, &'a Vec<ast::LifetimeDef>, Scope<'a>),
LateScope(&'a Vec<ast::LifetimeDef>, Scope<'a>),
/// lifetimes introduced by items within a code block are scoped
/// to that block.
BlockScope(ast::NodeId, Scope<'a>),
@ -115,12 +114,12 @@ 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"),
}

View File

@ -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)
}
}

View File

@ -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 }
}
}

View File

@ -63,6 +63,17 @@ pub trait TypeFoldable {
pub trait TypeFolder<'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
/// Invoked by the `super_*` routines when we enter a region
/// binding level (for example, when entering a function
/// signature). This is used by clients that want to track the
/// Debruijn index nesting level.
fn enter_region_binder(&mut self) { }
/// Invoked by the `super_*` routines when we exit a region
/// binding level. This is used by clients that want to
/// track the Debruijn index nesting level.
fn exit_region_binder(&mut self) { }
fn fold_ty(&mut self, t: ty::t) -> ty::t {
super_fold_ty(self, t)
}
@ -85,10 +96,10 @@ 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)
}))
}

View File

@ -106,9 +106,8 @@ pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime)
ty::ReStatic
}
Some(&rl::DefLateBoundRegion(binder_id, _, id)) => {
ty::ReLateBound(binder_id, ty::BrNamed(ast_util::local_def(id),
lifetime.name))
Some(&rl::DefLateBoundRegion(debruijn, id)) => {
ty::ReLateBound(debruijn, ty::BrNamed(ast_util::local_def(id), lifetime.name))
}
Some(&rl::DefEarlyBoundRegion(space, index, id)) => {
@ -210,8 +209,7 @@ fn ast_path_substs<'tcx,AC,RS>(
decl_generics: &ty::Generics,
self_ty: Option<ty::t>,
associated_ty: Option<ty::t>,
path: &ast::Path,
binder_id: ast::NodeId)
path: &ast::Path)
-> Substs
where AC: AstConv<'tcx>, RS: RegionScope
{
@ -463,8 +461,7 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
this: &AC,
rscope: &RS,
did: ast::DefId,
path: &ast::Path,
binder_id: ast::NodeId)
path: &ast::Path)
-> TypeAndSubsts
{
let tcx = this.tcx();
@ -473,14 +470,13 @@ pub fn ast_path_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
ty: decl_ty
} = this.get_item_ty(did);
let substs = ast_path_substs(this,
rscope,
did,
&generics,
None,
None,
path,
binder_id);
let substs = ast_path_substs_for_ty(this,
rscope,
did,
&generics,
None,
None,
path);
let ty = decl_ty.subst(tcx, &substs);
TypeAndSubsts { substs: substs, ty: ty }
}
@ -494,8 +490,7 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>(
this: &AC,
rscope: &RS,
did: ast::DefId,
path: &ast::Path,
binder_id: ast::NodeId)
path: &ast::Path)
-> TypeAndSubsts
where AC : AstConv<'tcx>, RS : RegionScope
{
@ -521,7 +516,7 @@ pub fn ast_path_to_ty_relaxed<'tcx,AC,RS>(
Substs::new(VecPerParamSpace::params_from_type(type_params),
VecPerParamSpace::params_from_type(region_params))
} else {
ast_path_substs(this, rscope, did, &generics, None, None, path, binder_id)
ast_path_substs_for_ty(this, rscope, did, &generics, None, None, path)
};
let ty = decl_ty.subst(tcx, &substs);
@ -628,7 +623,7 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
match a_def {
def::DefTy(did, _) |
def::DefStruct(did) if Some(did) == this.tcx().lang_items.owned_box() => {
let ty = ast_path_to_ty(this, rscope, did, path, id).ty;
let ty = ast_path_to_ty(this, rscope, did, path).ty;
match ty::get(ty).sty {
ty::ty_struct(struct_def_id, ref substs) => {
assert_eq!(struct_def_id, did);
@ -689,8 +684,7 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
trait_def_id,
None,
None,
path,
id);
path);
let empty_vec = [];
let bounds = match *opt_bounds { None => empty_vec.as_slice(),
Some(ref bounds) => bounds.as_slice() };
@ -752,12 +746,7 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC,
trait_did,
None,
Some(for_type),
trait_path,
ast::DUMMY_NODE_ID); // *see below
// * The trait in a qualified path cannot be "higher-ranked" and
// hence cannot use the parenthetical sugar, so the binder-id is
// irrelevant.
trait_path);
debug!("associated_ty_to_ty(trait_ref={})",
trait_ref.repr(this.tcx()));
@ -830,8 +819,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
tcx.sess.span_err(ast_ty.span,
"variadic function must have C calling convention");
}
ty::mk_bare_fn(tcx, ty_of_bare_fn(this, ast_ty.id, bf.fn_style,
bf.abi, &*bf.decl))
ty::mk_bare_fn(tcx, ty_of_bare_fn(this, bf.fn_style, bf.abi, &*bf.decl))
}
ast::TyClosure(ref f) => {
// Use corresponding trait store to figure out default bounds
@ -842,7 +830,6 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
[].as_slice(),
f.bounds.as_slice());
let fn_decl = ty_of_closure(this,
ast_ty.id,
f.fn_style,
f.onceness,
bounds,
@ -863,7 +850,6 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
f.bounds.as_slice());
let fn_decl = ty_of_closure(this,
ast_ty.id,
f.fn_style,
f.onceness,
bounds,
@ -910,8 +896,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
trait_def_id,
None,
None,
path,
id);
path);
let empty_bounds: &[ast::TyParamBound] = &[];
let ast_bounds = match *bounds {
Some(ref b) => b.as_slice(),
@ -927,7 +912,7 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
bounds)
}
def::DefTy(did, _) | def::DefStruct(did) => {
ast_path_to_ty(this, rscope, did, path, id).ty
ast_path_to_ty(this, rscope, did, path).ty
}
def::DefTyParam(space, id, n) => {
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
@ -1056,7 +1041,6 @@ struct SelfInfo<'a> {
pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>(
this: &AC,
id: ast::NodeId,
fn_style: ast::FnStyle,
untransformed_self_ty: ty::t,
explicit_self: &ast::ExplicitSelf,
@ -1069,7 +1053,6 @@ pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>(
});
let (bare_fn_ty, optional_explicit_self_category) =
ty_of_method_or_bare_fn(this,
id,
fn_style,
abi,
self_info,
@ -1077,17 +1060,14 @@ pub fn ty_of_method<'tcx, AC: AstConv<'tcx>>(
(bare_fn_ty, optional_explicit_self_category.unwrap())
}
pub fn ty_of_bare_fn<'tcx, AC: AstConv<'tcx>>(this: &AC, id: ast::NodeId,
fn_style: ast::FnStyle, abi: abi::Abi,
pub fn ty_of_bare_fn<'tcx, AC: AstConv<'tcx>>(this: &AC, fn_style: ast::FnStyle, abi: abi::Abi,
decl: &ast::FnDecl) -> ty::BareFnTy {
let (bare_fn_ty, _) =
ty_of_method_or_bare_fn(this, id, fn_style, abi, None, decl);
let (bare_fn_ty, _) = ty_of_method_or_bare_fn(this, fn_style, abi, None, decl);
bare_fn_ty
}
fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
this: &AC,
id: ast::NodeId,
fn_style: ast::FnStyle,
abi: abi::Abi,
opt_self_info: Option<SelfInfo>,
@ -1098,7 +1078,7 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
// New region names that appear inside of the arguments of the function
// declaration are bound to that function type.
let rb = rscope::BindingRscope::new(id);
let rb = rscope::BindingRscope::new();
// `implied_output_region` is the region that will be assumed for any
// region parameters in the return type. In accordance with the rules for
@ -1114,7 +1094,9 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
determine_explicit_self_category(this, &rb, &self_info);
explicit_self_category_result = Some(explicit_self_category);
match explicit_self_category {
ty::StaticExplicitSelfCategory => (None, None),
ty::StaticExplicitSelfCategory => {
(None, None)
}
ty::ByValueExplicitSelfCategory => {
(Some(self_info.untransformed_self_ty), None)
}
@ -1205,7 +1187,6 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>(
fn_style: fn_style,
abi: abi,
sig: ty::FnSig {
binder_id: id,
inputs: self_and_input_tys,
output: output_ty,
variadic: decl.variadic
@ -1290,7 +1271,6 @@ fn determine_explicit_self_category<'tcx, AC: AstConv<'tcx>,
pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>(
this: &AC,
id: ast::NodeId,
fn_style: ast::FnStyle,
onceness: ast::Onceness,
bounds: ty::ExistentialBounds,
@ -1300,13 +1280,14 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>(
expected_sig: Option<ty::FnSig>)
-> ty::ClosureTy
{
debug!("ty_of_fn_decl");
debug!("ty_of_closure(expected_sig={})",
expected_sig.repr(this.tcx()));
// new region names that appear inside of the fn decl are bound to
// that function type
let rb = rscope::BindingRscope::new(id);
let rb = rscope::BindingRscope::new();
let input_tys = decl.inputs.iter().enumerate().map(|(i, a)| {
let input_tys: Vec<_> = decl.inputs.iter().enumerate().map(|(i, a)| {
let expected_arg_ty = expected_sig.as_ref().and_then(|e| {
// no guarantee that the correct number of expected args
// were supplied
@ -1331,14 +1312,16 @@ pub fn ty_of_closure<'tcx, AC: AstConv<'tcx>>(
ast::NoReturn(_) => ty::FnDiverging
};
debug!("ty_of_closure: input_tys={}", input_tys.repr(this.tcx()));
debug!("ty_of_closure: output_ty={}", output_ty.repr(this.tcx()));
ty::ClosureTy {
fn_style: fn_style,
onceness: onceness,
store: store,
bounds: bounds,
abi: abi,
sig: ty::FnSig {binder_id: id,
inputs: input_tys,
sig: ty::FnSig {inputs: input_tys,
output: output_ty,
variadic: decl.variadic}
}

View File

@ -528,9 +528,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
// First, we have to replace any bound regions in the fn type with free ones.
// The free region references will be bound the node_id of the body block.
let (_, fn_sig) = replace_late_bound_regions(tcx, fn_sig.binder_id, fn_sig, |br| {
ty::ReFree(ty::FreeRegion {scope_id: body.id, bound_region: br})
});
let fn_sig = liberate_late_bound_regions(tcx, body.id, fn_sig);
let arg_tys = fn_sig.inputs.as_slice();
let ret_ty = fn_sig.output;
@ -3031,7 +3029,6 @@ fn check_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,

View File

@ -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),

View File

@ -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;
}

View File

@ -214,12 +214,11 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt,
for variant in variants.iter() {
// Nullary enum constructors get turned into constants; n-ary enum
// constructors get turned into functions.
let scope = variant.node.id;
let result_ty = match variant.node.kind {
ast::TupleVariantKind(ref args) if args.len() > 0 => {
let rs = ExplicitRscope;
let input_tys: Vec<_> = args.iter().map(|va| ccx.to_ty(&rs, &*va.ty)).collect();
ty::mk_ctor_fn(tcx, scope, input_tys.as_slice(), enum_ty)
ty::mk_ctor_fn(tcx, input_tys.as_slice(), enum_ty)
}
ast::TupleVariantKind(_) => {
@ -403,7 +402,6 @@ fn 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}
});

View File

@ -334,48 +334,6 @@ pub fn expected_found<'tcx, C: Combine<'tcx>, T>(
}
}
pub fn super_fn_sigs<'tcx, C: Combine<'tcx>>(this: &C,
a: &ty::FnSig,
b: &ty::FnSig)
-> cres<ty::FnSig> {
fn argvecs<'tcx, C: Combine<'tcx>>(this: &C,
a_args: &[ty::t],
b_args: &[ty::t])
-> cres<Vec<ty::t>> {
if a_args.len() == b_args.len() {
a_args.iter().zip(b_args.iter())
.map(|(a, b)| this.args(*a, *b)).collect()
} else {
Err(ty::terr_arg_count)
}
}
if a.variadic != b.variadic {
return Err(ty::terr_variadic_mismatch(expected_found(this, a.variadic, b.variadic)));
}
let inputs = try!(argvecs(this,
a.inputs.as_slice(),
b.inputs.as_slice()));
let output = try!(match (a.output, b.output) {
(ty::FnConverging(a_ty), ty::FnConverging(b_ty)) =>
Ok(ty::FnConverging(try!(this.tys(a_ty, b_ty)))),
(ty::FnDiverging, ty::FnDiverging) =>
Ok(ty::FnDiverging),
(a, b) =>
Err(ty::terr_convergence_mismatch(
expected_found(this, a != ty::FnDiverging, b != ty::FnDiverging)
)),
});
Ok(FnSig {binder_id: a.binder_id,
inputs: inputs,
output: output,
variadic: a.variadic})
}
pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
let tcx = this.infcx().tcx;

View File

@ -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)
}
}

View File

@ -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()

View File

@ -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 {

View File

@ -383,7 +383,6 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
fn_style: ast::NormalFn,
abi: abi::Rust,
sig: ty::FnSig {
binder_id: main_id,
inputs: Vec::new(),
output: ty::FnConverging(ty::mk_nil(tcx)),
variadic: false
@ -432,7 +431,6 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
fn_style: ast::NormalFn,
abi: abi::Rust,
sig: ty::FnSig {
binder_id: start_id,
inputs: vec!(
ty::mk_int(),
ty::mk_imm_ptr(tcx, ty::mk_imm_ptr(tcx, ty::mk_u8()))

View File

@ -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))
}
}

View File

@ -252,8 +252,7 @@ pub fn vec_map_to_string<T>(ts: &[T], f: |t: &T| -> String) -> String {
}
pub fn fn_sig_to_string(cx: &ctxt, typ: &ty::FnSig) -> String {
format!("fn{}{} -> {}", typ.binder_id, typ.inputs.repr(cx),
typ.output.repr(cx))
format!("fn{} -> {}", typ.inputs.repr(cx), typ.output.repr(cx))
}
pub fn trait_ref_to_string(cx: &ctxt, trait_ref: &ty::TraitRef) -> String {
@ -262,11 +261,11 @@ pub fn trait_ref_to_string(cx: &ctxt, trait_ref: &ty::TraitRef) -> String {
pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
fn bare_fn_to_string(cx: &ctxt,
fn_style: ast::FnStyle,
abi: abi::Abi,
ident: Option<ast::Ident>,
sig: &ty::FnSig)
-> String {
fn_style: ast::FnStyle,
abi: abi::Abi,
ident: Option<ast::Ident>,
sig: &ty::FnSig)
-> String {
let mut s = String::new();
match fn_style {
ast::NormalFn => {}
@ -1301,3 +1300,8 @@ 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))
}
}

View File

@ -14,9 +14,6 @@
*/
// This is only used by tests, hence allow dead code.
#![allow(dead_code)]
use driver::diagnostic;
use driver::diagnostic::Emitter;
use driver::driver;
@ -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);
})
}

View File

@ -269,7 +269,6 @@ pub fn trans_unboxing_shim(bcx: Block,
let self_type = fty.sig.inputs[0];
let boxed_self_type = ty::mk_uniq(tcx, self_type);
let boxed_function_type = ty::FnSig {
binder_id: fty.sig.binder_id,
inputs: fty.sig.inputs.iter().enumerate().map(|(i, typ)| {
if i == 0 {
boxed_self_type
@ -294,7 +293,6 @@ pub fn trans_unboxing_shim(bcx: Block,
// RustCall so the untupled arguments can be passed
// through verbatim. This is kind of ugly.
let fake_ty = ty::FnSig {
binder_id: fty.sig.binder_id,
inputs: type_of::untuple_arguments_if_necessary(ccx,
fty.sig.inputs.as_slice(),
fty.abi),

View File

@ -609,9 +609,6 @@ pub fn get_vtable(bcx: Block,
fn_style: closure_info.closure_type.fn_style,
abi: Rust,
sig: ty::FnSig {
binder_id: closure_info.closure_type
.sig
.binder_id,
inputs: new_inputs,
output: new_output,
variadic: false,