diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 6277656e03afc..7beccf4ebe85b 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -14,9 +14,7 @@ use middle::ty; use util::ppaux; use syntax::ast; -use syntax::ast_util; -use syntax::visit::Visitor; -use syntax::visit; +use syntax::visit::{mod, Visitor}; struct CheckCrateVisitor<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, @@ -37,24 +35,39 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { { self.with_const(true, f); } - fn outside_const(&mut self, f: F) where - F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>), - { - self.with_const(false, f); - } } impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { fn visit_item(&mut self, i: &ast::Item) { - check_item(self, i); + match i.node { + ast::ItemStatic(_, _, ref ex) | + ast::ItemConst(_, ref ex) => { + self.inside_const(|v| v.visit_expr(&**ex)); + } + ast::ItemEnum(ref enum_definition, _) => { + self.inside_const(|v| { + for var in enum_definition.variants.iter() { + if let Some(ref ex) = var.node.disr_expr { + v.visit_expr(&**ex); + } + } + }); + } + _ => self.with_const(false, |v| visit::walk_item(v, i)) + } } fn visit_pat(&mut self, p: &ast::Pat) { - check_pat(self, p); + let is_const = match p.node { + ast::PatLit(_) | ast::PatRange(..) => true, + _ => false + }; + self.with_const(is_const, |v| visit::walk_pat(v, p)) } fn visit_expr(&mut self, ex: &ast::Expr) { - if check_expr(self, ex) { - visit::walk_expr(self, ex); + if self.in_const { + check_expr(self, ex); } + visit::walk_expr(self, ex); } } @@ -64,57 +77,13 @@ pub fn check_crate(tcx: &ty::ctxt) { tcx.sess.abort_if_errors(); } -fn check_item(v: &mut CheckCrateVisitor, it: &ast::Item) { - match it.node { - ast::ItemStatic(_, _, ref ex) | - ast::ItemConst(_, ref ex) => { - v.inside_const(|v| v.visit_expr(&**ex)); - } - ast::ItemEnum(ref enum_definition, _) => { - for var in (*enum_definition).variants.iter() { - for ex in var.node.disr_expr.iter() { - v.inside_const(|v| v.visit_expr(&**ex)); - } - } - } - _ => v.outside_const(|v| visit::walk_item(v, it)) - } -} - -fn check_pat(v: &mut CheckCrateVisitor, p: &ast::Pat) { - fn is_str(e: &ast::Expr) -> bool { - match e.node { - ast::ExprBox(_, ref expr) => { - match expr.node { - ast::ExprLit(ref lit) => ast_util::lit_is_str(&**lit), - _ => false, - } - } - _ => false, - } - } - match p.node { - // Let through plain ~-string literals here - ast::PatLit(ref a) => if !is_str(&**a) { v.inside_const(|v| v.visit_expr(&**a)); }, - ast::PatRange(ref a, ref b) => { - if !is_str(&**a) { v.inside_const(|v| v.visit_expr(&**a)); } - if !is_str(&**b) { v.inside_const(|v| v.visit_expr(&**b)); } - } - _ => v.outside_const(|v| visit::walk_pat(v, p)) - } -} - -fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { - if !v.in_const { return true } - +fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) { match e.node { ast::ExprUnary(ast::UnDeref, _) => {} ast::ExprUnary(ast::UnUniq, _) => { span_err!(v.tcx.sess, e.span, E0010, "cannot do allocations in constant expressions"); - return false; } - ast::ExprLit(ref lit) if ast_util::lit_is_str(&**lit) => {} ast::ExprBinary(..) | ast::ExprUnary(..) => { let method_call = ty::MethodCall::expr(e.id); if v.tcx.method_map.borrow().contains_key(&method_call) { @@ -123,7 +92,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { expressions"); } } - ast::ExprLit(_) => (), + ast::ExprLit(_) => {} ast::ExprCast(ref from, _) => { let toty = ty::expr_ty(v.tcx, e); let fromty = ty::expr_ty(v.tcx, &**from); @@ -142,39 +111,23 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { expression"); } } - ast::ExprPath(ref pth) => { - // NB: In the future you might wish to relax this slightly - // to handle on-demand instantiation of functions via - // foo:: in a const. Currently that is only done on - // a path in trans::callee that only works in block contexts. - if !pth.segments.iter().all(|segment| segment.parameters.is_empty()) { - span_err!(v.tcx.sess, e.span, E0013, - "paths in constants may only refer to items without \ - type parameters"); - } - match v.tcx.def_map.borrow().get(&e.id) { - Some(&DefStatic(..)) | - Some(&DefConst(..)) | - Some(&DefFn(..)) | - Some(&DefVariant(_, _, _)) | - Some(&DefStruct(_)) => { } + ast::ExprPath(_) => { + match v.tcx.def_map.borrow()[e.id] { + DefStatic(..) | DefConst(..) | + DefFn(..) | DefStaticMethod(..) | DefMethod(..) | + DefStruct(_) | DefVariant(_, _, _) => {} - Some(&def) => { + def => { debug!("(checking const) found bad def: {}", def); span_err!(v.tcx.sess, e.span, E0014, "paths in constants may only refer to constants \ or functions"); } - None => { - v.tcx.sess.span_bug(e.span, "unbound path in const?!"); - } } } ast::ExprCall(ref callee, _) => { - match v.tcx.def_map.borrow().get(&callee.id) { - Some(&DefStruct(..)) | - Some(&DefVariant(..)) => {} // OK. - + match v.tcx.def_map.borrow()[callee.id] { + DefStruct(..) | DefVariant(..) => {} // OK. _ => { span_err!(v.tcx.sess, e.span, E0015, "function calls in constants are limited to \ @@ -190,9 +143,9 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { "blocks in constants are limited to items and \ tail expressions"); match stmt.node { - ast::StmtDecl(ref span, _) => { - match span.node { - ast::DeclLocal(_) => block_span_err(span.span), + ast::StmtDecl(ref decl, _) => { + match decl.node { + ast::DeclLocal(_) => block_span_err(decl.span), // Item statements are allowed ast::DeclItem(_) => {} @@ -206,10 +159,6 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { } } } - match block.expr { - Some(ref expr) => { check_expr(v, &**expr); } - None => {} - } } ast::ExprVec(_) | ast::ExprAddrOf(ast::MutImmutable, _) | @@ -232,11 +181,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool { } } - _ => { - span_err!(v.tcx.sess, e.span, E0019, - "constant contains unimplemented expression type"); - return false; - } + _ => span_err!(v.tcx.sess, e.span, E0019, + "constant contains unimplemented expression type") } - true } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 722fe82d41c32..92ca15b22fd8c 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -559,14 +559,14 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { id, expr_ty.repr(self.tcx()), def); match def { - def::DefStruct(..) | def::DefVariant(..) | def::DefFn(..) | - def::DefStaticMethod(..) | def::DefConst(..) => { + def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) | + def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => { Ok(self.cat_rvalue_node(id, span, expr_ty)) } def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) | def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) | def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) | - def::DefLabel(_) | def::DefSelfTy(..) | def::DefMethod(..) | + def::DefLabel(_) | def::DefSelfTy(..) | def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> { Ok(Rc::new(cmt_ { id:id, diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 225f6f116dae3..fa1da575d691f 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -511,7 +511,7 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Since we're in trans we don't care for any region parameters let substs = subst::Substs::erased(substs.types.clone()); - let (val, _) = monomorphize::monomorphic_fn(ccx, did, &substs, None); + let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, &substs, None); val } else if did.krate == ast::LOCAL_CRATE { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 169e52bcfe5be..9f18b73414538 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -38,6 +38,7 @@ use trans::cleanup::CleanupMethods; use trans::closure; use trans::common; use trans::common::*; +use trans::consts; use trans::datum::*; use trans::expr; use trans::glue; @@ -152,7 +153,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) _ => false } } => { - let substs = node_id_substs(bcx, ExprId(ref_expr.id)); + let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id), + bcx.fcx.param_substs); Callee { bcx: bcx, data: NamedTupleConstructor(substs, 0) @@ -162,23 +164,28 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) ty::ty_bare_fn(_, ref f) => f.abi == synabi::RustIntrinsic, _ => false } => { - let substs = node_id_substs(bcx, ExprId(ref_expr.id)); + let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id), + bcx.fcx.param_substs); let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did); Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) } } def::DefFn(did, _) | def::DefMethod(did, _, def::FromImpl(_)) | def::DefStaticMethod(did, def::FromImpl(_)) => { - fn_callee(bcx, trans_fn_ref(bcx, did, ExprId(ref_expr.id))) + fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id), + bcx.fcx.param_substs).val) } def::DefStaticMethod(meth_did, def::FromTrait(trait_did)) | def::DefMethod(meth_did, _, def::FromTrait(trait_did)) => { - fn_callee(bcx, meth::trans_static_method_callee(bcx, meth_did, + fn_callee(bcx, meth::trans_static_method_callee(bcx.ccx(), + meth_did, trait_did, - ref_expr.id)) + ref_expr.id, + bcx.fcx.param_substs).val) } def::DefVariant(tid, vid, _) => { let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid); - let substs = node_id_substs(bcx, ExprId(ref_expr.id)); + let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id), + bcx.fcx.param_substs); // Nullary variants are not callable assert!(vinfo.args.len() > 0u); @@ -189,7 +196,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) } } def::DefStruct(_) => { - let substs = node_id_substs(bcx, ExprId(ref_expr.id)); + let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id), + bcx.fcx.param_substs); Callee { bcx: bcx, data: NamedTupleConstructor(substs, 0) @@ -217,15 +225,19 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) /// Translates a reference (with id `ref_id`) to the fn/method with id `def_id` into a function /// pointer. This may require monomorphization or inlining. -pub fn trans_fn_ref(bcx: Block, def_id: ast::DefId, node: ExprOrMethodCall) -> ValueRef { +pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + def_id: ast::DefId, + node: ExprOrMethodCall, + param_substs: &subst::Substs<'tcx>) + -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_fn_ref"); - let substs = node_id_substs(bcx, node); + let substs = node_id_substs(ccx, node, param_substs); debug!("trans_fn_ref(def_id={}, node={}, substs={})", - def_id.repr(bcx.tcx()), + def_id.repr(ccx.tcx()), node, - substs.repr(bcx.tcx())); - trans_fn_ref_with_substs(bcx, def_id, node, substs) + substs.repr(ccx.tcx())); + trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs) } fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, @@ -235,10 +247,11 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, -> Callee<'blk, 'tcx> { Callee { bcx: bcx, - data: Fn(trans_fn_ref_with_substs(bcx, + data: Fn(trans_fn_ref_with_substs(bcx.ccx(), def_id, ExprId(ref_id), - substs)), + bcx.fcx.param_substs, + substs).val), } } @@ -364,28 +377,30 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( /// /// # Parameters /// -/// - `bcx`: the current block where the reference to the fn occurs +/// - `ccx`: the crate context /// - `def_id`: def id of the fn or method item being referenced /// - `node`: node id of the reference to the fn/method, if applicable. /// This parameter may be zero; but, if so, the resulting value may not /// have the right type, so it must be cast before being used. +/// - `param_substs`: if the `node` is in a polymorphic function, these +/// are the substitutions required to monomorphize its type /// - `substs`: values for each of the fn/method's parameters -pub fn trans_fn_ref_with_substs<'blk, 'tcx>( - bcx: Block<'blk, 'tcx>, // - def_id: ast::DefId, // def id of fn - node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A - substs: subst::Substs<'tcx>) // vtables for the call - -> ValueRef +pub fn trans_fn_ref_with_substs<'a, 'tcx>( + ccx: &CrateContext<'a, 'tcx>, + def_id: ast::DefId, + node: ExprOrMethodCall, + param_substs: &subst::Substs<'tcx>, + substs: subst::Substs<'tcx>) + -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_fn_ref_with_substs"); - let ccx = bcx.ccx(); - let tcx = bcx.tcx(); + let tcx = ccx.tcx(); - debug!("trans_fn_ref_with_substs(bcx={}, def_id={}, node={}, \ - substs={})", - bcx.to_str(), + debug!("trans_fn_ref_with_substs(def_id={}, node={}, \ + param_substs={}, substs={})", def_id.repr(tcx), node, + param_substs.repr(tcx), substs.repr(tcx)); assert!(substs.types.all(|t| !ty::type_needs_infer(*t))); @@ -443,15 +458,15 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( (true, source_id, new_substs) } ty::TypeTraitItem(_) => { - bcx.tcx().sess.bug("trans_fn_ref_with_vtables() tried \ - to translate an associated type?!") + tcx.sess.bug("trans_fn_ref_with_vtables() tried \ + to translate an associated type?!") } } } }; // If this is an unboxed closure, redirect to it. - match closure::get_or_create_declaration_if_unboxed_closure(bcx, + match closure::get_or_create_declaration_if_unboxed_closure(ccx, def_id, &substs) { None => {} @@ -494,24 +509,27 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( MethodCallKey(_) => None, }; - let (val, must_cast) = + let (val, fn_ty, must_cast) = monomorphize::monomorphic_fn(ccx, def_id, &substs, opt_ref_id); - let mut val = val; if must_cast && node != ExprId(0) { // Monotype of the REFERENCE to the function (type params // are subst'd) let ref_ty = match node { - ExprId(id) => node_id_type(bcx, id), + ExprId(id) => ty::node_id_to_type(tcx, id), MethodCallKey(method_call) => { - let t = (*bcx.tcx().method_map.borrow())[method_call].ty; - monomorphize_type(bcx, t) + (*tcx.method_map.borrow())[method_call].ty } }; - - val = PointerCast( - bcx, val, type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to()); + let ref_ty = monomorphize::apply_param_substs(tcx, + param_substs, + &ref_ty); + let llptrty = type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to(); + if llptrty != val_ty(val) { + let val = consts::ptrcast(val, llptrty); + return Datum::new(val, ref_ty, Rvalue::new(ByValue)); + } } - return val; + return Datum::new(val, fn_ty, Rvalue::new(ByValue)); } // Type scheme of the function item (may have type params) @@ -556,12 +574,12 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( let llptrty = llty.ptr_to(); if val_ty(val) != llptrty { debug!("trans_fn_ref_with_vtables(): casting pointer!"); - val = BitCast(bcx, val, llptrty); + val = consts::ptrcast(val, llptrty); } else { debug!("trans_fn_ref_with_vtables(): not casting pointer!"); } - val + Datum::new(val, fn_type, Rvalue::new(ByValue)) } // ______________________________________________________________________ diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 8ac427dd06124..de7a7f2aa7bcc 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -726,7 +726,10 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx // specify any of the types for the function, we just make it a symbol // that LLVM can later use. let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() { - Some(def_id) => callee::trans_fn_ref(pad_bcx, def_id, ExprId(0)), + Some(def_id) => { + callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0), + pad_bcx.fcx.param_substs).val + } None => { let mut personality = self.ccx.eh_personality().borrow_mut(); match *personality { diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 93a5b54fde3e5..ae58a1eb060af 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -20,6 +20,7 @@ use trans::build::*; use trans::cleanup::{CleanupMethods, ScopeId}; use trans::common::*; use trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum}; +use trans::datum::{Rvalue, ByValue}; use trans::debuginfo; use trans::expr; use trans::monomorphize::{mod, MonoId}; @@ -453,22 +454,21 @@ pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// 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<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - closure_id: ast::DefId, - substs: &Substs<'tcx>) - -> Option { - let ccx = bcx.ccx(); +pub fn get_or_create_declaration_if_unboxed_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + closure_id: ast::DefId, + substs: &Substs<'tcx>) + -> Option> { if !ccx.tcx().unboxed_closures.borrow().contains_key(&closure_id) { // Not an unboxed closure. return None } - let function_type = ty::node_id_to_type(bcx.tcx(), closure_id.node); - let function_type = monomorphize::apply_param_substs(bcx.tcx(), substs, &function_type); + let function_type = ty::node_id_to_type(ccx.tcx(), closure_id.node); + let function_type = monomorphize::apply_param_substs(ccx.tcx(), substs, &function_type); // Normalize type so differences in regions and typedefs don't cause // duplicate declarations - let function_type = ty::normalize_ty(bcx.tcx(), function_type); + let function_type = ty::normalize_ty(ccx.tcx(), function_type); let params = match function_type.sty { ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(), _ => unreachable!() @@ -479,10 +479,10 @@ pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, }; match ccx.unboxed_closure_vals().borrow().get(&mono_id) { - Some(llfn) => { + Some(&llfn) => { debug!("get_or_create_declaration_if_unboxed_closure(): found \ closure"); - return Some(*llfn) + return Some(Datum::new(llfn, function_type, Rvalue::new(ByValue))) } None => {} } @@ -502,7 +502,7 @@ pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, ccx.tn().type_to_string(val_ty(llfn))); ccx.unboxed_closure_vals().borrow_mut().insert(mono_id, llfn); - Some(llfn) + Some(Datum::new(llfn, function_type, Rvalue::new(ByValue))) } pub fn trans_unboxed_closure<'blk, 'tcx>( @@ -519,7 +519,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>( let closure_id = ast_util::local_def(id); let llfn = get_or_create_declaration_if_unboxed_closure( - bcx, + bcx.ccx(), closure_id, bcx.fcx.param_substs).unwrap(); @@ -539,7 +539,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>( trans_closure(bcx.ccx(), decl, body, - llfn, + llfn.val, bcx.fcx.param_substs, id, &[], diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 6efdcc2f0fa0f..11ce6a98be173 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -28,6 +28,7 @@ use middle::subst::{mod, Subst, Substs}; use trans::base; use trans::build; use trans::cleanup; +use trans::consts; use trans::datum; use trans::debuginfo; use trans::machine; @@ -803,12 +804,9 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va // NB: Do not use `do_spill_noroot` to make this into a constant string, or // you will be kicked off fast isel. See issue #4352 for an example of this. pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef { - unsafe { - let len = s.get().len(); - let cs = llvm::LLVMConstPointerCast(C_cstr(cx, s, false), - Type::i8p(cx).to_ref()); - C_named_struct(cx.tn().find_type("str_slice").unwrap(), &[cs, C_uint(cx, len)]) - } + let len = s.get().len(); + let cs = consts::ptrcast(C_cstr(cx, s, false), Type::i8p(cx)); + C_named_struct(cx.tn().find_type("str_slice").unwrap(), &[cs, C_uint(cx, len)]) } pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef { @@ -824,7 +822,7 @@ pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef { llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); - let cs = llvm::LLVMConstPointerCast(g, Type::i8p(cx).to_ref()); + let cs = consts::ptrcast(g, Type::i8p(cx)); C_struct(cx, &[cs, C_uint(cx, len)], false) } } @@ -1095,11 +1093,11 @@ pub enum ExprOrMethodCall { MethodCallKey(ty::MethodCall) } -pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - node: ExprOrMethodCall) - -> subst::Substs<'tcx> -{ - let tcx = bcx.tcx(); +pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + node: ExprOrMethodCall, + param_substs: &subst::Substs<'tcx>) + -> subst::Substs<'tcx> { + let tcx = ccx.tcx(); let substs = match node { ExprId(id) => { @@ -1111,15 +1109,13 @@ pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; if substs.types.any(|t| ty::type_needs_infer(*t)) { - bcx.sess().bug( - format!("type parameters for node {} include inference types: \ - {}", - node, - substs.repr(bcx.tcx()))[]); + tcx.sess.bug(format!("type parameters for node {} include inference types: {}", + node, substs.repr(tcx))[]); } - let substs = substs.erase_regions(); - bcx.monomorphize(&substs) + monomorphize::apply_param_substs(tcx, + param_substs, + &substs.erase_regions()) } pub fn langcall(bcx: Block, diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 347ec100ae7ad..b71425700138b 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -14,13 +14,13 @@ use llvm; use llvm::{ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True, False}; use llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE, RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE}; -use metadata::csearch; use middle::{const_eval, def}; use trans::{adt, closure, consts, debuginfo, expr, inline, machine}; use trans::base::{mod, push_ctxt}; use trans::common::*; use trans::type_::Type; use trans::type_of; +use middle::subst::Substs; use middle::ty::{mod, Ty}; use util::ppaux::{Repr, ty_to_string}; @@ -79,11 +79,9 @@ pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit) } } -pub fn const_ptrcast(cx: &CrateContext, a: ValueRef, t: Type) -> ValueRef { +pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { unsafe { - let b = llvm::LLVMConstPointerCast(a, t.ptr_to().to_ref()); - assert!(cx.const_globals().borrow_mut().insert(b as int, a).is_none()); - b + llvm::LLVMConstPointerCast(val, ty.to_ref()) } } @@ -258,7 +256,9 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, e: &ast::Expr) match ty.sty { ty::ty_vec(unit_ty, Some(len)) => { let llunitty = type_of::type_of(cx, unit_ty); - let llptr = const_ptrcast(cx, llconst, llunitty); + let llptr = ptrcast(llconst, llunitty.ptr_to()); + assert!(cx.const_globals().borrow_mut() + .insert(llptr as int, llconst).is_none()); assert_eq!(abi::FAT_PTR_ADDR, 0); assert_eq!(abi::FAT_PTR_EXTRA, 1); llconst = C_struct(cx, &[ @@ -523,7 +523,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef { } } (expr::cast_pointer, expr::cast_pointer) => { - llvm::LLVMConstPointerCast(v, llty.to_ref()) + ptrcast(v, llty) } (expr::cast_integral, expr::cast_pointer) => { llvm::LLVMConstIntToPtr(v, llty.to_ref()) @@ -616,36 +616,38 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef { C_array(llunitty, vs[]) } } - ast::ExprPath(ref pth) => { - // Assert that there are no type parameters in this path. - assert!(pth.segments.iter().all(|seg| !seg.parameters.has_types())); - - let opt_def = cx.tcx().def_map.borrow().get(&e.id).cloned(); - match opt_def { - Some(def::DefFn(def_id, _)) => { - if !ast_util::is_local(def_id) { - let ty = csearch::get_type(cx.tcx(), def_id).ty; - base::trans_external_path(cx, def_id, ty) - } else { - assert!(ast_util::is_local(def_id)); - base::get_item_val(cx, def_id.node) - } + ast::ExprPath(_) => { + let def = cx.tcx().def_map.borrow()[e.id]; + match def { + def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => { + expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val } - Some(def::DefConst(def_id)) => { + def::DefConst(def_id) => { get_const_val(cx, def_id) } - Some(def::DefVariant(enum_did, variant_did, _)) => { - let ety = ty::expr_ty(cx.tcx(), e); - let repr = adt::represent_type(cx, ety); + def::DefVariant(enum_did, variant_did, _) => { let vinfo = ty::enum_variant_with_id(cx.tcx(), enum_did, variant_did); - adt::trans_const(cx, &*repr, vinfo.disr_val, &[]) + if vinfo.args.len() > 0 { + // N-ary variant. + expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val + } else { + // Nullary variant. + let ety = ty::expr_ty(cx.tcx(), e); + let repr = adt::represent_type(cx, ety); + adt::trans_const(cx, &*repr, vinfo.disr_val, &[]) + } } - Some(def::DefStruct(_)) => { + def::DefStruct(_) => { let ety = ty::expr_ty(cx.tcx(), e); - let llty = type_of::type_of(cx, ety); - C_null(llty) + if let ty::ty_bare_fn(..) = ety.sty { + // Tuple struct. + expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val + } else { + // Unit struct. + C_null(type_of::type_of(cx, ety)) + } } _ => { cx.sess().span_bug(e.span, "expected a const, fn, struct, \ diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index cf3070919cb38..88e60eb555a0e 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -853,7 +853,9 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match def { def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) | def::DefStruct(_) | def::DefVariant(..) => { - trans_def_fn_unadjusted(bcx, ref_expr, def) + let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def, + bcx.fcx.param_substs); + DatumBlock::new(bcx, datum.to_expr_datum()) } def::DefStatic(did, _) => { // There are two things that may happen here: @@ -1250,7 +1252,9 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid); if variant_info.args.len() > 0u { // N-ary variant. - let llfn = callee::trans_fn_ref(bcx, vid, ExprId(ref_expr.id)); + let llfn = callee::trans_fn_ref(bcx.ccx(), vid, + ExprId(ref_expr.id), + bcx.fcx.param_substs).val; Store(bcx, llfn, lldest); return bcx; } else { @@ -1281,34 +1285,33 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn trans_def_fn_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - ref_expr: &ast::Expr, - def: def::Def) - -> DatumBlock<'blk, 'tcx, Expr> { +pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + ref_expr: &ast::Expr, + def: def::Def, + param_substs: &subst::Substs<'tcx>) + -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_def_datum_unadjusted"); - let llfn = match def { + match def { def::DefFn(did, _) | def::DefStruct(did) | def::DefVariant(_, did, _) | def::DefStaticMethod(did, def::FromImpl(_)) | def::DefMethod(did, _, def::FromImpl(_)) => { - callee::trans_fn_ref(bcx, did, ExprId(ref_expr.id)) + callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs) } def::DefStaticMethod(impl_did, def::FromTrait(trait_did)) | def::DefMethod(impl_did, _, def::FromTrait(trait_did)) => { - meth::trans_static_method_callee(bcx, impl_did, - trait_did, ref_expr.id) + meth::trans_static_method_callee(ccx, impl_did, + trait_did, ref_expr.id, + param_substs) } _ => { - bcx.tcx().sess.span_bug(ref_expr.span, format!( + ccx.tcx().sess.span_bug(ref_expr.span, format!( "trans_def_fn_unadjusted invoked on: {} for {}", def, - ref_expr.repr(bcx.tcx()))[]); + ref_expr.repr(ccx.tcx()))[]); } - }; - - let fn_ty = expr_ty(bcx, ref_expr); - DatumBlock::new(bcx, Datum::new(llfn, fn_ty, RvalueExpr(Rvalue::new(ByValue)))) + } } /// Translates a reference to a local variable or argument. This always results in an lvalue datum. diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index ab5c670ef5a2d..b4e37a410b896 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -26,6 +26,7 @@ use trans::build::*; use trans::callee; use trans::cleanup; use trans::cleanup::CleanupMethods; +use trans::consts; use trans::common::*; use trans::datum; use trans::debuginfo; @@ -577,9 +578,7 @@ pub fn emit_tydescs(ccx: &CrateContext) { // before being put into the tydesc because we only have a singleton // tydesc type. Then we'll recast each function to its real type when // calling it. - let drop_glue = unsafe { - llvm::LLVMConstPointerCast(get_drop_glue(ccx, ti.ty), glue_fn_ty.to_ref()) - }; + let drop_glue = consts::ptrcast(get_drop_glue(ccx, ti.ty), glue_fn_ty); ccx.stats().n_real_glues.set(ccx.stats().n_real_glues.get() + 1); let tydesc = C_named_struct(ccx.tydesc_type(), diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index f0588b3082ab6..36d8a23c331c0 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -122,9 +122,10 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty::MethodStaticUnboxedClosure(did) => { Callee { bcx: bcx, - data: Fn(callee::trans_fn_ref(bcx, + data: Fn(callee::trans_fn_ref(bcx.ccx(), did, - MethodCallKey(method_call))), + MethodCallKey(method_call), + bcx.fcx.param_substs).val), } } @@ -166,30 +167,31 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -pub fn trans_static_method_callee(bcx: Block, - method_id: ast::DefId, - trait_id: ast::DefId, - expr_id: ast::NodeId) - -> ValueRef +pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + method_id: ast::DefId, + trait_id: ast::DefId, + expr_id: ast::NodeId, + param_substs: &subst::Substs<'tcx>) + -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("meth::trans_static_method_callee"); - let ccx = bcx.ccx(); + let tcx = ccx.tcx(); debug!("trans_static_method_callee(method_id={}, trait_id={}, \ expr_id={})", method_id, - ty::item_path_str(bcx.tcx(), trait_id), + ty::item_path_str(tcx, trait_id), expr_id); let mname = if method_id.krate == ast::LOCAL_CRATE { - match bcx.tcx().map.get(method_id.node) { + match tcx.map.get(method_id.node) { ast_map::NodeTraitItem(method) => { let ident = match *method { ast::RequiredMethod(ref m) => m.ident, ast::ProvidedMethod(ref m) => m.pe_ident(), ast::TypeTraitItem(_) => { - bcx.tcx().sess.bug("trans_static_method_callee() on \ - an associated type?!") + tcx.sess.bug("trans_static_method_callee() on \ + an associated type?!") } }; ident.name @@ -197,7 +199,7 @@ pub fn trans_static_method_callee(bcx: Block, _ => panic!("callee is not a trait method") } } else { - csearch::get_item_path(bcx.tcx(), method_id).last().unwrap().name() + csearch::get_item_path(tcx, method_id).last().unwrap().name() }; debug!("trans_static_method_callee: method_id={}, expr_id={}, \ name={}", method_id, expr_id, token::get_name(mname)); @@ -205,7 +207,7 @@ pub fn trans_static_method_callee(bcx: Block, // Find the substitutions for the fn itself. This includes // type parameters that belong to the trait but also some that // belong to the method: - let rcvr_substs = node_id_substs(bcx, ExprId(expr_id)); + let rcvr_substs = node_id_substs(ccx, ExprId(expr_id), param_substs); let subst::SeparateVecsPerParamSpace { types: rcvr_type, selfs: rcvr_self, @@ -238,11 +240,11 @@ pub fn trans_static_method_callee(bcx: Block, Substs::erased(VecPerParamSpace::new(rcvr_type, rcvr_self, Vec::new())); - let trait_substs = bcx.tcx().mk_substs(trait_substs); - debug!("trait_substs={}", trait_substs.repr(bcx.tcx())); + let trait_substs = tcx.mk_substs(trait_substs); + debug!("trait_substs={}", trait_substs.repr(tcx)); let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id, substs: trait_substs })); - let vtbl = fulfill_obligation(bcx.ccx(), + let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref); @@ -282,17 +284,13 @@ pub fn trans_static_method_callee(bcx: Block, rcvr_method)); let mth_id = method_with_name(ccx, impl_did, mname); - let llfn = trans_fn_ref_with_substs(bcx, mth_id, ExprId(expr_id), - callee_substs); - - let callee_ty = node_id_type(bcx, expr_id); - let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to(); - PointerCast(bcx, llfn, llty) + trans_fn_ref_with_substs(ccx, mth_id, ExprId(expr_id), + param_substs, + callee_substs) } _ => { - bcx.tcx().sess.bug( - format!("static call to invalid vtable: {}", - vtbl.repr(bcx.tcx()))[]); + tcx.sess.bug(format!("static call to invalid vtable: {}", + vtbl.repr(tcx))[]); } } } @@ -346,20 +344,22 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx, MethodCallKey(method_call), vtable_impl.substs); // translate the function - let llfn = trans_fn_ref_with_substs(bcx, + let llfn = trans_fn_ref_with_substs(bcx.ccx(), mth_id, MethodCallKey(method_call), - callee_substs); + bcx.fcx.param_substs, + callee_substs).val; Callee { bcx: bcx, data: Fn(llfn) } } traits::VtableUnboxedClosure(closure_def_id, substs) => { // The substitutions should have no type parameters remaining // after passing through fulfill_obligation - let llfn = trans_fn_ref_with_substs(bcx, + let llfn = trans_fn_ref_with_substs(bcx.ccx(), closure_def_id, MethodCallKey(method_call), - substs); + bcx.fcx.param_substs, + substs).val; Callee { bcx: bcx, @@ -400,7 +400,7 @@ fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, { let ccx = bcx.ccx(); - let node_substs = node_id_substs(bcx, node); + let node_substs = node_id_substs(ccx, node, bcx.fcx.param_substs); debug!("rcvr_substs={}", rcvr_substs.repr(ccx.tcx())); debug!("node_substs={}", node_substs.repr(ccx.tcx())); @@ -684,10 +684,11 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } traits::VtableUnboxedClosure(closure_def_id, substs) => { let llfn = trans_fn_ref_with_substs( - bcx, + bcx.ccx(), closure_def_id, ExprId(0), - substs.clone()); + bcx.fcx.param_substs, + substs.clone()).val; (vec!(llfn)).into_iter() } @@ -788,10 +789,11 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Some(C_null(Type::nil(ccx).ptr_to())).into_iter() } else { let fn_ref = trans_fn_ref_with_substs( - bcx, + ccx, m_id, ExprId(0), - substs.clone()); + bcx.fcx.param_substs, + substs.clone()).val; // currently, at least, by-value self is not object safe assert!(m.explicit_self != ty::ByValueExplicitSelfCategory); diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index cc259e6765c34..166c986e4842d 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -38,7 +38,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: ast::DefId, psubsts: &subst::Substs<'tcx>, ref_id: Option) - -> (ValueRef, bool) { + -> (ValueRef, Ty<'tcx>, bool) { debug!("monomorphic_fn(\ fn_id={}, \ real_substs={}, \ @@ -58,11 +58,14 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, params: psubsts.types.clone() }; + let item_ty = ty::lookup_item_type(ccx.tcx(), fn_id).ty; + let mono_ty = item_ty.subst(ccx.tcx(), psubsts); + match ccx.monomorphized().borrow().get(&hash_id) { Some(&val) => { debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id)); - return (val, false); + return (val, mono_ty, false); } None => () } @@ -75,8 +78,6 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, psubsts.repr(ccx.tcx()), hash_id); - let tpt = ty::lookup_item_type(ccx.tcx(), fn_id); - let llitem_ty = tpt.ty; let map_node = session::expect( ccx.sess(), @@ -91,13 +92,12 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if let ast_map::NodeForeignItem(_) = map_node { if ccx.tcx().map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic { // Foreign externs don't have to be monomorphized. - return (get_item_val(ccx, fn_id.node), true); + return (get_item_val(ccx, fn_id.node), mono_ty, true); } } - debug!("monomorphic_fn about to subst into {}", llitem_ty.repr(ccx.tcx())); + debug!("monomorphic_fn about to subst into {}", item_ty.repr(ccx.tcx())); - let mono_ty = llitem_ty.subst(ccx.tcx(), psubsts); debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx())); let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty); @@ -283,7 +283,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.monomorphizing().borrow_mut().insert(fn_id, depth); debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id)); - (lldecl, true) + (lldecl, mono_ty, true) } #[deriving(PartialEq, Eq, Hash, Show)] diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index 688a0d0725058..5b5e6e8188f35 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -19,6 +19,7 @@ use trans::build::*; use trans::cleanup; use trans::cleanup::CleanupMethods; use trans::common::*; +use trans::consts; use trans::datum::*; use trans::expr::{Dest, Ignore, SaveIn}; use trans::expr; @@ -213,15 +214,13 @@ pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, match dest { Ignore => bcx, SaveIn(lldest) => { - unsafe { - let bytes = str_lit.get().len(); - let llbytes = C_uint(bcx.ccx(), bytes); - let llcstr = C_cstr(bcx.ccx(), str_lit, false); - let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p(bcx.ccx()).to_ref()); - Store(bcx, llcstr, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_ADDR])); - Store(bcx, llbytes, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_EXTRA])); - bcx - } + let bytes = str_lit.get().len(); + let llbytes = C_uint(bcx.ccx(), bytes); + let llcstr = C_cstr(bcx.ccx(), str_lit, false); + let llcstr = consts::ptrcast(llcstr, Type::i8p(bcx.ccx())); + Store(bcx, llcstr, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_ADDR])); + Store(bcx, llbytes, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_EXTRA])); + bcx } } } diff --git a/src/test/run-pass/const-polymorphic-paths.rs b/src/test/run-pass/const-polymorphic-paths.rs new file mode 100644 index 0000000000000..46b4dda971b6c --- /dev/null +++ b/src/test/run-pass/const-polymorphic-paths.rs @@ -0,0 +1,83 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(macro_rules)] + +use std::default::Default; +use std::option::IntoIter as OptionIter; +use std::rand::Rand; +use std::rand::XorShiftRng as DummyRng; +// FIXME the glob std::prelude::*; import of Vec is missing non-static inherent methods. +use std::vec::Vec; + +#[deriving(PartialEq, Eq)] +struct Newt(T); + +fn id(x: T) -> T { x } +fn eq(a: T, b: T) -> bool { a == b } +fn u8_as_i8(x: u8) -> i8 { x as i8 } +fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() } + +macro_rules! tests { + ($($expr:expr: $ty:ty /($($test:expr),*);)+) => (pub fn main() {$({ + const C: $ty = $expr; + static S: $ty = $expr; + assert!(eq(C($($test),*), $expr($($test),*))); + assert!(eq(S($($test),*), $expr($($test),*))); + assert!(eq(C($($test),*), S($($test),*))); + })+}) +} + +tests! { + // Free function. + id: fn(int) -> int /(5); + id::: fn(int) -> int /(5); + + // Enum variant constructor. + Some: fn(int) -> Option /(5); + Some::: fn(int) -> Option /(5); + + // Tuple struct constructor. + Newt: fn(int) -> Newt /(5); + Newt::: fn(int) -> Newt /(5); + + // Inherent static methods. + Vec::new: fn() -> Vec<()> /(); + Vec::<()>::new: fn() -> Vec<()> /(); + Vec::with_capacity: fn(uint) -> Vec<()> /(5); + Vec::<()>::with_capacity: fn(uint) -> Vec<()> /(5); + Vec::from_fn: fn(uint, fn(uint) -> uint) -> Vec /(5, id); + Vec::::from_fn: fn(uint, fn(uint) -> uint) -> Vec /(5, id); + Vec::from_fn:: uint>: fn(uint, fn(uint) -> uint) -> Vec /(5, id); + Vec::::from_fn:: uint>: fn(uint, fn(uint) -> uint) -> Vec /(5, id); + + // Inherent non-static method. + Vec::map_in_place: fn(Vec, fn(u8) -> i8) -> Vec + /(vec![b'f', b'o', b'o'], u8_as_i8); + Vec::map_in_place:: i8>: fn(Vec, fn(u8) -> i8) -> Vec + /(vec![b'f', b'o', b'o'], u8_as_i8); + // FIXME these break with "type parameter might not appear here pointing at ``. + // Vec::::map_in_place: fn(Vec, fn(u8) -> i8) -> Vec + // /(vec![b'f', b'o', b'o'], u8_as_i8); + // Vec::::map_in_place:: i8>: fn(Vec, fn(u8) -> i8) -> Vec + // /(vec![b'f', b'o', b'o'], u8_as_i8); + + // Trait static methods. + // FIXME qualified path expressions aka UFCS i.e. ::method. + Default::default: fn() -> int /(); + Rand::rand: fn(&mut DummyRng) -> int /(&mut dummy_rng()); + Rand::rand::: fn(&mut DummyRng) -> int /(&mut dummy_rng()); + + // Trait non-static methods. + Clone::clone: fn(&int) -> int /(&5); + FromIterator::from_iter: fn(OptionIter) -> Vec /(Some(5).into_iter()); + FromIterator::from_iter::>: fn(OptionIter) -> Vec + /(Some(5).into_iter()); +}