}
}
-fn parse_trait_store_<F>(st: &mut PState, conv: &mut F) -> ty::TraitStore where
- F: FnMut(DefIdSource, ast::DefId) -> ast::DefId,
-{
- match next(st) {
- '~' => ty::UniqTraitStore,
- '&' => ty::RegionTraitStore(parse_region_(st, conv), parse_mutability(st)),
- c => {
- st.tcx.sess.bug(&format!("parse_trait_store(): bad input '{}'",
- c)[])
- }
- }
-}
-
fn parse_vec_per_param_space<'a, 'tcx, T, F>(st: &mut PState<'a, 'tcx>,
mut f: F)
-> VecPerParamSpace<T> where
{
let unsafety = parse_unsafety(next(st));
let onceness = parse_onceness(next(st));
- let store = parse_trait_store_(st, conv);
let bounds = parse_existential_bounds_(st, conv);
let sig = parse_sig_(st, conv);
let abi = parse_abi_set(st);
ty::ClosureTy {
unsafety: unsafety,
onceness: onceness,
- store: store,
bounds: bounds,
sig: sig,
abi: abi,
enc_substs(w, cx, s.substs);
}
-pub fn enc_trait_store(w: &mut SeekableMemWriter, cx: &ctxt, s: ty::TraitStore) {
- match s {
- ty::UniqTraitStore => mywrite!(w, "~"),
- ty::RegionTraitStore(re, m) => {
- mywrite!(w, "&");
- enc_region(w, cx, re);
- enc_mutability(w, m);
- }
- }
-}
-
fn enc_unsafety(w: &mut SeekableMemWriter, p: ast::Unsafety) {
match p {
ast::Unsafety::Normal => mywrite!(w, "n"),
ft: &ty::ClosureTy<'tcx>) {
enc_unsafety(w, ft.unsafety);
enc_onceness(w, ft.onceness);
- enc_trait_store(w, cx, ft.store);
enc_existential_bounds(w, cx, &ft.bounds);
enc_fn_sig(w, cx, &ft.sig);
enc_abi(w, ft.abi);
}
}
-impl tr for ty::TraitStore {
- fn tr(&self, dcx: &DecodeContext) -> ty::TraitStore {
- match *self {
- ty::RegionTraitStore(r, m) => {
- ty::RegionTraitStore(r.tr(dcx), m)
- }
- ty::UniqTraitStore => ty::UniqTraitStore
- }
- }
-}
-
// ______________________________________________________________________
// Encoding and decoding of freevar information
sig: sig})
}
- fn closure_tys(&self, a: &ty::ClosureTy<'tcx>,
- b: &ty::ClosureTy<'tcx>) -> cres<'tcx, ty::ClosureTy<'tcx>> {
-
- let store = match (a.store, b.store) {
- (ty::RegionTraitStore(a_r, a_m),
- ty::RegionTraitStore(b_r, b_m)) if a_m == b_m => {
- let r = try!(self.contraregions(a_r, b_r));
- ty::RegionTraitStore(r, a_m)
- }
-
- _ if a.store == b.store => {
- a.store
- }
-
- _ => {
- return Err(ty::terr_sigil_mismatch(expected_found(self, a.store, b.store)))
- }
- };
- let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety));
- let onceness = try!(self.oncenesses(a.onceness, b.onceness));
- let bounds = try!(self.existential_bounds(&a.bounds, &b.bounds));
- let sig = try!(self.binders(&a.sig, &b.sig));
- let abi = try!(self.abi(a.abi, b.abi));
- Ok(ty::ClosureTy {
- unsafety: unsafety,
- onceness: onceness,
- store: store,
- bounds: bounds,
- sig: sig,
- abi: abi,
- })
- }
-
fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) -> cres<'tcx, ty::FnSig<'tcx>> {
if a.variadic != b.variadic {
return Err(ty::terr_variadic_mismatch(expected_found(self, a.variadic, b.variadic)));
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>;
- fn trait_stores(&self,
- vk: ty::terr_vstore_kind,
- a: ty::TraitStore,
- b: ty::TraitStore)
- -> cres<'tcx, ty::TraitStore> {
- debug!("{}.trait_stores(a={:?}, b={:?})", self.tag(), a, b);
-
- match (a, b) {
- (ty::RegionTraitStore(a_r, a_m),
- ty::RegionTraitStore(b_r, b_m)) if a_m == b_m => {
- self.contraregions(a_r, b_r).and_then(|r| {
- Ok(ty::RegionTraitStore(r, a_m))
- })
- }
-
- _ if a == b => {
- Ok(a)
- }
-
- _ => {
- Err(ty::terr_trait_stores_differ(vk, expected_found(self, a, b)))
- }
- }
- }
-
fn trait_refs(&self,
a: &ty::TraitRef<'tcx>,
b: &ty::TraitRef<'tcx>)
pub use self::InferRegion::*;
pub use self::ImplOrTraitItemId::*;
pub use self::UnboxedClosureKind::*;
-pub use self::TraitStore::*;
pub use self::ast_ty_to_ty_cache_entry::*;
pub use self::Variance::*;
pub use self::AutoAdjustment::*;
use middle::ty_fold::{self, TypeFoldable, TypeFolder};
use middle::ty_walk::TypeWalker;
use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string};
-use util::ppaux::{trait_store_to_string, ty_to_string};
+use util::ppaux::ty_to_string;
use util::ppaux::{Repr, UserString};
use util::common::{memoized, ErrorReported};
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
pub mutbl: ast::Mutability,
}
-#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Show)]
-pub enum TraitStore {
- /// Box<Trait>
- UniqTraitStore,
- /// &Trait and &mut Trait
- RegionTraitStore(Region, ast::Mutability),
-}
-
#[derive(Clone, Copy, Show)]
pub struct field_ty {
pub name: Name,
pub struct ClosureTy<'tcx> {
pub unsafety: ast::Unsafety,
pub onceness: ast::Onceness,
- pub store: TraitStore,
pub bounds: ExistentialBounds<'tcx>,
pub sig: PolyFnSig<'tcx>,
pub abi: abi::Abi,
terr_onceness_mismatch(expected_found<Onceness>),
terr_abi_mismatch(expected_found<abi::Abi>),
terr_mutability,
- terr_sigil_mismatch(expected_found<TraitStore>),
terr_box_mutability,
terr_ptr_mutability,
terr_ref_mutability,
terr_regions_no_overlap(Region, Region),
terr_regions_insufficiently_polymorphic(BoundRegion, Region),
terr_regions_overly_polymorphic(BoundRegion, Region),
- terr_trait_stores_differ(terr_vstore_kind, expected_found<TraitStore>),
terr_sorts(expected_found<Ty<'tcx>>),
terr_integer_as_char,
terr_int_mismatch(expected_found<IntVarValue>),
ty_fn_sig(fty).inputs()
}
-pub fn ty_closure_store(fty: Ty) -> TraitStore {
- match fty.sty {
- ty_unboxed_closure(..) => {
- // Close enough for the purposes of all the callers of this
- // function (which is soon to be deprecated anyhow).
- UniqTraitStore
- }
- ref s => {
- panic!("ty_closure_store() called on non-closure type: {:?}", s)
- }
- }
-}
-
pub fn ty_fn_ret<'tcx>(fty: Ty<'tcx>) -> Binder<FnOutput<'tcx>> {
match fty.sty {
ty_bare_fn(_, ref f) => f.sig.output(),
/// afterwards to present additional details, particularly when it comes to lifetime-related
/// errors.
pub fn type_err_to_str<'tcx>(cx: &ctxt<'tcx>, err: &type_err<'tcx>) -> String {
- fn tstore_to_closure(s: &TraitStore) -> String {
- match s {
- &UniqTraitStore => "proc".to_string(),
- &RegionTraitStore(..) => "closure".to_string()
- }
- }
-
match *err {
terr_cyclic_ty => "cyclic type of infinite size".to_string(),
terr_mismatch => "types differ".to_string(),
values.expected,
values.found)
}
- terr_sigil_mismatch(values) => {
- format!("expected {}, found {}",
- tstore_to_closure(&values.expected),
- tstore_to_closure(&values.found))
- }
terr_mutability => "values differ in mutability".to_string(),
terr_box_mutability => {
"boxed values differ in mutability".to_string()
found bound lifetime parameter {}",
bound_region_ptr_to_string(cx, br))
}
- terr_trait_stores_differ(_, ref values) => {
- format!("trait storage differs: expected `{}`, found `{}`",
- trait_store_to_string(cx, (*values).expected),
- trait_store_to_string(cx, (*values).found))
- }
terr_sorts(values) => {
// A naive approach to making sure that we're not reporting silly errors such as:
// (expected closure, found closure).
impl<'tcx> Repr<'tcx> for ClosureTy<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
- format!("ClosureTy({},{},{:?},{},{},{})",
+ format!("ClosureTy({},{},{},{},{})",
self.unsafety,
self.onceness,
- self.store,
self.bounds.repr(tcx),
self.sig.repr(tcx),
self.abi)
r
}
- fn fold_trait_store(&mut self, s: ty::TraitStore) -> ty::TraitStore {
- super_fold_trait_store(self, s)
- }
-
fn fold_existential_bounds(&mut self, s: &ty::ExistentialBounds<'tcx>)
-> ty::ExistentialBounds<'tcx> {
super_fold_existential_bounds(self, s)
}
}
-impl<'tcx> TypeFoldable<'tcx> for ty::TraitStore {
- fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::TraitStore {
- folder.fold_trait_store(*self)
- }
-}
-
impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Ty<'tcx> {
folder.fold_ty(*self)
-> ty::ClosureTy<'tcx>
{
ty::ClosureTy {
- store: fty.store.fold_with(this),
sig: fty.sig.fold_with(this),
unsafety: fty.unsafety,
onceness: fty.onceness,
mutbl: mt.mutbl}
}
-pub fn super_fold_trait_store<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
- trait_store: ty::TraitStore)
- -> ty::TraitStore {
- match trait_store {
- ty::UniqTraitStore => ty::UniqTraitStore,
- ty::RegionTraitStore(r, m) => {
- ty::RegionTraitStore(r.fold_with(this), m)
- }
- }
-}
-
pub fn super_fold_existential_bounds<'tcx, T: TypeFolder<'tcx>>(
this: &mut T,
bounds: &ty::ExistentialBounds<'tcx>)
ty_to_string(cx, m.ty))
}
-pub fn trait_store_to_string(cx: &ctxt, s: ty::TraitStore) -> String {
- match s {
- ty::UniqTraitStore => "Box ".to_string(),
- ty::RegionTraitStore(r, m) => {
- format!("{}{}", region_ptr_to_string(cx, r), mutability_to_string(m))
- }
- }
-}
-
pub fn vec_map_to_string<T, F>(ts: &[T], f: F) -> String where
F: FnMut(&T) -> String,
{
fn closure_to_string<'tcx>(cx: &ctxt<'tcx>, cty: &ty::ClosureTy<'tcx>) -> String {
let mut s = String::new();
- match cty.store {
- ty::UniqTraitStore => {}
- ty::RegionTraitStore(region, _) => {
- s.push_str(®ion_to_string(cx, "", true, region)[]);
- }
- }
-
match cty.unsafety {
ast::Unsafety::Normal => {}
ast::Unsafety::Unsafe => {
let bounds_str = cty.bounds.user_string(cx);
- match cty.store {
- ty::UniqTraitStore => {
- assert_eq!(cty.onceness, ast::Once);
- s.push_str("proc");
- push_sig_to_string(cx, &mut s, '(', ')', &cty.sig,
- &bounds_str[]);
- }
- ty::RegionTraitStore(..) => {
- match cty.onceness {
- ast::Many => {}
- ast::Once => s.push_str("once ")
- }
- push_sig_to_string(cx, &mut s, '|', '|', &cty.sig,
- &bounds_str[]);
- }
+ match cty.onceness {
+ ast::Many => {}
+ ast::Once => s.push_str("once ")
}
+ push_sig_to_string(cx, &mut s, '|', '|', &cty.sig,
+ &bounds_str[]);
s
}
}
}
-impl<'tcx> Repr<'tcx> for ty::TraitStore {
- fn repr(&self, tcx: &ctxt) -> String {
- trait_store_to_string(tcx, *self)
- }
-}
-
impl<'tcx> Repr<'tcx> for ty::BuiltinBound {
fn repr(&self, _tcx: &ctxt) -> String {
format!("{:?}", *self)
}
}
-// Returns a pointer to the body for the box. The box may be an opaque
-// box. The result will be casted to the type of body_t, if it is statically
-// known.
-pub fn at_box_body<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- body_t: Ty<'tcx>, boxptr: ValueRef) -> ValueRef {
- let _icx = push_ctxt("at_box_body");
- let ccx = bcx.ccx();
- let ty = Type::at_box(ccx, type_of(ccx, body_t));
- let boxptr = PointerCast(bcx, boxptr, ty.ptr_to());
- GEPi(bcx, boxptr, &[0u, abi::BOX_FIELD_BODY])
-}
-
fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
info_ty: Ty<'tcx>, it: LangItem) -> ast::DefId {
match bcx.tcx().lang_items.require(it) {
.map(|arg| node_id_type(bcx, arg.id))
.collect::<Vec<_>>();
let monomorphized_arg_types = match closure_env.kind {
- closure::NotClosure | closure::BoxedClosure(..) => {
+ closure::NotClosure => {
monomorphized_arg_types
}
};
bcx = match closure_env.kind {
- closure::NotClosure | closure::BoxedClosure(..) => {
+ closure::NotClosure => {
copy_args_to_allocas(bcx,
arg_scope,
&decl.inputs[],
pub use self::ClosureKind::*;
-use back::abi;
use back::link::mangle_internal_name_by_path_and_seq;
-use llvm::ValueRef;
use middle::mem_categorization::Typer;
use trans::adt;
use trans::base::*;
use trans::build::*;
use trans::cleanup::{CleanupMethods, ScopeId};
use trans::common::*;
-use trans::datum::{Datum, Lvalue, rvalue_scratch_datum};
+use trans::datum::{Datum, rvalue_scratch_datum};
use trans::datum::{Rvalue, ByValue};
use trans::debuginfo;
use trans::expr;
use trans::monomorphize::{self, MonoId};
use trans::type_of::*;
-use trans::type_::Type;
-use middle::ty::{self, Ty, UnboxedClosureTyper};
+use middle::ty::{self, UnboxedClosureTyper};
use middle::subst::{Substs};
use session::config::FullDebugInfo;
-use util::ppaux::ty_to_string;
use syntax::ast;
use syntax::ast_util;
-// ___Good to know (tm)__________________________________________________
-//
-// The layout of a closure environment in memory is
-// roughly as follows:
-//
-// struct rust_opaque_box { // see rust_internal.h
-// unsigned ref_count; // obsolete (part of @T's header)
-// fn(void*) *drop_glue; // destructor (for proc)
-// rust_opaque_box *prev; // obsolete (part of @T's header)
-// rust_opaque_box *next; // obsolete (part of @T's header)
-// struct closure_data {
-// upvar1_t upvar1;
-// ...
-// upvarN_t upvarN;
-// }
-// };
-//
-// Note that the closure is itself a rust_opaque_box. This is true
-// even for ~fn and ||, because we wish to keep binary compatibility
-// between all kinds of closures. The allocation strategy for this
-// closure depends on the closure type. For a sendfn, the closure
-// (and the referenced type descriptors) will be allocated in the
-// exchange heap. For a fn, the closure is allocated in the task heap
-// and is reference counted. For a block, the closure is allocated on
-// the stack.
-//
-// ## Opaque closures and the embedded type descriptor ##
-//
-// One interesting part of closures is that they encapsulate the data
-// that they close over. So when I have a ptr to a closure, I do not
-// know how many type descriptors it contains nor what upvars are
-// captured within. That means I do not know precisely how big it is
-// nor where its fields are located. This is called an "opaque
-// closure".
-//
-// Typically an opaque closure suffices because we only manipulate it
-// by ptr. The routine Type::at_box().ptr_to() returns an appropriate
-// type for such an opaque closure; it allows access to the box fields,
-// but not the closure_data itself.
-//
-// But sometimes, such as when cloning or freeing a closure, we need
-// to know the full information. That is where the type descriptor
-// that defines the closure comes in handy. We can use its take and
-// drop glue functions to allocate/free data as needed.
-//
-// ## Subtleties concerning alignment ##
-//
-// It is important that we be able to locate the closure data *without
-// knowing the kind of data that is being bound*. This can be tricky
-// because the alignment requirements of the bound data affects the
-// alignment requires of the closure_data struct as a whole. However,
-// right now this is a non-issue in any case, because the size of the
-// rust_opaque_box header is always a multiple of 16-bytes, which is
-// the maximum alignment requirement we ever have to worry about.
-//
-// The only reason alignment matters is that, in order to learn what data
-// is bound, we would normally first load the type descriptors: but their
-// location is ultimately depend on their content! There is, however, a
-// workaround. We can load the tydesc from the rust_opaque_box, which
-// describes the closure_data struct and has self-contained derived type
-// descriptors, and read the alignment from there. It's just annoying to
-// do. Hopefully should this ever become an issue we'll have monomorphized
-// and type descriptors will all be a bad dream.
-//
-// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-#[derive(Copy)]
-pub struct EnvValue<'tcx> {
- action: ast::CaptureClause,
- datum: Datum<'tcx, Lvalue>
-}
-
-impl<'tcx> EnvValue<'tcx> {
- pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
- format!("{:?}({})", self.action, self.datum.to_string(ccx))
- }
-}
-
-// Given a closure ty, emits a corresponding tuple ty
-pub fn mk_closure_tys<'tcx>(tcx: &ty::ctxt<'tcx>,
- bound_values: &[EnvValue<'tcx>])
- -> Ty<'tcx> {
- // determine the types of the values in the env. Note that this
- // is the actual types that will be stored in the map, not the
- // logical types as the user sees them, so by-ref upvars must be
- // converted to ptrs.
- let bound_tys = bound_values.iter().map(|bv| {
- match bv.action {
- ast::CaptureByValue => bv.datum.ty,
- ast::CaptureByRef => ty::mk_mut_ptr(tcx, bv.datum.ty)
- }
- }).collect();
- let cdata_ty = ty::mk_tup(tcx, bound_tys);
- debug!("cdata_ty={}", ty_to_string(tcx, cdata_ty));
- return cdata_ty;
-}
-
-fn tuplify_box_ty<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> Ty<'tcx> {
- let ptr = ty::mk_imm_ptr(tcx, tcx.types.i8);
- ty::mk_tup(tcx, vec!(tcx.types.uint, ty::mk_nil_ptr(tcx), ptr, ptr, t))
-}
-
-pub struct ClosureResult<'blk, 'tcx: 'blk> {
- llbox: ValueRef, // llvalue of ptr to closure
- cdata_ty: Ty<'tcx>, // type of the closure data
- bcx: Block<'blk, 'tcx> // final bcx
-}
-
-// Given a block context and a list of tydescs and values to bind
-// construct a closure out of them. If copying is true, it is a
-// heap allocated closure that copies the upvars into environment.
-// Otherwise, it is stack allocated and copies pointers to the upvars.
-pub fn store_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- bound_values: Vec<EnvValue<'tcx>>)
- -> ClosureResult<'blk, 'tcx> {
- let _icx = push_ctxt("closure::store_environment");
- let ccx = bcx.ccx();
- let tcx = ccx.tcx();
-
- // compute the type of the closure
- let cdata_ty = mk_closure_tys(tcx, &bound_values[]);
-
- // cbox_ty has the form of a tuple: (a, b, c) we want a ptr to a
- // tuple. This could be a ptr in uniq or a box or on stack,
- // whatever.
- let cbox_ty = tuplify_box_ty(tcx, cdata_ty);
- let cboxptr_ty = ty::mk_ptr(tcx, ty::mt {ty:cbox_ty, mutbl:ast::MutImmutable});
- let llboxptr_ty = type_of(ccx, cboxptr_ty);
-
- // If there are no bound values, no point in allocating anything.
- if bound_values.is_empty() {
- return ClosureResult {llbox: C_null(llboxptr_ty),
- cdata_ty: cdata_ty,
- bcx: bcx};
- }
-
- // allocate closure in the heap
- let llbox = alloc_ty(bcx, cbox_ty, "__closure");
-
- let llbox = PointerCast(bcx, llbox, llboxptr_ty);
- debug!("tuplify_box_ty = {}", ty_to_string(tcx, cbox_ty));
-
- // Copy expr values into boxed bindings.
- let mut bcx = bcx;
- for (i, bv) in bound_values.into_iter().enumerate() {
- debug!("Copy {} into closure", bv.to_string(ccx));
-
- if ccx.sess().asm_comments() {
- add_comment(bcx, &format!("Copy {} into closure",
- bv.to_string(ccx))[]);
- }
-
- let bound_data = GEPi(bcx, llbox, &[0u, abi::BOX_FIELD_BODY, i]);
-
- match bv.action {
- ast::CaptureByValue => {
- bcx = bv.datum.store_to(bcx, bound_data);
- }
- ast::CaptureByRef => {
- Store(bcx, bv.datum.to_llref(), bound_data);
- }
- }
- }
-
- ClosureResult { llbox: llbox, cdata_ty: cdata_ty, bcx: bcx }
-}
-
-// Given a context and a list of upvars, build a closure. This just
-// collects the upvars and packages them up for store_environment.
-fn build_closure<'blk, 'tcx>(bcx0: Block<'blk, 'tcx>,
- freevar_mode: ast::CaptureClause,
- freevars: &Vec<ty::Freevar>)
- -> ClosureResult<'blk, 'tcx> {
- let _icx = push_ctxt("closure::build_closure");
-
- // If we need to, package up the iterator body to call
- let bcx = bcx0;
-
- // Package up the captured upvars
- let mut env_vals = Vec::new();
- for freevar in freevars.iter() {
- let datum = expr::trans_local_var(bcx, freevar.def);
- env_vals.push(EnvValue {action: freevar_mode, datum: datum});
- }
-
- store_environment(bcx, env_vals)
-}
-
-// Given an enclosing block context, a new function context, a closure type,
-// and a list of upvars, generate code to load and populate the environment
-// with the upvars and type descriptors.
-fn load_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- cdata_ty: Ty<'tcx>,
- freevars: &[ty::Freevar],
- store: ty::TraitStore)
- -> Block<'blk, 'tcx> {
- let _icx = push_ctxt("closure::load_environment");
-
- // Load a pointer to the closure data, skipping over the box header:
- let llcdata = at_box_body(bcx, cdata_ty, bcx.fcx.llenv.unwrap());
-
- // Store the pointer to closure data in an alloca for debug info because that's what the
- // llvm.dbg.declare intrinsic expects
- let env_pointer_alloca = if bcx.sess().opts.debuginfo == FullDebugInfo {
- let alloc = alloc_ty(bcx, ty::mk_mut_ptr(bcx.tcx(), cdata_ty), "__debuginfo_env_ptr");
- Store(bcx, llcdata, alloc);
- Some(alloc)
- } else {
- None
- };
-
- // Populate the upvars from the environment
- let mut i = 0u;
- for freevar in freevars.iter() {
- let mut upvarptr = GEPi(bcx, llcdata, &[0u, i]);
- let captured_by_ref = match store {
- ty::RegionTraitStore(..) => {
- upvarptr = Load(bcx, upvarptr);
- true
- }
- ty::UniqTraitStore => false
- };
- let def_id = freevar.def.def_id();
-
- bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvarptr);
- if let Some(env_pointer_alloca) = env_pointer_alloca {
- debuginfo::create_captured_var_metadata(
- bcx,
- def_id.node,
- env_pointer_alloca,
- i,
- captured_by_ref,
- freevar.span);
- }
-
- i += 1u;
- }
-
- bcx
-}
fn load_unboxed_closure_environment<'blk, 'tcx>(
bcx: Block<'blk, 'tcx>,
freevar_mode: ast::CaptureClause,
freevars: &[ty::Freevar])
-> Block<'blk, 'tcx> {
- let _icx = push_ctxt("closure::load_environment");
+ let _icx = push_ctxt("closure::load_unboxed_closure_environment");
// Special case for small by-value selfs.
let closure_id = ast_util::local_def(bcx.fcx.id);
bcx
}
-fn fill_fn_pair(bcx: Block, pair: ValueRef, llfn: ValueRef, llenvptr: ValueRef) {
- Store(bcx, llfn, GEPi(bcx, pair, &[0u, abi::FAT_PTR_ADDR]));
- let llenvptr = PointerCast(bcx, llenvptr, Type::i8p(bcx.ccx()));
- Store(bcx, llenvptr, GEPi(bcx, pair, &[0u, abi::FAT_PTR_EXTRA]));
-}
-
#[derive(PartialEq)]
pub enum ClosureKind<'tcx> {
NotClosure,
- // See load_environment.
- BoxedClosure(Ty<'tcx>, ty::TraitStore),
// See load_unboxed_closure_environment.
UnboxedClosure(ast::CaptureClause)
}
match self.kind {
NotClosure => bcx,
- BoxedClosure(cdata_ty, store) => {
- load_environment(bcx, cdata_ty, self.freevars, store)
- }
UnboxedClosure(freevar_mode) => {
load_unboxed_closure_environment(bcx, arg_scope, freevar_mode, self.freevars)
}
}
}
-/// Translates the body of a closure expression.
-///
-/// - `store`
-/// - `decl`
-/// - `body`
-/// - `id`: The id of the closure expression.
-/// - `cap_clause`: information about captured variables, if any.
-/// - `dest`: where to write the closure value, which must be a
-/// (fn ptr, env) pair
-pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- store: ty::TraitStore,
- decl: &ast::FnDecl,
- body: &ast::Block,
- id: ast::NodeId,
- dest: expr::Dest)
- -> Block<'blk, 'tcx> {
- let _icx = push_ctxt("closure::trans_expr_fn");
-
- let dest_addr = match dest {
- expr::SaveIn(p) => p,
- expr::Ignore => {
- return bcx; // closure construction is non-side-effecting
- }
- };
-
- let ccx = bcx.ccx();
- let tcx = bcx.tcx();
- let fty = node_id_type(bcx, id);
- let s = tcx.map.with_path(id, |path| {
- mangle_internal_name_by_path_and_seq(path, "closure")
- });
- let llfn = decl_internal_rust_fn(ccx, fty, &s[]);
-
- // set an inline hint for all closures
- set_inline_hint(llfn);
-
- let freevar_mode = tcx.capture_mode(id);
- let freevars: Vec<ty::Freevar> =
- ty::with_freevars(tcx, id, |fv| fv.iter().map(|&fv| fv).collect());
-
- let ClosureResult {
- llbox,
- cdata_ty,
- bcx
- } = build_closure(bcx, freevar_mode, &freevars);
-
- trans_closure(ccx,
- decl,
- body,
- llfn,
- bcx.fcx.param_substs,
- id,
- &[],
- ty::erase_late_bound_regions(ccx.tcx(), &ty::ty_fn_ret(fty)),
- ty::ty_fn_abi(fty),
- ClosureEnv::new(&freevars[],
- BoxedClosure(cdata_ty, store)));
- fill_fn_pair(bcx, dest_addr, llfn, llbox);
- bcx
-}
-
/// Returns the LLVM function declaration for an unboxed closure, creating it
/// if necessary. If the ID does not correspond to a closure ID, returns None.
pub fn get_or_create_declaration_if_unboxed_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
unique_type_id: &mut String) {
let ty::ClosureTy { unsafety,
onceness,
- store,
ref bounds,
ref sig,
abi: _ } = closure_ty;
unique_type_id.push_str("once ");
}
- match store {
- ty::UniqTraitStore => unique_type_id.push_str("~|"),
- ty::RegionTraitStore(_, ast::MutMutable) => {
- unique_type_id.push_str("&mut|")
- }
- ty::RegionTraitStore(_, ast::MutImmutable) => {
- unique_type_id.push_str("&|")
- }
- };
+ unique_type_id.push_str("|");
let sig = ty::erase_late_bound_regions(cx.tcx(), sig);
use trans::type_::Type;
use syntax::{ast, ast_util, codemap};
-use syntax::print::pprust::{expr_to_string};
use syntax::ptr::P;
use syntax::parse::token;
use std::rc::Rc;
// closure or an older, legacy style closure. Store this
// into a variable to ensure the the RefCell-lock is
// released before we recurse.
- let is_unboxed_closure =
- bcx.tcx().unboxed_closures.borrow().contains_key(&ast_util::local_def(expr.id));
- if is_unboxed_closure {
- closure::trans_unboxed_closure(bcx, &**decl, &**body, expr.id, dest)
- } else {
- let expr_ty = expr_ty(bcx, expr);
- let store = ty::ty_closure_store(expr_ty);
- debug!("translating block function {} with type {}",
- expr_to_string(expr), expr_ty.repr(tcx));
- closure::trans_expr_fn(bcx, store, &**decl, &**body, expr.id, dest)
- }
+ closure::trans_unboxed_closure(bcx, &**decl, &**body, expr.id, dest)
}
ast::ExprCall(ref f, ref args) => {
if bcx.tcx().is_method_call(expr.id) {
Type::vec(ccx, &Type::i8(ccx))
}
- // The box pointed to by @T.
- pub fn at_box(ccx: &CrateContext, ty: Type) -> Type {
- Type::struct_(ccx, &[
- ccx.int_type(), Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to(),
- Type::i8p(ccx), Type::i8p(ccx), ty
- ], false)
- }
-
pub fn vtable_ptr(ccx: &CrateContext) -> Type {
Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to()
}
unsafety: ast::Unsafety,
onceness: ast::Onceness,
bounds: ty::ExistentialBounds<'tcx>,
- store: ty::TraitStore,
decl: &ast::FnDecl,
abi: abi::Abi,
expected_sig: Option<ty::FnSig<'tcx>>)
ty::ClosureTy {
unsafety: unsafety,
onceness: onceness,
- store: store,
bounds: bounds,
abi: abi,
sig: ty::Binder(ty::FnSig {inputs: input_tys,
//
// FIXME(pcwalton): Refactor this API.
ty::region_existential_bound(ty::ReStatic),
- ty::RegionTraitStore(ty::ReStatic, ast::MutImmutable),
decl,
abi::RustCall,