From cb404dd4fbe30907ed53e9f9915e37d644382a12 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Wed, 9 Jul 2014 23:42:08 -0700 Subject: [PATCH] librustc: Emit enum variant constructor at callsite instead of via a call to a function. --- src/librustc/middle/trans/base.rs | 55 +++++++++++++++++++++++++++++ src/librustc/middle/trans/callee.rs | 27 +++++++++++--- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 98342bfbcdc..84db9e5335a 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1704,6 +1704,61 @@ pub fn trans_enum_variant(ccx: &CrateContext, llfndecl); } +pub fn trans_enum_variant_constructor<'a>(mut bcx: &'a Block<'a>, + ctor_ty: ty::t, + disr: ty::Disr, + args: callee::CallArgs, + dest: expr::Dest) -> Result<'a> { + + let ccx = bcx.fcx.ccx; + let tcx = &ccx.tcx; + + let result_ty = match ty::get(ctor_ty).sty { + ty::ty_bare_fn(ref bft) => bft.sig.output, + _ => ccx.sess().bug( + format!("trans_enum_variant_constructor: \ + unexpected ctor return type {}", + ctor_ty.repr(tcx)).as_slice()) + }; + + // Get location to store the result. If the user does not care about + // the result, just make a stack slot + let llresult = match dest { + expr::SaveIn(d) => d, + expr::Ignore => { + if !type_is_zero_size(ccx, result_ty) { + alloc_ty(bcx, result_ty, "constructor_result") + } else { + C_undef(type_of::type_of(ccx, result_ty)) + } + } + }; + + if !type_is_zero_size(ccx, result_ty) { + let repr = adt::represent_type(ccx, result_ty); + adt::trans_start_init(bcx, &*repr, llresult, disr); + + match args { + callee::ArgExprs(exprs) => { + for (i, expr) in exprs.iter().enumerate() { + let lldestptr = adt::trans_field_ptr(bcx, &*repr, llresult, disr, i); + bcx = expr::trans_into(bcx, *expr, expr::SaveIn(lldestptr)); + } + } + _ => ccx.sess().bug("expected expr as arguments for variant/struct tuple constructor") + } + } + + // If the caller doesn't care about the result + // drop the temporary we made + let bcx = match dest { + expr::SaveIn(_) => bcx, + expr::Ignore => glue::drop_ty(bcx, llresult, result_ty) + }; + + Result::new(bcx, llresult) +} + pub fn trans_tuple_struct(ccx: &CrateContext, _fields: &[ast::StructField], ctor_id: ast::NodeId, diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 8eab227ad16..608710a2508 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -64,6 +64,10 @@ pub struct MethodData { pub enum CalleeData { Closure(Datum), + // Constructor for enum variant/tuple-like-struct + // i.e. Some, Ok + TupleVariantConstructor(subst::Substs, ty::Disr), + // Represents a (possibly monomorphized) top-level fn item or method // item. Note that this is just the fn-ptr and is not a Rust closure // value (which is a pair). @@ -158,11 +162,16 @@ fn trans_def<'a>(bcx: &'a Block<'a>, def: def::Def, ref_expr: &ast::Expr) ref_expr.id)) } def::DefVariant(tid, vid, _) => { - // nullary variants are not callable - assert!(ty::enum_variant_with_id(bcx.tcx(), - tid, - vid).args.len() > 0u); - fn_callee(bcx, trans_fn_ref(bcx, vid, ExprId(ref_expr.id))) + let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid); + let substs = node_id_substs(bcx, ExprId(ref_expr.id)); + + // Nullary variants are not callable + assert!(vinfo.args.len() > 0u); + + Callee { + bcx: bcx, + data: TupleVariantConstructor(substs, vinfo.disr_val) + } } def::DefStruct(def_id) => { fn_callee(bcx, trans_fn_ref(bcx, def_id, ExprId(ref_expr.id))) @@ -710,6 +719,14 @@ pub fn trans_call_inner<'a>( arg_cleanup_scope, args, dest.unwrap(), substs); } + TupleVariantConstructor(substs, disr) => { + assert!(dest.is_some()); + fcx.pop_custom_cleanup_scope(arg_cleanup_scope); + + let ctor_ty = callee_ty.subst(bcx.tcx(), &substs); + return base::trans_enum_variant_constructor(bcx, ctor_ty, disr, + args, dest.unwrap()); + } }; // Intrinsics should not become actual functions. -- 2.44.0