From febdb49e9269724058aacf645610912bf26ecdb4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 27 Feb 2013 19:28:37 -0500 Subject: [PATCH] Change bare functions so that they are represented by a single pointer. The basic idea is that we add a new kind of adjustment, AutoAddEnv, that pads an extern fn into a closure by adding the extra NULL word. Then there are a few misc changes in trans to get the LLVM types to match up. Fixes #4808. --- src/librustc/middle/astencode.rs | 14 +- src/librustc/middle/borrowck/gather_loans.rs | 18 ++- src/librustc/middle/borrowck/mod.rs | 17 ++- src/librustc/middle/mem_categorization.rs | 46 +++--- src/librustc/middle/moves.rs | 4 +- src/librustc/middle/trans/callee.rs | 26 +++- src/librustc/middle/trans/common.rs | 6 + src/librustc/middle/trans/expr.rs | 137 ++++++++++++------ src/librustc/middle/trans/type_of.rs | 11 +- src/librustc/middle/ty.rs | 38 ++++- src/librustc/middle/typeck/check/method.rs | 18 ++- src/librustc/middle/typeck/check/mod.rs | 4 +- src/librustc/middle/typeck/check/regionck.rs | 56 ++++--- src/librustc/middle/typeck/check/writeback.rs | 24 ++- src/librustc/middle/typeck/infer/coercion.rs | 22 +-- 15 files changed, 312 insertions(+), 129 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 02cd5afc920..1b6452e977e 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -451,9 +451,17 @@ impl tr for ast::def { impl tr for ty::AutoAdjustment { fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::AutoAdjustment { - ty::AutoAdjustment { - autoderefs: self.autoderefs, - autoref: self.autoref.map(|ar| ar.tr(xcx)), + match self { + &ty::AutoAddEnv(r, s) => { + ty::AutoAddEnv(r.tr(xcx), s) + } + + &ty::AutoDerefRef(ref adr) => { + ty::AutoDerefRef(ty::AutoDerefRef { + autoderefs: adr.autoderefs, + autoref: adr.autoref.map(|ar| ar.tr(xcx)), + }) + } } } } diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs index 546e9359a32..236592874cb 100644 --- a/src/librustc/middle/borrowck/gather_loans.rs +++ b/src/librustc/middle/borrowck/gather_loans.rs @@ -299,17 +299,27 @@ impl GatherLoanCtxt { expr_repr(self.tcx(), expr), adjustment); let _i = indenter(); - match adjustment.autoref { - None => { + match *adjustment { + ty::AutoAddEnv(*) => { + debug!("autoaddenv -- no autoref"); + return; + } + + ty::AutoDerefRef( + ty::AutoDerefRef { + autoref: None, _ }) => { debug!("no autoref"); return; } - Some(ref autoref) => { + ty::AutoDerefRef( + ty::AutoDerefRef { + autoref: Some(ref autoref), + autoderefs: autoderefs}) => { let mcx = &mem_categorization_ctxt { tcx: self.tcx(), method_map: self.bccx.method_map}; - let mut cmt = mcx.cat_expr_autoderefd(expr, adjustment); + let mut cmt = mcx.cat_expr_autoderefd(expr, autoderefs); debug!("after autoderef, cmt=%s", self.bccx.cmt_to_repr(cmt)); match autoref.kind { diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 568bc5b5e70..87ff8554fd9 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -478,9 +478,20 @@ pub impl BorrowckCtxt { } fn cat_expr_autoderefd(&self, expr: @ast::expr, - adj: @ty::AutoAdjustment) - -> cmt { - cat_expr_autoderefd(self.tcx, self.method_map, expr, adj) + adj: @ty::AutoAdjustment) -> cmt { + match *adj { + ty::AutoAddEnv(*) => { + // no autoderefs + cat_expr_unadjusted(self.tcx, self.method_map, expr) + } + + ty::AutoDerefRef( + ty::AutoDerefRef { + autoderefs: autoderefs, _}) => { + cat_expr_autoderefd(self.tcx, self.method_map, expr, + autoderefs) + } + } } fn cat_def(&self, diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index f027ca99d51..e1a2079be25 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -241,12 +241,12 @@ pub fn cat_expr_autoderefd( tcx: ty::ctxt, method_map: typeck::method_map, expr: @ast::expr, - adj: @ty::AutoAdjustment) -> cmt { - + autoderefs: uint) -> cmt +{ let mcx = &mem_categorization_ctxt { tcx: tcx, method_map: method_map }; - return mcx.cat_expr_autoderefd(expr, adj); + return mcx.cat_expr_autoderefd(expr, autoderefs); } pub fn cat_def( @@ -361,28 +361,38 @@ pub impl mem_categorization_ctxt { self.cat_expr_unadjusted(expr) } - Some(adjustment) => { - match adjustment.autoref { - Some(_) => { - // Equivalent to &*expr or something similar. - // This is an rvalue, effectively. - let expr_ty = ty::expr_ty(self.tcx, expr); - self.cat_rvalue(expr, expr_ty) - } - None => { - // Equivalent to *expr or something similar. - self.cat_expr_autoderefd(expr, adjustment) - } - } + Some(@ty::AutoAddEnv(*)) => { + // Convert a bare fn to a closure by adding NULL env. + // Result is an rvalue. + let expr_ty = ty::expr_ty_adjusted(self.tcx, expr); + self.cat_rvalue(expr, expr_ty) + } + + Some( + @ty::AutoDerefRef( + ty::AutoDerefRef { + autoref: Some(_), _})) => { + // Equivalent to &*expr or something similar. + // Result is an rvalue. + let expr_ty = ty::expr_ty_adjusted(self.tcx, expr); + self.cat_rvalue(expr, expr_ty) + } + + Some( + @ty::AutoDerefRef( + ty::AutoDerefRef { + autoref: None, autoderefs: autoderefs})) => { + // Equivalent to *expr or something similar. + self.cat_expr_autoderefd(expr, autoderefs) } } } fn cat_expr_autoderefd(&self, expr: @ast::expr, - adjustment: &ty::AutoAdjustment) -> cmt { + autoderefs: uint) -> cmt { let mut cmt = self.cat_expr_unadjusted(expr); - for uint::range(1, adjustment.autoderefs+1) |deref| { + for uint::range(1, autoderefs+1) |deref| { cmt = self.cat_deref(expr, cmt, deref); } return cmt; diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index b23066c1d96..8e344c0afc7 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -410,7 +410,9 @@ impl VisitContext { // those adjustments is to take a reference, then it's only // reading the underlying expression, not moving it. let comp_mode = match self.tcx.adjustments.find(&expr.id) { - Some(adj) if adj.autoref.is_some() => Read, + Some(@ty::AutoDerefRef( + ty::AutoDerefRef { + autoref: Some(_), _})) => Read, _ => expr_mode.component_mode(expr) }; diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 6924ccf3ab6..ff37e6d76c6 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -82,10 +82,25 @@ pub fn trans(bcx: block, expr: @ast::expr) -> Callee { } // any other expressions are closures: - return closure_callee(&expr::trans_to_datum(bcx, expr)); + return datum_callee(bcx, expr); - fn closure_callee(db: &DatumBlock) -> Callee { - return Callee {bcx: db.bcx, data: Closure(db.datum)}; + fn datum_callee(bcx: block, expr: @ast::expr) -> Callee { + let DatumBlock {bcx, datum} = expr::trans_to_datum(bcx, expr); + match ty::get(datum.ty).sty { + ty::ty_bare_fn(*) => { + let llval = datum.to_appropriate_llval(bcx); + return Callee {bcx: bcx, data: Fn(FnData {llfn: llval})}; + } + ty::ty_closure(*) => { + return Callee {bcx: bcx, data: Closure(datum)}; + } + _ => { + bcx.tcx().sess.span_bug( + expr.span, + fmt!("Type of callee is neither bare-fn nor closure: %s", + bcx.ty_to_str(datum.ty))); + } + } } fn fn_callee(bcx: block, fd: FnData) -> Callee { @@ -117,7 +132,7 @@ pub fn trans(bcx: block, expr: @ast::expr) -> Callee { ast::def_binding(*) | ast::def_upvar(*) | ast::def_self(*) => { - closure_callee(&expr::trans_to_datum(bcx, ref_expr)) + datum_callee(bcx, ref_expr) } ast::def_mod(*) | ast::def_foreign_mod(*) | ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) | @@ -380,7 +395,6 @@ pub fn trans_rtcall_or_lang_call_with_type_params(bcx: block, fty); let mut llfnty = type_of::type_of(callee.bcx.ccx(), substituted); - llfnty = lib::llvm::struct_tys(llfnty)[0]; new_llval = PointerCast(callee.bcx, fn_data.llfn, llfnty); } _ => fail!() @@ -703,6 +717,8 @@ pub fn trans_arg_expr(bcx: block, } ast::by_copy => { + debug!("by copy arg with type %s, storing to scratch", + ty_to_str(ccx.tcx, arg_datum.ty)); let scratch = scratch_datum(bcx, arg_datum.ty, false); arg_datum.store_to_datum(bcx, arg_expr.id, diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 48a3d2c82c8..04fefd4fb33 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -1344,6 +1344,12 @@ pub fn expr_ty(bcx: block, ex: @ast::expr) -> ty::t { node_id_type(bcx, ex.id) } +pub fn expr_ty_adjusted(bcx: block, ex: @ast::expr) -> ty::t { + let tcx = bcx.tcx(); + let t = ty::expr_ty_adjusted(tcx, ex); + monomorphize_type(bcx, t) +} + pub fn node_id_type_params(bcx: block, id: ast::node_id) -> ~[ty::t] { let tcx = bcx.tcx(); let params = ty::node_id_to_type_params(tcx, id); diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index a7b12d13d4e..8ceb539351e 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -136,7 +136,8 @@ use middle::trans::machine; use middle::trans::meth; use middle::trans::tvec; use middle::ty::struct_mutable_fields; -use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn}; +use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn, + AutoDerefRef, AutoAddEnv}; use util::common::indenter; use util::ppaux::ty_to_str; @@ -189,7 +190,14 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { None => { trans_to_datum_unadjusted(bcx, expr) } - Some(adj) => { + Some(@AutoAddEnv(*)) => { + let mut bcx = bcx; + let mut datum = unpack_datum!(bcx, { + trans_to_datum_unadjusted(bcx, expr) + }); + add_env(bcx, expr, datum) + } + Some(@AutoDerefRef(ref adj)) => { let mut bcx = bcx; let mut datum = unpack_datum!(bcx, { trans_to_datum_unadjusted(bcx, expr) @@ -258,6 +266,25 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { DatumBlock {bcx: bcx, datum: scratch} } + fn add_env(bcx: block, expr: @ast::expr, datum: Datum) -> DatumBlock { + // This is not the most efficient thing possible; since closures + // are two words it'd be better if this were compiled in + // 'dest' mode, but I can't find a nice way to structure the + // code and keep it DRY that accommodates that use case at the + // moment. + + let tcx = bcx.tcx(); + let closure_ty = expr_ty_adjusted(bcx, expr); + debug!("add_env(closure_ty=%s)", ty_to_str(tcx, closure_ty)); + let scratch = scratch_datum(bcx, closure_ty, false); + let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]); + assert datum.appropriate_mode() == ByValue; + Store(bcx, datum.to_appropriate_llval(bcx), llfn); + let llenv = GEPi(bcx, scratch.val, [0u, abi::fn_field_box]); + Store(bcx, base::null_env_ptr(bcx), llenv); + DatumBlock {bcx: bcx, datum: scratch} + } + fn auto_slice_and_ref(bcx: block, datum: Datum) -> DatumBlock { let DatumBlock { bcx, datum } = auto_slice(bcx, datum); auto_ref(bcx, datum) @@ -412,6 +439,9 @@ fn trans_rvalue_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { trace_span!(bcx, expr.span, @shorten(bcx.expr_to_str(expr))); match expr.node { + ast::expr_path(_) => { + return trans_def_datum_unadjusted(bcx, expr, bcx.def(expr.id)); + } ast::expr_vstore(contents, ast::expr_vstore_box) | ast::expr_vstore(contents, ast::expr_vstore_mut_box) => { return tvec::trans_uniq_or_managed_vstore(bcx, heap_managed, @@ -677,22 +707,13 @@ fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr, }; match def { - ast::def_fn(did, _) | ast::def_static_method(did, None, _) => { - let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id); - return fn_data_to_datum(bcx, did, fn_data, lldest); - } - ast::def_static_method(impl_did, Some(trait_did), _) => { - let fn_data = meth::trans_static_method_callee(bcx, impl_did, - trait_did, - ref_expr.id); - return fn_data_to_datum(bcx, impl_did, fn_data, lldest); - } ast::def_variant(tid, vid) => { let variant_info = ty::enum_variant_with_id(ccx.tcx, tid, vid); if variant_info.args.len() > 0u { // N-ary variant. let fn_data = callee::trans_fn_ref(bcx, vid, ref_expr.id); - return fn_data_to_datum(bcx, vid, fn_data, lldest); + Store(bcx, fn_data.llfn, lldest); + return bcx; } else if !ty::enum_is_univariant(ccx.tcx, tid) { // Nullary variant. let lldiscrimptr = GEPi(bcx, lldest, [0u, 0u]); @@ -717,6 +738,66 @@ fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr, } } +fn trans_def_datum_unadjusted(bcx: block, + ref_expr: @ast::expr, + def: ast::def) -> DatumBlock +{ + let _icx = bcx.insn_ctxt("trans_def_datum_unadjusted"); + + match def { + ast::def_fn(did, _) | ast::def_static_method(did, None, _) => { + let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id); + return fn_data_to_datum(bcx, ref_expr, did, fn_data); + } + ast::def_static_method(impl_did, Some(trait_did), _) => { + let fn_data = meth::trans_static_method_callee(bcx, impl_did, + trait_did, + ref_expr.id); + return fn_data_to_datum(bcx, ref_expr, impl_did, fn_data); + } + _ => { + bcx.tcx().sess.span_bug(ref_expr.span, fmt!( + "Non-DPS def %? referened by %s", + def, bcx.node_id_to_str(ref_expr.id))); + } + } + + fn fn_data_to_datum(bcx: block, + ref_expr: @ast::expr, + def_id: ast::def_id, + fn_data: callee::FnData) -> DatumBlock { + /*! + * + * Translates a reference to a top-level fn item into a rust + * value. This is just a fn pointer. + */ + + let is_extern = { + let fn_tpt = ty::lookup_item_type(bcx.tcx(), def_id); + ty::ty_fn_purity(fn_tpt.ty) == ast::extern_fn + }; + let (rust_ty, llval) = if is_extern { + let rust_ty = ty::mk_ptr( + bcx.tcx(), + ty::mt { + ty: ty::mk_mach_uint(bcx.tcx(), ast::ty_u8), + mutbl: ast::m_imm + }); // *u8 + (rust_ty, PointerCast(bcx, fn_data.llfn, T_ptr(T_i8()))) + } else { + let fn_ty = expr_ty(bcx, ref_expr); + (fn_ty, fn_data.llfn) + }; + return DatumBlock { + bcx: bcx, + datum: Datum {val: llval, + ty: rust_ty, + mode: ByValue, + source: RevokeClean} + }; + } +} + fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { /*! * @@ -1004,36 +1085,6 @@ pub fn trans_local_var(bcx: block, def: ast::def) -> Datum { } } -fn fn_data_to_datum(bcx: block, - def_id: ast::def_id, - fn_data: callee::FnData, - lldest: ValueRef) -> block { - //! - // - // Translates a reference to a top-level fn item into a rust - // value. This is generally a Rust closure pair: (fn ptr, env) - // where the environment is NULL. However, extern functions for - // interfacing with C are represted as just the fn ptr with type - // *u8. - // - // Strictly speaking, references to extern fns ought to be - // RvalueDatumExprs, but it's not worth the complexity to avoid the - // extra stack slot that LLVM probably optimizes away anyhow. - - let fn_tpt = ty::lookup_item_type(bcx.tcx(), def_id); - if ty::ty_fn_purity(fn_tpt.ty) == ast::extern_fn { - let val = PointerCast(bcx, fn_data.llfn, T_ptr(T_i8())); - Store(bcx, val, lldest); - return bcx; - } - - let llfn = GEPi(bcx, lldest, [0u, abi::fn_field_code]); - Store(bcx, fn_data.llfn, llfn); - let llenv = GEPi(bcx, lldest, [0u, abi::fn_field_box]); - Store(bcx, base::null_env_ptr(bcx), llenv); - return bcx; -} - // The optional node ID here is the node ID of the path identifying the enum // variant in use. If none, this cannot possibly an enum variant (so, if it // is and `node_id_opt` is none, this function fails). diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 8275db8cdb2..7af33eb2b9d 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -130,8 +130,7 @@ pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef { T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())]) } - // FIXME(#4804) Bare fn repr - ty::ty_bare_fn(*) => T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())]), + ty::ty_bare_fn(*) => T_ptr(T_i8()), ty::ty_closure(*) => T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())]), ty::ty_trait(_, _, vstore) => T_opaque_trait(cx, vstore), @@ -169,7 +168,9 @@ pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef { ty::ty_enum(def_id, _) => T_struct(enum_body_types(cx, def_id, t)), ty::ty_self | ty::ty_infer(*) | ty::ty_param(*) | ty::ty_err(*) => { - cx.tcx.sess.bug(~"fictitious type in sizing_type_of()") + cx.tcx.sess.bug( + fmt!("fictitious type %? in sizing_type_of()", + ty::get(t).sty)) } }; @@ -266,9 +267,7 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { T_struct(~[T_struct(tys)]) } - // FIXME(#4804) Bare fn repr - // ty::ty_bare_fn(_) => T_ptr(type_of_fn_from_ty(cx, t)), - ty::ty_bare_fn(_) => T_fn_pair(cx, type_of_fn_from_ty(cx, t)), + ty::ty_bare_fn(_) => T_ptr(type_of_fn_from_ty(cx, t)), ty::ty_closure(_) => T_fn_pair(cx, type_of_fn_from_ty(cx, t)), ty::ty_trait(_, _, vstore) => T_opaque_trait(cx, vstore), ty::ty_type => T_ptr(cx.tydesc_type), diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 182ab11b917..deede95dc03 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -172,7 +172,14 @@ impl cmp::Eq for region_variance { #[auto_encode] #[auto_decode] -pub struct AutoAdjustment { +pub enum AutoAdjustment { + AutoAddEnv(ty::Region, ast::Sigil), + AutoDerefRef(AutoDerefRef) +} + +#[auto_encode] +#[auto_decode] +pub struct AutoDerefRef { autoderefs: uint, autoref: Option } @@ -198,7 +205,7 @@ pub enum AutoRefKind { AutoBorrowVecRef, /// Convert from @fn()/~fn() to &fn() - AutoBorrowFn, + AutoBorrowFn } // Stores information about provided methods (a.k.a. default methods) in @@ -1477,7 +1484,6 @@ pub fn type_is_structural(ty: t) -> bool { match get(ty).sty { ty_rec(_) | ty_struct(*) | ty_tup(_) | ty_enum(*) | ty_closure(_) | - ty_bare_fn(_) | // FIXME(#4804) Bare fn repr ty_trait(*) | ty_evec(_, vstore_fixed(_)) | ty_estr(vstore_fixed(_)) | ty_evec(_, vstore_slice(_)) | ty_estr(vstore_slice(_)) @@ -1587,7 +1593,7 @@ pub pure fn type_is_scalar(ty: t) -> bool { match get(ty).sty { ty_nil | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | ty_infer(IntVar(_)) | ty_infer(FloatVar(_)) | ty_type | - ty_ptr(_) => true, + ty_bare_fn(*) | ty_ptr(_) => true, _ => false } } @@ -2884,7 +2890,25 @@ pub fn expr_ty_adjusted(cx: ctxt, expr: @ast::expr) -> t { return match cx.adjustments.find(&expr.id) { None => unadjusted_ty, - Some(adj) => { + Some(@AutoAddEnv(r, s)) => { + match ty::get(unadjusted_ty).sty { + ty::ty_bare_fn(ref b) => { + ty::mk_closure( + cx, + ty::ClosureTy {purity: b.purity, + sigil: s, + onceness: ast::Many, + region: r, + sig: copy b.sig}) + } + ref b => { + cx.sess.bug( + fmt!("add_env adjustment on non-bare-fn: %?", b)); + } + } + } + + Some(@AutoDerefRef(ref adj)) => { let mut adjusted_ty = unadjusted_ty; for uint::range(0, adj.autoderefs) |i| { @@ -3066,9 +3090,11 @@ pub fn expr_kind(tcx: ctxt, match expr.node { ast::expr_path(*) => { match resolve_expr(tcx, expr) { - ast::def_fn(*) | ast::def_static_method(*) | ast::def_variant(*) | ast::def_struct(*) => RvalueDpsExpr, + // Fn pointers are just scalar values. + ast::def_fn(*) | ast::def_static_method(*) => RvalueDatumExpr, + // Note: there is actually a good case to be made that // def_args, particularly those of immediate type, ought to // considered rvalues. diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 34b650aa180..63d09d88f52 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -799,26 +799,28 @@ pub impl LookupContext { let region = self.infcx().next_region_var(self.expr.span, self.expr.id); (ty::mk_rptr(tcx, region, self_mt), - ty::AutoAdjustment { + ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: autoderefs+1, autoref: Some(ty::AutoRef {kind: AutoPtr, region: region, - mutbl: self_mt.mutbl})}) + mutbl: self_mt.mutbl})})) } ty::ty_evec(self_mt, vstore_slice(_)) if self_mt.mutbl == m_mutbl => { let region = self.infcx().next_region_var(self.expr.span, self.expr.id); (ty::mk_evec(tcx, self_mt, vstore_slice(region)), - ty::AutoAdjustment { + ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, autoref: Some(ty::AutoRef {kind: AutoBorrowVec, region: region, - mutbl: self_mt.mutbl})}) + mutbl: self_mt.mutbl})})) } _ => { - (self_ty, ty::AutoAdjustment {autoderefs: autoderefs, - autoref: None}) + (self_ty, + ty::AutoDerefRef(ty::AutoDerefRef { + autoderefs: autoderefs, + autoref: None})) } }; } @@ -947,14 +949,14 @@ pub impl LookupContext { Some(mme) => { self.fcx.write_adjustment( self.self_expr.id, - @ty::AutoAdjustment { + @ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, autoref: Some(ty::AutoRef { kind: kind, region: region, mutbl: *mutbl, }), - }); + })); return Some(mme); } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index e63e46ace3d..ec5156ae1f7 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -736,7 +736,9 @@ pub impl FnCtxt { if derefs == 0 { return; } self.write_adjustment( node_id, - @ty::AutoAdjustment { autoderefs: derefs, autoref: None } + @ty::AutoDerefRef(ty::AutoDerefRef { + autoderefs: derefs, + autoref: None }) ); } diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index c91607489ec..7187f15e749 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -184,8 +184,13 @@ pub fn visit_expr(expr: @ast::expr, &&rcx: @mut Rcx, v: rvt) { debug!("visit_expr(e=%s)", rcx.fcx.expr_to_str(expr)); for rcx.fcx.inh.adjustments.find(&expr.id).each |adjustment| { - for adjustment.autoref.each |autoref| { - guarantor::for_autoref(rcx, expr, *adjustment, autoref); + match *adjustment { + @ty::AutoDerefRef( + ty::AutoDerefRef { + autoderefs: autoderefs, autoref: Some(ref autoref)}) => { + guarantor::for_autoref(rcx, expr, autoderefs, autoref); + } + _ => {} } } @@ -329,9 +334,11 @@ pub fn constrain_auto_ref(rcx: @mut Rcx, expr: @ast::expr) { let adjustment = rcx.fcx.inh.adjustments.find(&expr.id); let region = match adjustment { - Some(@ty::AutoAdjustment { autoref: Some(ref auto_ref), _ }) => { + Some(@ty::AutoDerefRef( + ty::AutoDerefRef { + autoref: Some(ref auto_ref), _})) => { auto_ref.region - }, + } _ => { return; } }; @@ -563,7 +570,7 @@ pub mod guarantor { pub fn for_autoref(rcx: @mut Rcx, expr: @ast::expr, - adjustment: &ty::AutoAdjustment, + autoderefs: uint, autoref: &ty::AutoRef) { /*! * @@ -578,7 +585,7 @@ pub mod guarantor { let mut expr_ct = categorize_unadjusted(rcx, expr); expr_ct = apply_autoderefs( - rcx, expr, adjustment.autoderefs, expr_ct); + rcx, expr, autoderefs, expr_ct); for expr_ct.cat.guarantor.each |g| { infallibly_mk_subr(rcx, true, expr.span, autoref.region, *g); } @@ -723,19 +730,32 @@ pub mod guarantor { let mut expr_ct = categorize_unadjusted(rcx, expr); debug!("before adjustments, cat=%?", expr_ct.cat); - for rcx.fcx.inh.adjustments.find(&expr.id).each |adjustment| { - debug!("adjustment=%?", adjustment); - - expr_ct = apply_autoderefs( - rcx, expr, adjustment.autoderefs, expr_ct); - - for adjustment.autoref.each |autoref| { - // If there is an autoref, then the result of this - // expression will be some sort of borrowed pointer. - expr_ct.cat.guarantor = None; - expr_ct.cat.pointer = BorrowedPointer(autoref.region); - debug!("autoref, cat=%?", expr_ct.cat); + match rcx.fcx.inh.adjustments.find(&expr.id) { + Some(@ty::AutoAddEnv(*)) => { + // This is basically an rvalue, not a pointer, no regions + // involved. + expr_ct.cat = ExprCategorization { + guarantor: None, + pointer: NotPointer + }; } + + Some(@ty::AutoDerefRef(ref adjustment)) => { + debug!("adjustment=%?", adjustment); + + expr_ct = apply_autoderefs( + rcx, expr, adjustment.autoderefs, expr_ct); + + for adjustment.autoref.each |autoref| { + // If there is an autoref, then the result of this + // expression will be some sort of borrowed pointer. + expr_ct.cat.guarantor = None; + expr_ct.cat.pointer = BorrowedPointer(autoref.region); + debug!("autoref, cat=%?", expr_ct.cat); + } + } + + None => {} } debug!("result=%?", expr_ct.cat); diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index a16dab4bdea..a6aed9c7b0c 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -79,7 +79,24 @@ fn resolve_type_vars_for_node(wbcx: @mut WbCtxt, sp: span, id: ast::node_id) // Resolve any borrowings for the node with id `id` match fcx.inh.adjustments.find(&id) { None => (), - Some(adj) => { + + Some(@ty::AutoAddEnv(r, s)) => { + match resolve_region(fcx.infcx(), r, resolve_all | force_all) { + Err(e) => { + // This should not, I think, happen: + fcx.ccx.tcx.sess.span_err( + sp, fmt!("cannot resolve bound for closure: %s", + infer::fixup_err_to_str(e))); + } + Ok(r1) => { + let resolved_adj = @ty::AutoAddEnv(r1, s); + debug!("Adjustments for node %d: %?", id, resolved_adj); + fcx.tcx().adjustments.insert(id, resolved_adj); + } + } + } + + Some(@ty::AutoDerefRef(adj)) => { let resolved_autoref = match adj.autoref { Some(ref autoref) => { match resolve_region(fcx.infcx(), autoref.region, @@ -99,9 +116,10 @@ fn resolve_type_vars_for_node(wbcx: @mut WbCtxt, sp: span, id: ast::node_id) None => None }; - let resolved_adj = @ty::AutoAdjustment { + let resolved_adj = @ty::AutoDerefRef(ty::AutoDerefRef { + autoderefs: adj.autoderefs, autoref: resolved_autoref, - ..*adj}; + }); debug!("Adjustments for node %d: %?", id, resolved_adj); fcx.tcx().adjustments.insert(id, resolved_adj); } diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 5d291fdde77..17db5d475fd 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -67,7 +67,7 @@ we may want to adjust precisely when coercions occur. use core::prelude::*; use middle::ty::{TyVar, AutoPtr, AutoBorrowVec, AutoBorrowFn}; -use middle::ty::{AutoAdjustment, AutoRef}; +use middle::ty::{AutoAdjustment, AutoDerefRef, AutoRef}; use middle::ty::{vstore_slice, vstore_box, vstore_uniq, vstore_fixed}; use middle::ty::{mt}; use middle::ty; @@ -206,14 +206,14 @@ impl Coerce { r_borrow, mt {ty: inner_ty, mutbl: mt_b.mutbl}); if_ok!(sub.tys(a_borrowed, b)); - Ok(Some(@AutoAdjustment { + Ok(Some(@AutoDerefRef(AutoDerefRef { autoderefs: 1, autoref: Some(AutoRef { kind: AutoPtr, region: r_borrow, mutbl: mt_b.mutbl }) - })) + }))) } fn coerce_borrowed_string(&self, @@ -236,14 +236,14 @@ impl Coerce { let r_a = self.infcx.next_region_var_nb(self.span); let a_borrowed = ty::mk_estr(self.infcx.tcx, vstore_slice(r_a)); if_ok!(self.subtype(a_borrowed, b)); - Ok(Some(@AutoAdjustment { + Ok(Some(@AutoDerefRef(AutoDerefRef { autoderefs: 0, autoref: Some(AutoRef { kind: AutoBorrowVec, region: r_a, mutbl: m_imm }) - })) + }))) } fn coerce_borrowed_vector(&self, @@ -269,14 +269,14 @@ impl Coerce { mt {ty: ty_inner, mutbl: mt_b.mutbl}, vstore_slice(r_borrow)); if_ok!(sub.tys(a_borrowed, b)); - Ok(Some(@AutoAdjustment { + Ok(Some(@AutoDerefRef(AutoDerefRef { autoderefs: 0, autoref: Some(AutoRef { kind: AutoBorrowVec, region: r_borrow, mutbl: mt_b.mutbl }) - })) + }))) } fn coerce_borrowed_fn(&self, @@ -309,14 +309,14 @@ impl Coerce { }); if_ok!(self.subtype(a_borrowed, b)); - Ok(Some(@AutoAdjustment { + Ok(Some(@AutoDerefRef(AutoDerefRef { autoderefs: 0, autoref: Some(AutoRef { kind: AutoBorrowFn, region: r_borrow, mutbl: m_imm }) - })) + }))) } fn coerce_from_bare_fn(&self, @@ -347,10 +347,12 @@ impl Coerce { // for now, bare fn and closures have the same // representation + let adj = @ty::AutoAddEnv(fn_ty_b.region, fn_ty_b.sigil); let a_closure = ty::mk_closure( self.infcx.tcx, ty::ClosureTy {sig: copy fn_ty_a.sig, ..fn_ty_b}); - self.subtype(a_closure, b) + if_ok!(self.subtype(a_closure, b)); + Ok(Some(adj)) } fn coerce_unsafe_ptr(&self,