diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 4bb69a2688a41..97a550a4076fa 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -148,6 +148,12 @@ declare_lint! { "uses of #[derive] with raw pointers are rarely correct" } +declare_lint! { + pub TRANSMUTE_FROM_FN_ITEM_TYPES, + Warn, + "transmute from function item type to pointer-sized type erroneously allowed" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -177,7 +183,8 @@ impl LintPass for HardwiredLints { INVALID_TYPE_PARAM_DEFAULT, MATCH_OF_UNIT_VARIANT_VIA_PAREN_DOTDOT, CONST_ERR, - RAW_POINTER_DERIVE + RAW_POINTER_DERIVE, + TRANSMUTE_FROM_FN_ITEM_TYPES ) } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 023b972250491..c11e9dc822eb3 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -1287,6 +1287,9 @@ pub fn check_crate(tcx: &TyCtxt, access_levels: &AccessLevels) { } *tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner(); + + // Put the lint store back in the session. + mem::replace(&mut *tcx.sess.lint_store.borrow_mut(), cx.lints); } pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index e3d05388f5218..e6821cf639eca 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -44,7 +44,8 @@ enum RootUnsafeContext { fn type_is_unsafe_function(ty: Ty) -> bool { match ty.sty { - ty::TyBareFn(_, ref f) => f.unsafety == hir::Unsafety::Unsafe, + ty::TyFnDef(_, _, ref f) | + ty::TyFnPtr(ref f) => f.unsafety == hir::Unsafety::Unsafe, _ => false, } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 5ddea6917435e..a87ce1206b408 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -556,7 +556,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { callee, callee_ty); let call_scope = self.tcx().region_maps.node_extent(call.id); match callee_ty.sty { - ty::TyBareFn(..) => { + ty::TyFnDef(..) | ty::TyFnPtr(_) => { self.consume_expr(callee); } ty::TyError => { } diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index b64fa688d5163..6c0dd9b608d56 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -161,7 +161,8 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { ty::TySlice(..) | ty::TyRawPtr(..) | ty::TyRef(..) | - ty::TyBareFn(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | ty::TyTrait(..) | ty::TyStruct(..) | ty::TyClosure(..) | diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index b9a5b32b71d82..1e3546269dbc2 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -454,7 +454,7 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, -> UnitResult<'tcx> { debug!("mk_eqty({:?} <: {:?})", a, b); - cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b)) + cx.eq_types(a_is_expected, origin, a, b) } pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, @@ -466,7 +466,7 @@ pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, { debug!("mk_eq_trait_refs({:?} <: {:?})", a, b); - cx.commit_if_ok(|_| cx.eq_trait_refs(a_is_expected, origin, a.clone(), b.clone())) + cx.eq_trait_refs(a_is_expected, origin, a, b) } pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, @@ -478,7 +478,7 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, { debug!("mk_sub_poly_trait_refs({:?} <: {:?})", a, b); - cx.commit_if_ok(|_| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone())) + cx.sub_poly_trait_refs(a_is_expected, origin, a, b) } fn expected_found(a_is_expected: bool, @@ -1351,18 +1351,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn report_mismatched_types(&self, - span: Span, + origin: TypeOrigin, expected: Ty<'tcx>, actual: Ty<'tcx>, - err: &TypeError<'tcx>) { + err: TypeError<'tcx>) { let trace = TypeTrace { - origin: TypeOrigin::Misc(span), + origin: origin, values: Types(ExpectedFound { expected: expected, found: actual }) }; - self.report_and_explain_type_error(trace, err); + self.report_and_explain_type_error(trace, &err); } pub fn report_conflicting_default_types(&self, diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 7de8904e3f26f..fd857513e5b56 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -12,7 +12,7 @@ use dep_graph::DepNode; use middle::def::Def; use middle::def_id::DefId; use middle::subst::{Subst, Substs, EnumeratedItems}; -use middle::ty::{TransmuteRestriction, TyCtxt, TyBareFn}; +use middle::ty::{TransmuteRestriction, TyCtxt}; use middle::ty::{self, Ty, TypeFoldable}; use std::fmt; @@ -53,7 +53,7 @@ struct IntrinsicCheckingVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { let intrinsic = match self.tcx.lookup_item_type(def_id).ty.sty { - ty::TyBareFn(_, ref bfty) => bfty.abi == RustIntrinsic, + ty::TyFnDef(_, _, ref bfty) => bfty.abi == RustIntrinsic, _ => return false }; intrinsic && self.tcx.item_name(def_id).as_str() == "transmute" @@ -238,7 +238,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for IntrinsicCheckingVisitor<'a, 'tcx> { Def::Fn(did) if self.def_id_is_transmute(did) => { let typ = self.tcx.node_id_to_type(expr.id); match typ.sty { - TyBareFn(_, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { + ty::TyFnDef(_, _, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => { if let ty::FnConverging(to) = bare_fn_ty.sig.0.output { let from = bare_fn_ty.sig.0.inputs[0]; self.check_transmute(expr.span, from, to, expr.id); diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 9cc94402b1651..02dfeb80b928f 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -148,11 +148,11 @@ impl<'tcx> Substs<'tcx> { Substs { types: types, regions: regions } } - pub fn with_method_from(self, + pub fn with_method_from(&self, meth_substs: &Substs<'tcx>) -> Substs<'tcx> { - let Substs { types, regions } = self; + let Substs { types, regions } = self.clone(); let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace)); let regions = regions.map(|r| { r.with_slice(FnSpace, meth_substs.regions().get_slice(FnSpace)) diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index b0970457892bb..b79849e87ffac 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -301,7 +301,8 @@ fn ty_is_local_constructor<'tcx>(tcx: &TyCtxt<'tcx>, ty::TyUint(..) | ty::TyFloat(..) | ty::TyStr | - ty::TyBareFn(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | ty::TyArray(..) | ty::TySlice(..) | ty::TyRawPtr(..) | diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index f0ff0380aaa31..8a2f0c0c09304 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -278,7 +278,7 @@ pub enum Vtable<'tcx, N> { #[derive(Clone, PartialEq, Eq)] pub struct VtableImplData<'tcx, N> { pub impl_def_id: DefId, - pub substs: subst::Substs<'tcx>, + pub substs: &'tcx subst::Substs<'tcx>, pub nested: Vec } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index b19771420bd39..e36307feddbf7 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -948,7 +948,7 @@ fn confirm_impl_candidate<'cx,'tcx>( for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] { if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] { if assoc_ty.name == obligation.predicate.item_name { - return (assoc_ty.ty.unwrap().subst(selcx.tcx(), &impl_vtable.substs), + return (assoc_ty.ty.unwrap().subst(selcx.tcx(), impl_vtable.substs), impl_vtable.nested); } } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 373ec37663f55..2ecfa119007b8 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1286,7 +1286,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // provide an impl, but only for suitable `fn` pointers - ty::TyBareFn(_, &ty::BareFnTy { + ty::TyFnDef(_, _, &ty::BareFnTy { + unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: _, + output: ty::FnConverging(_), + variadic: false + }) + }) | + ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -1646,7 +1655,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | - ty::TyBareFn(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | ty::TyChar => { // safe for everything ok_if(Vec::new()) @@ -1850,7 +1860,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | - ty::TyBareFn(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | ty::TyStr | ty::TyError | ty::TyInfer(ty::IntVar(_)) | @@ -2294,7 +2305,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_obligations.append(&mut substs.obligations); VtableImplData { impl_def_id: impl_def_id, - substs: substs.value, + substs: self.tcx().mk_substs(substs.value), nested: impl_obligations } } diff --git a/src/librustc/middle/traits/structural_impls.rs b/src/librustc/middle/traits/structural_impls.rs index 453420e2a54dc..903b7c80bafab 100644 --- a/src/librustc/middle/traits/structural_impls.rs +++ b/src/librustc/middle/traits/structural_impls.rs @@ -147,9 +147,10 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> { fn super_fold_with>(&self, folder: &mut F) -> Self { + let substs = self.substs.fold_with(folder); traits::VtableImplData { impl_def_id: self.impl_def_id, - substs: self.substs.fold_with(folder), + substs: folder.tcx().mk_substs(substs), nested: self.nested.fold_with(folder), } } diff --git a/src/librustc/middle/ty/adjustment.rs b/src/librustc/middle/ty/adjustment.rs index 40581cfa1c54d..e4c293a74e896 100644 --- a/src/librustc/middle/ty/adjustment.rs +++ b/src/librustc/middle/ty/adjustment.rs @@ -155,8 +155,8 @@ impl<'tcx> ty::TyS<'tcx> { match *adjustment { AdjustReifyFnPointer => { match self.sty { - ty::TyBareFn(Some(_), b) => { - cx.mk_fn(None, b) + ty::TyFnDef(_, _, b) => { + cx.mk_ty(ty::TyFnPtr(b)) } _ => { cx.sess.bug( @@ -168,7 +168,7 @@ impl<'tcx> ty::TyS<'tcx> { AdjustUnsafeFnPointer => { match self.sty { - ty::TyBareFn(None, b) => cx.safe_to_unsafe_fn_ty(b), + ty::TyFnPtr(b) => cx.safe_to_unsafe_fn_ty(b), ref b => { cx.sess.bug( &format!("AdjustUnsafeFnPointer adjustment on non-fn-ptr: \ diff --git a/src/librustc/middle/ty/cast.rs b/src/librustc/middle/ty/cast.rs index 8233b6b2b2b6e..b25d6e0476d98 100644 --- a/src/librustc/middle/ty/cast.rs +++ b/src/librustc/middle/ty/cast.rs @@ -69,7 +69,7 @@ impl<'tcx> CastTy<'tcx> { Some(CastTy::Int(IntTy::CEnum)), ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)), ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)), - ty::TyBareFn(..) => Some(CastTy::FnPtr), + ty::TyFnPtr(..) => Some(CastTy::FnPtr), _ => None, } } diff --git a/src/librustc/middle/ty/contents.rs b/src/librustc/middle/ty/contents.rs index 8dfa0262f2b0d..47a15a14b41ee 100644 --- a/src/librustc/middle/ty/contents.rs +++ b/src/librustc/middle/ty/contents.rs @@ -187,7 +187,7 @@ impl<'tcx> ty::TyS<'tcx> { // Scalar and unique types are sendable, and durable ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | - ty::TyBareFn(..) | ty::TyChar => { + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => { TC::None } diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index ffc52af19bbe1..61a7f49f45d4e 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -41,7 +41,6 @@ use std::borrow::Borrow; use std::cell::{Cell, RefCell, Ref}; use std::hash::{Hash, Hasher}; use std::rc::Rc; -use syntax::abi::Abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::parse::token::special_idents; @@ -734,8 +733,8 @@ impl<'tcx> TyCtxt<'tcx> { pub fn print_debug_stats(&self) { sty_debug_print!( self, - TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyBareFn, TyTrait, - TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection); + TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, + TyTrait, TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection); println!("Substs interner: #{}", self.substs_interner.borrow().len()); println!("BareFnTy interner: #{}", self.bare_fn_interner.borrow().len()); @@ -792,12 +791,11 @@ impl<'tcx> TyCtxt<'tcx> { /// Create an unsafe fn ty based on a safe fn ty. pub fn safe_to_unsafe_fn_ty(&self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> { assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal); - let unsafe_fn_ty_a = self.mk_bare_fn(ty::BareFnTy { + self.mk_fn_ptr(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: bare_fn.abi, sig: bare_fn.sig.clone() - }); - self.mk_fn(None, unsafe_fn_ty_a) + }) } pub fn mk_bare_fn(&self, bare_fn: BareFnTy<'tcx>) -> &'tcx BareFnTy<'tcx> { @@ -946,26 +944,14 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_ty(TyBool) } - pub fn mk_fn(&self, - opt_def_id: Option, - fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> { - self.mk_ty(TyBareFn(opt_def_id, fty)) - } - - pub fn mk_ctor_fn(&self, - def_id: DefId, - input_tys: &[Ty<'tcx>], - output: Ty<'tcx>) -> Ty<'tcx> { - let input_args = input_tys.iter().cloned().collect(); - self.mk_fn(Some(def_id), self.mk_bare_fn(BareFnTy { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: input_args, - output: ty::FnConverging(output), - variadic: false - }) - })) + pub fn mk_fn_def(&self, def_id: DefId, + substs: &'tcx Substs<'tcx>, + fty: BareFnTy<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyFnDef(def_id, substs, self.mk_bare_fn(fty))) + } + + pub fn mk_fn_ptr(&self, fty: BareFnTy<'tcx>) -> Ty<'tcx> { + self.mk_ty(TyFnPtr(self.mk_bare_fn(fty))) } pub fn mk_trait(&self, diff --git a/src/librustc/middle/ty/error.rs b/src/librustc/middle/ty/error.rs index 39a5069e12944..1033af5f331a7 100644 --- a/src/librustc/middle/ty/error.rs +++ b/src/librustc/middle/ty/error.rs @@ -223,8 +223,8 @@ impl<'tcx> ty::TyS<'tcx> { ty::TySlice(_) => "slice".to_string(), ty::TyRawPtr(_) => "*-ptr".to_string(), ty::TyRef(_, _) => "&-ptr".to_string(), - ty::TyBareFn(Some(_), _) => format!("fn item"), - ty::TyBareFn(None, _) => "fn pointer".to_string(), + ty::TyFnDef(..) => format!("fn item"), + ty::TyFnPtr(_) => "fn pointer".to_string(), ty::TyTrait(ref inner) => { format!("trait {}", cx.item_path_str(inner.principal_def_id())) } diff --git a/src/librustc/middle/ty/fast_reject.rs b/src/librustc/middle/ty/fast_reject.rs index a42e5fc2e85f2..fc4db22a8a62f 100644 --- a/src/librustc/middle/ty/fast_reject.rs +++ b/src/librustc/middle/ty/fast_reject.rs @@ -83,7 +83,7 @@ pub fn simplify_type(tcx: &TyCtxt, ty::TyTuple(ref tys) => { Some(TupleSimplifiedType(tys.len())) } - ty::TyBareFn(_, ref f) => { + ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { Some(FunctionSimplifiedType(f.sig.0.inputs.len())) } ty::TyProjection(_) | ty::TyParam(_) => { diff --git a/src/librustc/middle/ty/flags.rs b/src/librustc/middle/ty/flags.rs index a0b03fe8126dd..c491bd6ca5e99 100644 --- a/src/librustc/middle/ty/flags.rs +++ b/src/librustc/middle/ty/flags.rs @@ -134,7 +134,12 @@ impl FlagComputation { self.add_tys(&ts[..]); } - &ty::TyBareFn(_, ref f) => { + &ty::TyFnDef(_, substs, ref f) => { + self.add_substs(substs); + self.add_fn_sig(&f.sig); + } + + &ty::TyFnPtr(ref f) => { self.add_fn_sig(&f.sig); } } diff --git a/src/librustc/middle/ty/outlives.rs b/src/librustc/middle/ty/outlives.rs index fc20c1bcb85fe..9439180a6cd21 100644 --- a/src/librustc/middle/ty/outlives.rs +++ b/src/librustc/middle/ty/outlives.rs @@ -182,7 +182,8 @@ fn compute_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, ty::TyRawPtr(..) | // ... ty::TyRef(..) | // OutlivesReference ty::TyTuple(..) | // ... - ty::TyBareFn(..) | // OutlivesFunction (*) + ty::TyFnDef(..) | // OutlivesFunction (*) + ty::TyFnPtr(_) | // OutlivesFunction (*) ty::TyTrait(..) | // OutlivesObject, OutlivesFragment (*) ty::TyError => { // (*) Bare functions and traits are both binders. In the diff --git a/src/librustc/middle/ty/relate.rs b/src/librustc/middle/ty/relate.rs index 5d6106a6d7747..6da65c85f91db 100644 --- a/src/librustc/middle/ty/relate.rs +++ b/src/librustc/middle/ty/relate.rs @@ -139,11 +139,11 @@ fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R, relate_substs(relation, opt_variances, a_subst, b_subst) } -fn relate_substs<'a,'tcx:'a,R>(relation: &mut R, - variances: Option<&ty::ItemVariances>, - a_subst: &Substs<'tcx>, - b_subst: &Substs<'tcx>) - -> RelateResult<'tcx, Substs<'tcx>> +pub fn relate_substs<'a,'tcx:'a,R>(relation: &mut R, + variances: Option<&ty::ItemVariances>, + a_subst: &Substs<'tcx>, + b_subst: &Substs<'tcx>) + -> RelateResult<'tcx, Substs<'tcx>> where R: TypeRelation<'a,'tcx> { let mut substs = Substs::empty(); @@ -568,11 +568,19 @@ pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, } } - (&ty::TyBareFn(a_opt_def_id, a_fty), &ty::TyBareFn(b_opt_def_id, b_fty)) - if a_opt_def_id == b_opt_def_id => + (&ty::TyFnDef(a_def_id, a_substs, a_fty), + &ty::TyFnDef(b_def_id, b_substs, b_fty)) + if a_def_id == b_def_id => { + let substs = try!(relate_substs(relation, None, a_substs, b_substs)); let fty = try!(relation.relate(a_fty, b_fty)); - Ok(tcx.mk_fn(a_opt_def_id, tcx.mk_bare_fn(fty))) + Ok(tcx.mk_fn_def(a_def_id, tcx.mk_substs(substs), fty)) + } + + (&ty::TyFnPtr(a_fty), &ty::TyFnPtr(b_fty)) => + { + let fty = try!(relation.relate(a_fty, b_fty)); + Ok(tcx.mk_fn_ptr(fty)) } (&ty::TyProjection(ref a_data), &ty::TyProjection(ref b_data)) => diff --git a/src/librustc/middle/ty/structural_impls.rs b/src/librustc/middle/ty/structural_impls.rs index 001ea02a27c3e..3fe9e02a90d42 100644 --- a/src/librustc/middle/ty/structural_impls.rs +++ b/src/librustc/middle/ty/structural_impls.rs @@ -282,9 +282,16 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } ty::TyTrait(ref trait_ty) => ty::TyTrait(trait_ty.fold_with(folder)), ty::TyTuple(ref ts) => ty::TyTuple(ts.fold_with(folder)), - ty::TyBareFn(opt_def_id, ref f) => { + ty::TyFnDef(def_id, substs, ref f) => { + let substs = substs.fold_with(folder); + let bfn = f.fold_with(folder); + ty::TyFnDef(def_id, + folder.tcx().mk_substs(substs), + folder.tcx().mk_bare_fn(bfn)) + } + ty::TyFnPtr(ref f) => { let bfn = f.fold_with(folder); - ty::TyBareFn(opt_def_id, folder.tcx().mk_bare_fn(bfn)) + ty::TyFnPtr(folder.tcx().mk_bare_fn(bfn)) } ty::TyRef(r, ref tm) => { let r = r.fold_with(folder); @@ -318,7 +325,10 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyEnum(_tid, ref substs) => substs.visit_with(visitor), ty::TyTrait(ref trait_ty) => trait_ty.visit_with(visitor), ty::TyTuple(ref ts) => ts.visit_with(visitor), - ty::TyBareFn(_opt_def_id, ref f) => f.visit_with(visitor), + ty::TyFnDef(_, substs, ref f) => { + substs.visit_with(visitor) || f.visit_with(visitor) + } + ty::TyFnPtr(ref f) => f.visit_with(visitor), ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), ty::TyStruct(_did, ref substs) => substs.visit_with(visitor), ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), diff --git a/src/librustc/middle/ty/sty.rs b/src/librustc/middle/ty/sty.rs index c8f8e07383275..2d7b7dc6e9b58 100644 --- a/src/librustc/middle/ty/sty.rs +++ b/src/librustc/middle/ty/sty.rs @@ -127,14 +127,14 @@ pub enum TypeVariants<'tcx> { /// `&a mut T` or `&'a T`. TyRef(&'tcx Region, TypeAndMut<'tcx>), - /// If the def-id is Some(_), then this is the type of a specific - /// fn item. Otherwise, if None(_), it is a fn pointer type. - /// - /// FIXME: Conflating function pointers and the type of a - /// function is probably a terrible idea; a function pointer is a - /// value with a specific type, but a function can be polymorphic - /// or dynamically dispatched. - TyBareFn(Option, &'tcx BareFnTy<'tcx>), + /// The anonymous type of a function declaration/definition. Each + /// function has a unique type. + TyFnDef(DefId, &'tcx Substs<'tcx>, &'tcx BareFnTy<'tcx>), + + /// A pointer to a function. Written as `fn() -> i32`. + /// FIXME: This is currently also used to represent the callee of a method; + /// see ty::MethodCallee etc. + TyFnPtr(&'tcx BareFnTy<'tcx>), /// A trait, defined with `trait`. TyTrait(Box>), @@ -1029,7 +1029,7 @@ impl<'tcx> TyS<'tcx> { match self.sty { TyBool | TyChar | TyInt(_) | TyFloat(_) | TyUint(_) | TyInfer(IntVar(_)) | TyInfer(FloatVar(_)) | - TyBareFn(..) | TyRawPtr(_) => true, + TyFnDef(..) | TyFnPtr(_) | TyRawPtr(_) => true, _ => false } } @@ -1080,20 +1080,6 @@ impl<'tcx> TyS<'tcx> { } } - pub fn is_bare_fn(&self) -> bool { - match self.sty { - TyBareFn(..) => true, - _ => false - } - } - - pub fn is_bare_fn_item(&self) -> bool { - match self.sty { - TyBareFn(Some(_), _) => true, - _ => false - } - } - pub fn is_fp(&self) -> bool { match self.sty { TyInfer(FloatVar(_)) | TyFloat(_) => true, @@ -1154,7 +1140,7 @@ impl<'tcx> TyS<'tcx> { pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> { match self.sty { - TyBareFn(_, ref f) => &f.sig, + TyFnDef(_, _, ref f) | TyFnPtr(ref f) => &f.sig, _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self) } } @@ -1162,7 +1148,7 @@ impl<'tcx> TyS<'tcx> { /// Returns the ABI of the given function. pub fn fn_abi(&self) -> abi::Abi { match self.sty { - TyBareFn(_, ref f) => f.abi, + TyFnDef(_, _, ref f) | TyFnPtr(ref f) => f.abi, _ => panic!("Ty::fn_abi() called on non-fn type"), } } @@ -1178,7 +1164,7 @@ impl<'tcx> TyS<'tcx> { pub fn is_fn(&self) -> bool { match self.sty { - TyBareFn(..) => true, + TyFnDef(..) | TyFnPtr(_) => true, _ => false } } @@ -1224,7 +1210,8 @@ impl<'tcx> TyS<'tcx> { TyProjection(ref data) => { data.trait_ref.substs.regions().as_slice().to_vec() } - TyBareFn(..) | + TyFnDef(..) | + TyFnPtr(_) | TyBool | TyChar | TyInt(_) | diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs index 7c32d931fffcb..2b83aaccdc46b 100644 --- a/src/librustc/middle/ty/util.rs +++ b/src/librustc/middle/ty/util.rs @@ -514,9 +514,12 @@ impl<'tcx> TyCtxt<'tcx> { region(state, *r); mt(state, m); } - TyBareFn(opt_def_id, ref b) => { + TyFnDef(def_id, _, _) => { byte!(14); - hash!(opt_def_id); + hash!(def_id); + } + TyFnPtr(ref b) => { + byte!(15); hash!(b.unsafety); hash!(b.abi); fn_sig(state, &b.sig); @@ -599,14 +602,14 @@ impl<'tcx> TyCtxt<'tcx> { #[derive(Debug)] pub struct ImplMethod<'tcx> { pub method: Rc>, - pub substs: Substs<'tcx>, + pub substs: &'tcx Substs<'tcx>, pub is_provided: bool } impl<'tcx> TyCtxt<'tcx> { pub fn get_impl_method(&self, impl_def_id: DefId, - substs: Substs<'tcx>, + substs: &'tcx Substs<'tcx>, name: Name) -> ImplMethod<'tcx> { @@ -633,9 +636,10 @@ impl<'tcx> TyCtxt<'tcx> { if meth.name == name { let impl_to_trait_substs = self .make_substs_for_receiver_types(&trait_ref, meth); + let substs = impl_to_trait_substs.subst(self, substs); return ImplMethod { method: meth.clone(), - substs: impl_to_trait_substs.subst(self, &substs), + substs: self.mk_substs(substs), is_provided: true } } @@ -677,7 +681,7 @@ impl<'tcx> ty::TyS<'tcx> { // Fast-path for primitive types let result = match self.sty { TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyRawPtr(..) | TyBareFn(..) | TyRef(_, TypeAndMut { + TyRawPtr(..) | TyFnDef(..) | TyFnPtr(_) | TyRef(_, TypeAndMut { mutbl: hir::MutImmutable, .. }) => Some(false), @@ -719,7 +723,7 @@ impl<'tcx> ty::TyS<'tcx> { // Fast-path for primitive types let result = match self.sty { TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyBox(..) | TyRawPtr(..) | TyRef(..) | TyBareFn(..) | + TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | TyArray(..) | TyTuple(..) | TyClosure(..) => Some(true), TyStr | TyTrait(..) | TySlice(_) => Some(false), diff --git a/src/librustc/middle/ty/walk.rs b/src/librustc/middle/ty/walk.rs index 81cad4486904b..b6d93ecf78b88 100644 --- a/src/librustc/middle/ty/walk.rs +++ b/src/librustc/middle/ty/walk.rs @@ -98,7 +98,11 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { ty::TyTuple(ref ts) => { push_reversed(stack, ts); } - ty::TyBareFn(_, ref ft) => { + ty::TyFnDef(_, substs, ref ft) => { + push_reversed(stack, substs.types.as_slice()); + push_sig_subtypes(stack, &ft.sig); + } + ty::TyFnPtr(ref ft) => { push_sig_subtypes(stack, &ft.sig); } } diff --git a/src/librustc/middle/ty/wf.rs b/src/librustc/middle/ty/wf.rs index c6d1bc8d64958..5f81d27a1f688 100644 --- a/src/librustc/middle/ty/wf.rs +++ b/src/librustc/middle/ty/wf.rs @@ -354,8 +354,8 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> { // WFedness.) } - ty::TyBareFn(..) => { - // let the loop iterator into the argument/return + ty::TyFnDef(..) | ty::TyFnPtr(_) => { + // let the loop iterate into the argument/return // types appearing in the fn signature } diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index ce7b1ceb35540..4556611df594b 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -861,20 +861,10 @@ impl<'tcx> Debug for TypedConstVal<'tcx> { } } -#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)] -pub enum ItemKind { - Constant, - /// This is any sort of callable (usually those that have a type of `fn(…) -> …`). This - /// includes functions, constructors, but not methods which have their own ItemKind. - Function, - Method, -} - #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] pub enum Literal<'tcx> { Item { def_id: DefId, - kind: ItemKind, substs: &'tcx Substs<'tcx>, }, Value { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 9c92208191e9c..8fd784cbde7a7 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -13,7 +13,7 @@ use middle::def_id::DefId; use middle::subst::{self, Subst}; use middle::ty::{BrAnon, BrEnv, BrFresh, BrNamed}; use middle::ty::{TyBool, TyChar, TyStruct, TyEnum}; -use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyBareFn}; +use middle::ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use middle::ty::{TyParam, TyRawPtr, TyRef, TyTuple}; use middle::ty::TyClosure; use middle::ty::{TyBox, TyTrait, TyInt, TyUint, TyInfer}; @@ -812,7 +812,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { } write!(f, ")") } - TyBareFn(opt_def_id, ref bare_fn) => { + TyFnDef(def_id, substs, ref bare_fn) => { if bare_fn.unsafety == hir::Unsafety::Unsafe { try!(write!(f, "unsafe ")); } @@ -822,13 +822,30 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { } try!(write!(f, "{}", bare_fn.sig.0)); + try!(ty::tls::with(|tcx| { + write!(f, " {{{}", tcx.item_path_str(def_id)) + })); + + let tps = substs.types.get_slice(subst::FnSpace); + if tps.len() >= 1 { + try!(write!(f, "::<{}", tps[0])); + for &ty in &tps[1..] { + try!(write!(f, ", {}", ty)); + } + try!(write!(f, ">")); + } + write!(f, "}}") + } + TyFnPtr(ref bare_fn) => { + if bare_fn.unsafety == hir::Unsafety::Unsafe { + try!(write!(f, "unsafe ")); + } - if let Some(def_id) = opt_def_id { - try!(write!(f, " {{{}}}", ty::tls::with(|tcx| { - tcx.item_path_str(def_id) - }))); + if bare_fn.abi != Abi::Rust { + try!(write!(f, "extern {} ", bare_fn.abi)); } - Ok(()) + + write!(f, "{}", bare_fn.sig.0) } TyInfer(infer_ty) => write!(f, "{}", infer_ty), TyError => write!(f, "[type error]"), diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index abeaffe80ab0b..ce84147559c19 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -261,16 +261,15 @@ impl<'a, 'tcx> Env<'a, 'tcx> { pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> { let input_args = input_tys.iter().cloned().collect(); - self.infcx.tcx.mk_fn(None, - self.infcx.tcx.mk_bare_fn(ty::BareFnTy { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - sig: ty::Binder(ty::FnSig { - inputs: input_args, - output: ty::FnConverging(output_ty), - variadic: false, - }), - })) + self.infcx.tcx.mk_fn_ptr(ty::BareFnTy { + unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: input_args, + output: ty::FnConverging(output_ty), + variadic: false, + }), + }) } pub fn t_nil(&self) -> Ty<'tcx> { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 86ab8d45e4e1d..0c906f8eb546c 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1065,7 +1065,7 @@ impl LateLintPass for MutableTransmutes { } let typ = cx.tcx.node_id_to_type(expr.id); match typ.sty { - ty::TyBareFn(_, ref bare_fn) if bare_fn.abi == RustIntrinsic => { + ty::TyFnDef(_, _, ref bare_fn) if bare_fn.abi == RustIntrinsic => { if let ty::FnConverging(to) = bare_fn.sig.0.output { let from = bare_fn.sig.0.inputs[0]; return Some((&from.sty, &to.sty)); @@ -1079,7 +1079,7 @@ impl LateLintPass for MutableTransmutes { fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool { match cx.tcx.lookup_item_type(def_id).ty.sty { - ty::TyBareFn(_, ref bfty) if bfty.abi == RustIntrinsic => (), + ty::TyFnDef(_, _, ref bfty) if bfty.abi == RustIntrinsic => (), _ => return false } cx.tcx.with_path(def_id, |path| match path.last() { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 1cf0339c086e5..e47f67dad8fcf 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -171,6 +171,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { reference: "RFC 218 ", }, + FutureIncompatibleInfo { + id: LintId::of(TRANSMUTE_FROM_FN_ITEM_TYPES), + reference: "issue #19925 ", + }, ]); // We have one lint pass defined specially diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index c7cb2d15a092f..10535549ceb77 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -391,7 +391,7 @@ fn is_repr_nullable_ptr<'tcx>(tcx: &TyCtxt<'tcx>, if def.variants[data_idx].fields.len() == 1 { match def.variants[data_idx].fields[0].ty(tcx, substs).sty { - ty::TyBareFn(None, _) => { return true; } + ty::TyFnPtr(_) => { return true; } ty::TyRef(..) => { return true; } _ => { } } @@ -556,7 +556,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { self.check_type_for_ffi(cache, ty) } - ty::TyBareFn(None, bare_fn) => { + ty::TyFnPtr(bare_fn) => { match bare_fn.abi { Abi::Rust | Abi::RustIntrinsic | @@ -595,7 +595,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::TyParam(..) | ty::TyInfer(..) | ty::TyError | ty::TyClosure(..) | ty::TyProjection(..) | - ty::TyBareFn(Some(_), _) => { + ty::TyFnDef(..) => { panic!("Unexpected type in foreign function") } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e286e028f3330..72bf9633c3e7a 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -472,7 +472,7 @@ pub fn get_adt_def<'tcx>(intr: &IdentInterner, variant.name, ctor_ty); let field_tys = match ctor_ty.sty { - ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { + ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { ref inputs, .. }), ..}) => { // tuple-struct constructors don't have escaping regions @@ -988,7 +988,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc, let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics); let ity = tcx.lookup_item_type(def_id).ty; let fty = match ity.sty { - ty::TyBareFn(_, fty) => fty.clone(), + ty::TyFnDef(_, _, fty) => fty.clone(), _ => tcx.sess.bug(&format!( "the type {:?} of the method {:?} is not a function?", ity, name)) @@ -1582,7 +1582,8 @@ pub fn is_extern_item(cdata: Cmd, id: DefIndex, tcx: &TyCtxt) -> bool { let ty::TypeScheme { generics, ty } = get_type(cdata, id, tcx); let no_generics = generics.types.is_empty(); match ty.sty { - ty::TyBareFn(_, fn_ty) if fn_ty.abi != Abi::Rust => return no_generics, + ty::TyFnDef(_, _, fn_ty) | ty::TyFnPtr(fn_ty) + if fn_ty.abi != Abi::Rust => return no_generics, _ => no_generics, } }, diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index bf5a97232fcc7..e9b23eb045856 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -380,10 +380,11 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } 'F' => { let def_id = self.parse_def(); - return tcx.mk_fn(Some(def_id), tcx.mk_bare_fn(self.parse_bare_fn_ty())); + let substs = self.tcx.mk_substs(self.parse_substs()); + return tcx.mk_fn_def(def_id, substs, self.parse_bare_fn_ty()); } 'G' => { - return tcx.mk_fn(None, tcx.mk_bare_fn(self.parse_bare_fn_ty())); + return tcx.mk_fn_ptr(self.parse_bare_fn_ty()); } '#' => { // This is a hacky little caching scheme. The idea is that if we encode diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 7289cd2b5b3b8..a6601e591ab67 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -135,12 +135,13 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx ty::TyStr => { write!(w, "v"); } - ty::TyBareFn(Some(def_id), f) => { + ty::TyFnDef(def_id, substs, f) => { write!(w, "F"); write!(w, "{}|", (cx.ds)(def_id)); + enc_substs(w, cx, substs); enc_bare_fn_ty(w, cx, f); } - ty::TyBareFn(None, f) => { + ty::TyFnPtr(f) => { write!(w, "G"); enc_bare_fn_ty(w, cx, f); } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index ca00b99b10898..a7f4a53b022e1 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -239,7 +239,9 @@ impl<'a,'tcx> Builder<'a,'tcx> { } ExprKind::Call { ty, fun, args } => { let diverges = match ty.sty { - ty::TyBareFn(_, ref f) => f.sig.0.output.diverges(), + ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { + f.sig.0.output.diverges() + } _ => false }; let fun = unpack!(block = this.as_operand(block, fun)); diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 5d040bcb40ad8..8c435b45daeff 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -12,7 +12,6 @@ //! kind of thing. use build::Builder; -use hair::*; use rustc::middle::ty::Ty; use rustc::mir::repr::*; use std::u32; @@ -59,16 +58,4 @@ impl<'a,'tcx> Builder<'a,'tcx> { }); temp } - - pub fn item_ref_operand(&mut self, - span: Span, - item_ref: ItemRef<'tcx>) - -> Operand<'tcx> { - let literal = Literal::Item { - def_id: item_ref.def_id, - kind: item_ref.kind, - substs: item_ref.substs, - }; - self.literal_operand(span, item_ref.ty, literal) - } } diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 6b1b3a33d3d79..3d14ad2374bb4 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -503,7 +503,6 @@ impl<'a,'tcx> Builder<'a,'tcx> { ty: self.hir.tcx().lookup_item_type(funcdid).ty, literal: Literal::Item { def_id: funcdid, - kind: ItemKind::Function, substs: self.hir.tcx().mk_substs(Substs::empty()) } } @@ -641,7 +640,6 @@ fn build_free<'tcx>(tcx: &TyCtxt<'tcx>, ty: tcx.lookup_item_type(free_func).ty.subst(tcx, substs), literal: Literal::Item { def_id: free_func, - kind: ItemKind::Function, substs: substs } }), diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 1a8558b063aa2..cbd6bed81a68f 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -61,7 +61,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { let method = method_callee(cx, self, ty::MethodCall::expr(self.id)); let sig = match method.ty.sty { - ty::TyBareFn(_, fn_ty) => &fn_ty.sig, + ty::TyFnDef(_, _, fn_ty) => &fn_ty.sig, _ => cx.tcx.sess.span_bug(self.span, "type of method is not an fn") }; @@ -581,7 +581,6 @@ fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, kind: ExprKind::Literal { literal: Literal::Item { def_id: callee.def_id, - kind: ItemKind::Method, substs: callee.substs, }, }, @@ -618,14 +617,13 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs); // Otherwise there may be def_map borrow conflicts let def = cx.tcx.def_map.borrow()[&expr.id].full_def(); - let (def_id, kind) = match def { + let def_id = match def { // A regular function. - Def::Fn(def_id) => (def_id, ItemKind::Function), - Def::Method(def_id) => (def_id, ItemKind::Method), + Def::Fn(def_id) | Def::Method(def_id) => def_id, Def::Struct(def_id) => match cx.tcx.node_id_to_type(expr.id).sty { // A tuple-struct constructor. Should only be reached if not called in the same // expression. - ty::TyBareFn(..) => (def_id, ItemKind::Function), + ty::TyFnDef(..) => def_id, // A unit struct which is used as a value. We return a completely different ExprKind // here to account for this special case. ty::TyStruct(adt_def, substs) => return ExprKind::Adt { @@ -640,7 +638,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) Def::Variant(enum_id, variant_id) => match cx.tcx.node_id_to_type(expr.id).sty { // A variant constructor. Should only be reached if not called in the same // expression. - ty::TyBareFn(..) => (variant_id, ItemKind::Function), + ty::TyFnDef(..) => variant_id, // A unit variant, similar special case to the struct case above. ty::TyEnum(adt_def, substs) => { debug_assert!(adt_def.did == enum_id); @@ -660,7 +658,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) if let Some(v) = cx.try_const_eval_literal(expr) { return ExprKind::Literal { literal: v }; } else { - (def_id, ItemKind::Constant) + def_id } } @@ -677,7 +675,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) &format!("def `{:?}` not yet implemented", def)), }; ExprKind::Literal { - literal: Literal::Item { def_id: def_id, kind: kind, substs: substs } + literal: Literal::Item { def_id: def_id, substs: substs } } } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 707dd972003ff..6a22dce7af9d2 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -14,7 +14,7 @@ //! unit-tested and separated from the Rust source and compiler data //! structures. -use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, ItemKind, +use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, TypedConstVal}; use rustc::middle::const_eval::ConstVal; use rustc::middle::def_id::DefId; @@ -28,14 +28,6 @@ use self::cx::Cx; pub mod cx; -#[derive(Clone, Debug)] -pub struct ItemRef<'tcx> { - pub ty: Ty<'tcx>, - pub kind: ItemKind, - pub def_id: DefId, - pub substs: &'tcx Substs<'tcx>, -} - #[derive(Clone, Debug)] pub struct Block<'tcx> { pub extent: CodeExtent, diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index bf22c7b0b8b34..e021300f1b397 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -421,7 +421,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let func_ty = mir.operand_ty(tcx, func); debug!("check_terminator: call, func_ty={:?}", func_ty); let func_ty = match func_ty.sty { - ty::TyBareFn(_, func_ty) => func_ty, + ty::TyFnDef(_, _, func_ty) | ty::TyFnPtr(func_ty) => func_ty, _ => { span_mirbug!(self, term, "call to non-function {:?}", func_ty); return; diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 810712bb0cf18..3a39a3c6dd194 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -582,7 +582,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, v.add_qualif(ConstQualif::NON_ZERO_SIZED); } Some(Def::Struct(..)) => { - if let ty::TyBareFn(..) = node_ty.sty { + if let ty::TyFnDef(..) = node_ty.sty { // Count the function pointer. v.add_qualif(ConstQualif::NON_ZERO_SIZED); } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 214ac81ee5092..2acae3fa01ddc 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -857,7 +857,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { if let Def::Struct(..) = self.tcx.resolve_expr(expr) { let expr_ty = self.tcx.expr_ty(expr); let def = match expr_ty.sty { - ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { + ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { output: ty::FnConverging(ty), .. }), ..}) => ty, _ => expr_ty diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index e8368f1bd971c..c5508a8268fe2 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -451,8 +451,8 @@ fn find_discr_field_candidate<'tcx>(tcx: &TyCtxt<'tcx>, // Regular thin pointer: &T/&mut T/Box ty::TyRef(..) | ty::TyBox(..) => Some(path), - // Functions are just pointers - ty::TyBareFn(..) => Some(path), + // Function pointer: `fn() -> i32` + ty::TyFnPtr(_) => Some(path), // Is this the NonZero lang item wrapping a pointer or integer type? ty::TyStruct(def, substs) if Some(def.did) == tcx.lang_items.non_zero() => { diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs index 33370abc3fcc1..98e9a1c98ad84 100644 --- a/src/librustc_trans/trans/asm.rs +++ b/src/librustc_trans/trans/asm.rs @@ -50,7 +50,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) expr_ty(bcx, &out.expr), out_datum, cleanup::CustomScope(temp_scope), - callee::DontAutorefArg, &mut inputs); if out.is_rw { ext_inputs.push(*inputs.last().unwrap()); @@ -64,7 +63,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) expr_ty(bcx, &out.expr), out_datum, cleanup::CustomScope(temp_scope), - callee::DontAutorefArg, &mut ext_inputs); ext_constraints.push(i.to_string()); } @@ -80,7 +78,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) expr_ty(bcx, &input), in_datum, cleanup::CustomScope(temp_scope), - callee::DontAutorefArg, &mut inputs); } inputs.extend_from_slice(&ext_inputs[..]); diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs index 8f9648b333b82..009d43e813ebc 100644 --- a/src/librustc_trans/trans/attributes.rs +++ b/src/librustc_trans/trans/attributes.rs @@ -131,7 +131,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx let function_type; let (fn_sig, abi, env_ty) = match fn_type.sty { - ty::TyBareFn(_, ref f) => (&f.sig, f.abi, None), + ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => (&f.sig, f.abi, None), ty::TyClosure(closure_did, ref substs) => { let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables); function_type = infcx.closure_type(closure_did, substs); @@ -162,7 +162,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx _ => ccx.sess().bug("expected tuple'd inputs") } }, - ty::TyBareFn(..) if abi == Abi::RustCall => { + ty::TyFnDef(..) | ty::TyFnPtr(_) if abi == Abi::RustCall => { let mut inputs = vec![fn_sig.inputs[0]]; match fn_sig.inputs[1].sty { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 8f9608926b9b7..5088dabfbe78e 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -195,16 +195,14 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, name: &str, - did: DefId) + attrs: &[ast::Attribute]) -> ValueRef { if let Some(n) = ccx.externs().borrow().get(name) { return *n; } let f = declare::declare_rust_fn(ccx, name, fn_ty); - - let attrs = ccx.sess().cstore.item_attrs(did); - attributes::from_fn_attrs(ccx, &attrs[..], f); + attributes::from_fn_attrs(ccx, &attrs, f); ccx.externs().borrow_mut().insert(name.to_string(), f); f @@ -390,7 +388,7 @@ pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, _ => bcx.sess().bug("compare_scalar_types: must be a comparison operator"), } } - ty::TyBareFn(..) | ty::TyBool | ty::TyUint(_) | ty::TyChar => { + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyBool | ty::TyUint(_) | ty::TyChar => { ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), op, false), lhs, @@ -621,8 +619,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, source: Ty<'tcx>, target: Ty<'tcx>, - old_info: Option, - param_substs: &'tcx Substs<'tcx>) + old_info: Option) -> ValueRef { let (source, target) = ccx.tcx().struct_lockstep_tails(source, target); match (&source.sty, &target.sty) { @@ -641,7 +638,7 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>, def_id: principal.def_id(), substs: substs, }); - consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs), + consts::ptrcast(meth::get_vtable(ccx, trait_ref), Type::vtable_ptr(ccx)) } _ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {:?} -> {:?}", @@ -668,7 +665,7 @@ pub fn unsize_thin_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, assert!(common::type_is_sized(bcx.tcx(), a)); let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), b).ptr_to(); (PointerCast(bcx, src, ptr_ty), - unsized_info(bcx.ccx(), a, b, None, bcx.fcx.param_substs)) + unsized_info(bcx.ccx(), a, b, None)) } _ => bcx.sess().bug("unsize_thin_ptr: called on bad types"), } @@ -900,29 +897,31 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(cx: Block<'blk, 'tcx>, } } -pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - did: DefId, - t: Ty<'tcx>) - -> ValueRef { - let name = ccx.sess().cstore.item_symbol(did); - match t.sty { - ty::TyBareFn(_, ref fn_ty) => { - match ccx.sess().target.target.adjust_abi(fn_ty.abi) { - Abi::Rust | Abi::RustCall => { - get_extern_rust_fn(ccx, t, &name[..], did) - } +pub fn get_extern_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + def_id: DefId) + -> datum::Datum<'tcx, datum::Rvalue> { + let name = ccx.sess().cstore.item_symbol(def_id); + let attrs = ccx.sess().cstore.item_attrs(def_id); + let ty = ccx.tcx().lookup_item_type(def_id).ty; + match ty.sty { + ty::TyFnDef(_, _, fty) => { + let abi = fty.abi; + let fty = infer::normalize_associated_type(ccx.tcx(), fty); + let ty = ccx.tcx().mk_fn_ptr(fty); + let llfn = match ccx.sess().target.target.adjust_abi(abi) { Abi::RustIntrinsic | Abi::PlatformIntrinsic => { - ccx.sess().bug("unexpected intrinsic in trans_external_path") + ccx.sess().bug("unexpected intrinsic in get_extern_fn") + } + Abi::Rust | Abi::RustCall => { + get_extern_rust_fn(ccx, ty, &name, &attrs) } _ => { - let attrs = ccx.sess().cstore.item_attrs(did); - foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name, &attrs) + foreign::register_foreign_item_fn(ccx, abi, ty, &name, &attrs) } - } - } - _ => { - get_extern_const(ccx, did, t) + }; + datum::immediate_rvalue(llfn, ty) } + _ => unreachable!("get_extern_fn: expected fn item type, found {}", ty) } } @@ -2610,7 +2609,7 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, node_id: ast::NodeId, node_type: Ty<'tcx>) -> ValueRef { - if let ty::TyBareFn(_, ref f) = node_type.sty { + if let ty::TyFnDef(_, _, ref f) = node_type.sty { if f.abi != Abi::Rust && f.abi != Abi::RustCall { ccx.sess().span_bug(sp, &format!("only the `{}` or `{}` calling conventions are valid \ @@ -2685,8 +2684,7 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) { .as_local_node_id(start_def_id) { get_item_val(ccx, start_node_id) } else { - let start_fn_type = ccx.tcx().lookup_item_type(start_def_id).ty; - trans_external_path(ccx, start_def_id, start_fn_type) + get_extern_fn(ccx, start_def_id).val }; let args = { let opaque_rust_main = @@ -2915,7 +2913,7 @@ fn register_method(ccx: &CrateContext, let sym = exported_name(ccx, id, mty, &attrs); - if let ty::TyBareFn(_, ref f) = mty.sty { + if let ty::TyFnDef(_, _, ref f) = mty.sty { let llfn = if f.abi == Abi::Rust || f.abi == Abi::RustCall { register_fn(ccx, span, sym, id, mty) } else { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 85660f1641ded..05e5ac808d030 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -14,7 +14,6 @@ //! and methods are represented as just a fn ptr and not a full //! closure. -pub use self::AutorefArg::*; pub use self::CalleeData::*; pub use self::CallArgs::*; @@ -22,7 +21,6 @@ use arena::TypedArena; use back::link; use llvm::{self, ValueRef, get_params}; use middle::cstore::LOCAL_CRATE; -use middle::def::Def; use middle::def_id::DefId; use middle::infer; use middle::subst; @@ -32,14 +30,13 @@ use trans::adt; use trans::base; use trans::base::*; use trans::build::*; -use trans::callee; use trans::cleanup; use trans::cleanup::CleanupMethods; use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext, ExprOrMethodCall, FunctionContext, MethodCallKey}; use trans::consts; use trans::datum::*; -use trans::debuginfo::{DebugLoc, ToDebugLoc}; +use trans::debuginfo::DebugLoc; use trans::declare; use trans::expr; use trans::glue; @@ -52,177 +49,148 @@ use trans::type_::Type; use trans::type_of; use trans::Disr; use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use middle::ty::MethodCall; use rustc_front::hir; use syntax::abi::Abi; use syntax::ast; +use syntax::codemap::DUMMY_SP; use syntax::errors; use syntax::ptr::P; -#[derive(Copy, Clone)] -pub struct MethodData { - pub llfn: ValueRef, - pub llself: ValueRef, -} - pub enum CalleeData<'tcx> { - // Constructor for enum variant/tuple-like-struct - // i.e. Some, Ok + /// Constructor for enum variant/tuple-like-struct. NamedTupleConstructor(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). - Fn(/* llfn */ ValueRef), + /// Function pointer. + Fn(ValueRef), - Intrinsic(ast::NodeId, subst::Substs<'tcx>), + Intrinsic(ast::NodeId, &'tcx subst::Substs<'tcx>), - TraitItem(MethodData) + /// Trait object found in the vtable at that index. + Virtual(usize) } -pub struct Callee<'blk, 'tcx: 'blk> { - pub bcx: Block<'blk, 'tcx>, +pub struct Callee<'tcx> { pub data: CalleeData<'tcx>, pub ty: Ty<'tcx> } -fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr) - -> Callee<'blk, 'tcx> { - let _icx = push_ctxt("trans_callee"); - debug!("callee::trans(expr={:?})", expr); - - // pick out special kinds of expressions that can be called: - match expr.node { - hir::ExprPath(..) => { - return trans_def(bcx, bcx.def(expr.id), expr); +impl<'tcx> Callee<'tcx> { + /// Function pointer. + pub fn ptr(datum: Datum<'tcx, Rvalue>) -> Callee<'tcx> { + Callee { + data: Fn(datum.val), + ty: datum.ty } - _ => {} } - // any other expressions are closures: - return datum_callee(bcx, expr); - - fn datum_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr) - -> Callee<'blk, 'tcx> { - let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr); - match datum.ty.sty { - ty::TyBareFn(..) => { - Callee { - bcx: bcx, - ty: datum.ty, - data: Fn(datum.to_llscalarish(bcx)) - } - } - _ => { - bcx.tcx().sess.span_bug( - expr.span, - &format!("type of callee is neither bare-fn nor closure: {}", - datum.ty)); - } - } + /// Trait or impl method call. + pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>, + method_call: ty::MethodCall) + -> Callee<'tcx> { + let method = bcx.tcx().tables.borrow().method_map[&method_call]; + Callee::method(bcx, method) } - fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Rvalue>) - -> Callee<'blk, 'tcx> { - Callee { - bcx: bcx, - data: Fn(datum.val), - ty: datum.ty - } + /// Trait or impl method. + pub fn method<'blk>(bcx: Block<'blk, 'tcx>, + method: ty::MethodCallee<'tcx>) -> Callee<'tcx> { + let substs = bcx.tcx().mk_substs(bcx.fcx.monomorphize(&method.substs)); + let ty = bcx.fcx.monomorphize(&method.ty); + Callee::def(bcx.ccx(), method.def_id, substs, ty) } - fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - def: Def, - ref_expr: &hir::Expr) - -> Callee<'blk, 'tcx> { - debug!("trans_def(def={:?}, ref_expr={:?})", def, ref_expr); - let expr_ty = common::node_id_type(bcx, ref_expr.id); - match def { - Def::Fn(did) if { - let maybe_def_id = inline::get_local_instance(bcx.ccx(), did); - let maybe_ast_node = maybe_def_id.and_then(|def_id| { - let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap(); - bcx.tcx().map.find(node_id) - }); - match maybe_ast_node { - Some(hir_map::NodeStructCtor(_)) => true, - _ => false - } - } => { - Callee { - bcx: bcx, + /// Function or method definition. + pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>, + def_id: DefId, + substs: &'tcx subst::Substs<'tcx>, + ty: Ty<'tcx>) + -> Callee<'tcx> { + let tcx = ccx.tcx(); + + if substs.self_ty().is_some() { + // Only trait methods can have a Self parameter. + let method_item = tcx.impl_or_trait_item(def_id); + let trait_id = method_item.container().id(); + let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id)); + let vtbl = common::fulfill_obligation(ccx, DUMMY_SP, trait_ref); + return meth::callee_for_trait_impl(ccx, def_id, substs, + trait_id, ty, vtbl); + } + + let maybe_node_id = inline::get_local_instance(ccx, def_id) + .and_then(|def_id| tcx.map.as_local_node_id(def_id)); + let maybe_ast_node = maybe_node_id.and_then(|node_id| { + tcx.map.find(node_id) + }); + match maybe_ast_node { + Some(hir_map::NodeStructCtor(_)) => { + return Callee { data: NamedTupleConstructor(Disr(0)), - ty: expr_ty - } - } - Def::Fn(did) if match expr_ty.sty { - ty::TyBareFn(_, ref f) => f.abi == Abi::RustIntrinsic || - f.abi == Abi::PlatformIntrinsic, - _ => false - } => { - let substs = common::node_id_substs(bcx.ccx(), - ExprId(ref_expr.id), - bcx.fcx.param_substs); - let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did); - let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap(); - Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty } - } - Def::Fn(did) => { - fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id), - bcx.fcx.param_substs)) - } - Def::Method(meth_did) => { - let method_item = bcx.tcx().impl_or_trait_item(meth_did); - let fn_datum = match method_item.container() { - ty::ImplContainer(_) => { - trans_fn_ref(bcx.ccx(), meth_did, - ExprId(ref_expr.id), - bcx.fcx.param_substs) - } - ty::TraitContainer(trait_did) => { - meth::trans_static_method_callee(bcx.ccx(), - meth_did, - trait_did, - ref_expr.id, - bcx.fcx.param_substs) - } + ty: ty }; - fn_callee(bcx, fn_datum) } - Def::Variant(tid, vid) => { - let vinfo = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid); + Some(hir_map::NodeVariant(_)) => { + let vinfo = common::inlined_variant_def(ccx, maybe_node_id.unwrap()); assert_eq!(vinfo.kind(), ty::VariantKind::Tuple); - Callee { - bcx: bcx, + return Callee { data: NamedTupleConstructor(Disr::from(vinfo.disr_val)), - ty: expr_ty - } + ty: ty + }; } - Def::Struct(..) => { - Callee { - bcx: bcx, - data: NamedTupleConstructor(Disr(0)), - ty: expr_ty + Some(hir_map::NodeForeignItem(fi)) => { + let abi = tcx.map.get_foreign_abi(fi.id); + if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { + return Callee { + data: Intrinsic(fi.id, substs), + ty: ty + }; } } - Def::Static(..) | - Def::Const(..) | - Def::AssociatedConst(..) | - Def::Local(..) | - Def::Upvar(..) => { - datum_callee(bcx, ref_expr) - } - Def::Mod(..) | Def::ForeignMod(..) | Def::Trait(..) | - Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(..) | - Def::AssociatedTy(..) | Def::Label(..) | Def::TyParam(..) | - Def::SelfTy(..) | Def::Err => { - bcx.tcx().sess.span_bug( - ref_expr.span, - &format!("cannot translate def {:?} \ - to a callable thing!", def)); + _ => {} + } + Callee::ptr(trans_fn_ref_with_substs(ccx, def_id, Some(ty), substs)) + } + + /// This behemoth of a function translates function calls. Unfortunately, in + /// order to generate more efficient LLVM output at -O0, it has quite a complex + /// signature (refactoring this into two functions seems like a good idea). + /// + /// In particular, for lang items, it is invoked with a dest of None, and in + /// that case the return value contains the result of the fn. The lang item must + /// not return a structural type or else all heck breaks loose. + /// + /// For non-lang items, `dest` is always Some, and hence the result is written + /// into memory somewhere. Nonetheless we return the actual return value of the + /// function. + pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>, + debug_loc: DebugLoc, + args: CallArgs<'a, 'tcx>, + dest: Option) + -> Result<'blk, 'tcx> { + trans_call_inner(bcx, debug_loc, self, args, dest) + } + + /// Turn the callee into a function pointer. + pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) + -> Datum<'tcx, Rvalue> { + match self.data { + Fn(llfn) => { + let fn_ptr_ty = match self.ty.sty { + ty::TyFnDef(_, _, f) => ccx.tcx().mk_ty(ty::TyFnPtr(f)), + _ => self.ty + }; + immediate_rvalue(llfn, fn_ptr_ty) } + Virtual(idx) => meth::trans_object_shim(ccx, self.ty, idx), + NamedTupleConstructor(_) => match self.ty.sty { + ty::TyFnDef(def_id, substs, _) => { + return trans_fn_ref_with_substs(ccx, def_id, Some(self.ty), substs); + } + _ => unreachable!("expected fn item type, found {}", self.ty) + }, + Intrinsic(..) => unreachable!("intrinsic {} getting reified", self.ty) } } } @@ -241,7 +209,17 @@ pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id, node, substs); - trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs) + let ref_ty = match node { + ExprId(0) => return trans_fn_ref_with_substs(ccx, def_id, None, substs), + ExprId(id) => ccx.tcx().node_id_to_type(id), + MethodCallKey(method_call) => { + ccx.tcx().tables.borrow().method_map[&method_call].ty + } + }; + let ref_ty = monomorphize::apply_param_substs(ccx.tcx(), + param_substs, + &ref_ty); + trans_fn_ref_with_substs(ccx, def_id, Some(ref_ty), substs) } /// Translates an adapter that implements the `Fn` trait for a fn @@ -290,33 +268,33 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`, // which is the fn pointer, and `args`, which is the arguments tuple. - let (opt_def_id, sig) = - match bare_fn_ty.sty { - ty::TyBareFn(opt_def_id, - &ty::BareFnTy { unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - ref sig }) => { - (opt_def_id, sig) - } + let sig = match bare_fn_ty.sty { + ty::TyFnDef(_, _, + &ty::BareFnTy { unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + ref sig }) | + ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal, + abi: Abi::Rust, + ref sig }) => sig, - _ => { - tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}", - bare_fn_ty)); - } - }; + _ => { + tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}", + bare_fn_ty)); + } + }; let sig = tcx.erase_late_bound_regions(sig); let sig = infer::normalize_associated_type(ccx.tcx(), &sig); let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec()); - let tuple_fn_ty = tcx.mk_fn(opt_def_id, - tcx.mk_bare_fn(ty::BareFnTy { - unsafety: hir::Unsafety::Normal, - abi: Abi::RustCall, - sig: ty::Binder(ty::FnSig { - inputs: vec![bare_fn_ty_maybe_ref, - tuple_input_ty], - output: sig.output, - variadic: false - })})); + let tuple_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { + unsafety: hir::Unsafety::Normal, + abi: Abi::RustCall, + sig: ty::Binder(ty::FnSig { + inputs: vec![bare_fn_ty_maybe_ref, + tuple_input_ty], + output: sig.output, + variadic: false + }) + }); debug!("tuple_fn_ty: {:?}", tuple_fn_ty); // @@ -341,11 +319,18 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( let llargs = get_params(fcx.llfn); let self_idx = fcx.arg_offset(); - // the first argument (`self`) will be ptr to the fn pointer - let llfnpointer = if is_by_ref { - Load(bcx, llargs[self_idx]) - } else { - llargs[self_idx] + let llfnpointer = match bare_fn_ty.sty { + ty::TyFnDef(def_id, substs, _) => { + // Function definitions have to be turned into a pointer. + Callee::def(ccx, def_id, substs, bare_fn_ty).reify(ccx).val + } + + // the first argument (`self`) will be ptr to the fn pointer + _ => if is_by_ref { + Load(bcx, llargs[self_idx]) + } else { + llargs[self_idx] + } }; assert!(!fcx.needs_ret_allocas); @@ -354,13 +339,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")) ); - bcx = trans_call_inner(bcx, DebugLoc::None, |bcx, _| { - Callee { - bcx: bcx, - data: Fn(llfnpointer), - ty: bare_fn_ty - } - }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx; + let callee = Callee { + data: Fn(llfnpointer), + ty: bare_fn_ty + }; + bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx; finish_fn(&fcx, bcx, sig.output, DebugLoc::None); @@ -379,30 +362,25 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( /// - `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 +/// - `ref_ty`: monotype of the reference to the fn/method, if applicable. +/// This parameter may be None; but, if so, the resulting value may not +/// have the right type, so it must be cast before being used. /// - `substs`: values for each of the fn/method's parameters pub fn trans_fn_ref_with_substs<'a, 'tcx>( ccx: &CrateContext<'a, 'tcx>, def_id: DefId, - node: ExprOrMethodCall, - param_substs: &'tcx subst::Substs<'tcx>, - substs: subst::Substs<'tcx>) + ref_ty: Option>, + substs: &'tcx subst::Substs<'tcx>) -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_fn_ref_with_substs"); let tcx = ccx.tcx(); - debug!("trans_fn_ref_with_substs(def_id={:?}, node={:?}, \ - param_substs={:?}, substs={:?})", - def_id, - node, - param_substs, - substs); + debug!("trans_fn_ref_with_substs(def_id={:?}, ref_ty={:?}, substs={:?})", + def_id, ref_ty, substs); assert!(!substs.types.needs_infer()); assert!(!substs.types.has_escaping_regions()); - let substs = substs.erase_regions(); // Check whether this fn has an inlined copy and, if so, redirect // def_id to the local id of the inlined copy. @@ -437,48 +415,45 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( // Should be either intra-crate or inlined. assert_eq!(def_id.krate, LOCAL_CRATE); - let opt_ref_id = match node { - ExprId(id) => if id != 0 { Some(id) } else { None }, - MethodCallKey(_) => None, + let substs = tcx.mk_substs(substs.clone().erase_regions()); + let (mut val, fn_ty, must_cast) = + monomorphize::monomorphic_fn(ccx, def_id, substs); + let fn_ty = ref_ty.unwrap_or(fn_ty); + let fn_ptr_ty = match fn_ty.sty { + ty::TyFnDef(_, _, fty) => { + // Create a fn pointer with the substituted signature. + tcx.mk_ty(ty::TyFnPtr(fty)) + } + _ => unreachable!("expected fn item type, found {}", fn_ty) }; - - let substs = tcx.mk_substs(substs); - let (val, fn_ty, must_cast) = - monomorphize::monomorphic_fn(ccx, def_id, substs, opt_ref_id); - 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) => tcx.node_id_to_type(id), - MethodCallKey(method_call) => { - tcx.tables.borrow().method_map[&method_call].ty - } - }; - 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 must_cast && ref_ty.is_some() { + let llptrty = type_of::type_of(ccx, fn_ptr_ty); if llptrty != common::val_ty(val) { - let val = consts::ptrcast(val, llptrty); - return Datum::new(val, ref_ty, Rvalue::new(ByValue)); + val = consts::ptrcast(val, llptrty); } } - return Datum::new(val, fn_ty, Rvalue::new(ByValue)); + return immediate_rvalue(val, fn_ptr_ty); } - // Type scheme of the function item (may have type params) - let fn_type_scheme = tcx.lookup_item_type(def_id); - let fn_type = infer::normalize_associated_type(tcx, &fn_type_scheme.ty); - // Find the actual function pointer. - let mut val = { - if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) { - // Internal reference. - get_item_val(ccx, node_id) - } else { - // External reference. - trans_external_path(ccx, def_id, fn_type) - } + let local_node = ccx.tcx().map.as_local_node_id(def_id); + let mut datum = if let Some(node_id) = local_node { + // Type scheme of the function item (may have type params) + let fn_type_scheme = tcx.lookup_item_type(def_id); + let fn_type = match fn_type_scheme.ty.sty { + ty::TyFnDef(_, _, fty) => { + // Create a fn pointer with the normalized signature. + tcx.mk_fn_ptr(infer::normalize_associated_type(tcx, fty)) + } + _ => unreachable!("expected fn item type, found {}", + fn_type_scheme.ty) + }; + + // Internal reference. + immediate_rvalue(get_item_val(ccx, node_id), fn_type) + } else { + // External reference. + get_extern_fn(ccx, def_id) }; // This is subtle and surprising, but sometimes we have to bitcast @@ -504,93 +479,36 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( // This can occur on either a crate-local or crate-external // reference. It also occurs when testing libcore and in some // other weird situations. Annoying. - let llty = type_of::type_of_fn_from_ty(ccx, fn_type); - let llptrty = llty.ptr_to(); - if common::val_ty(val) != llptrty { + let llptrty = type_of::type_of(ccx, datum.ty); + if common::val_ty(datum.val) != llptrty { debug!("trans_fn_ref_with_substs(): casting pointer!"); - val = consts::ptrcast(val, llptrty); + datum.val = consts::ptrcast(datum.val, llptrty); } else { debug!("trans_fn_ref_with_substs(): not casting pointer!"); } - Datum::new(val, fn_type, Rvalue::new(ByValue)) + datum } // ______________________________________________________________________ // Translating calls -pub fn trans_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - call_expr: &hir::Expr, - f: &hir::Expr, - args: CallArgs<'a, 'tcx>, - dest: expr::Dest) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_call"); - trans_call_inner(bcx, - call_expr.debug_loc(), - |bcx, _| trans(bcx, f), - args, - Some(dest)).bcx -} - -pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - call_expr: &hir::Expr, - rcvr: &hir::Expr, - args: CallArgs<'a, 'tcx>, - dest: expr::Dest) - -> Block<'blk, 'tcx> { - let _icx = push_ctxt("trans_method_call"); - debug!("trans_method_call(call_expr={:?})", call_expr); - let method_call = MethodCall::expr(call_expr.id); - trans_call_inner( - bcx, - call_expr.debug_loc(), - |cx, arg_cleanup_scope| { - meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope) - }, - args, - Some(dest)).bcx -} - pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, did: DefId, args: &[ValueRef], dest: Option, debug_loc: DebugLoc) -> Result<'blk, 'tcx> { - callee::trans_call_inner(bcx, debug_loc, |bcx, _| { - let datum = trans_fn_ref_with_substs(bcx.ccx(), - did, - ExprId(0), - bcx.fcx.param_substs, - subst::Substs::trans_empty()); - Callee { - bcx: bcx, - data: Fn(datum.val), - ty: datum.ty - } - }, ArgVals(args), dest) + let datum = trans_fn_ref(bcx.ccx(), did, ExprId(0), bcx.fcx.param_substs); + Callee::ptr(datum).call(bcx, debug_loc, ArgVals(args), dest) } -/// This behemoth of a function translates function calls. Unfortunately, in -/// order to generate more efficient LLVM output at -O0, it has quite a complex -/// signature (refactoring this into two functions seems like a good idea). -/// -/// In particular, for lang items, it is invoked with a dest of None, and in -/// that case the return value contains the result of the fn. The lang item must -/// not return a structural type or else all heck breaks loose. -/// -/// For non-lang items, `dest` is always Some, and hence the result is written -/// into memory somewhere. Nonetheless we return the actual return value of the -/// function. -pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, - debug_loc: DebugLoc, - get_callee: F, - args: CallArgs<'a, 'tcx>, - dest: Option) - -> Result<'blk, 'tcx> where - F: FnOnce(Block<'blk, 'tcx>, cleanup::ScopeId) -> Callee<'blk, 'tcx>, -{ +fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, + debug_loc: DebugLoc, + callee: Callee<'tcx>, + args: CallArgs<'a, 'tcx>, + dest: Option) + -> Result<'blk, 'tcx> { // Introduce a temporary cleanup scope that will contain cleanups // for the arguments while they are being evaluated. The purpose // this cleanup is to ensure that, should a panic occur while @@ -600,27 +518,17 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, // scope will ever execute. let fcx = bcx.fcx; let ccx = fcx.ccx; - let arg_cleanup_scope = fcx.push_custom_cleanup_scope(); - - let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope)); - let mut bcx = callee.bcx; let (abi, ret_ty) = match callee.ty.sty { - ty::TyBareFn(_, ref f) => { + ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { let sig = bcx.tcx().erase_late_bound_regions(&f.sig); let sig = infer::normalize_associated_type(bcx.tcx(), &sig); (f.abi, sig.output) } - _ => panic!("expected bare rust fn or closure in trans_call_inner") + _ => panic!("expected fn item or ptr in Callee::call") }; - let (llfn, llself) = match callee.data { - Fn(llfn) => { - (llfn, None) - } - TraitItem(d) => { - (d.llfn, Some(d.llself)) - } + match callee.data { Intrinsic(node, substs) => { assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic); assert!(dest.is_some()); @@ -632,14 +540,15 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } }; + let arg_cleanup_scope = fcx.push_custom_cleanup_scope(); return intrinsic::trans_intrinsic_call(bcx, node, callee.ty, arg_cleanup_scope, args, - dest.unwrap(), substs, + dest.unwrap(), + substs, call_info); } NamedTupleConstructor(disr) => { assert!(dest.is_some()); - fcx.pop_custom_cleanup_scope(arg_cleanup_scope); return base::trans_named_tuple_constructor(bcx, callee.ty, @@ -648,7 +557,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, dest.unwrap(), debug_loc); } - }; + _ => {} + } // Intrinsics should not become actual functions. // We trans them in place in `trans_intrinsic_call` @@ -688,6 +598,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, llvm::LLVMGetUndef(Type::nil(ccx).ptr_to().to_ref()) }; + let arg_cleanup_scope = fcx.push_custom_cleanup_scope(); + // The code below invokes the function, using either the Rust // conventions (if it is a rust fn) or the native conventions // (otherwise). The important part is that, when all is said @@ -711,10 +623,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } } - // Push a trait object's self. - if let Some(llself) = llself { - llargs.push(llself); - } + let arg_start = llargs.len(); // Push the arguments. bcx = trans_args(bcx, @@ -722,16 +631,25 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, callee.ty, &mut llargs, cleanup::CustomScope(arg_cleanup_scope), - llself.is_some(), abi); fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); + let datum = match callee.data { + Fn(f) => immediate_rvalue(f, callee.ty), + Virtual(idx) => { + // The data and vtable pointers were split by trans_arg_datum. + let vtable = llargs.remove(arg_start + 1); + meth::get_virtual_method(bcx, vtable, idx, callee.ty) + } + _ => unreachable!() + }; + // Invoke the actual rust fn and update bcx/llresult. let (llret, b) = base::invoke(bcx, - llfn, + datum.val, &llargs[..], - callee.ty, + datum.ty, debug_loc); bcx = b; llresult = llret; @@ -754,16 +672,17 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, assert!(dest.is_some()); let mut llargs = Vec::new(); - let arg_tys = match args { - ArgExprs(a) => a.iter().map(|x| common::expr_ty_adjusted(bcx, &x)).collect(), - _ => panic!("expected arg exprs.") + let (llfn, arg_tys) = match (callee.data, &args) { + (Fn(f), &ArgExprs(a)) => { + (f, a.iter().map(|x| common::expr_ty_adjusted(bcx, &x)).collect()) + } + _ => panic!("expected fn ptr and arg exprs.") }; bcx = trans_args(bcx, args, callee.ty, &mut llargs, cleanup::CustomScope(arg_cleanup_scope), - false, abi); fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); @@ -800,23 +719,22 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } pub enum CallArgs<'a, 'tcx> { - // Supply value of arguments as a list of expressions that must be - // translated. This is used in the common case of `foo(bar, qux)`. + /// Supply value of arguments as a list of expressions that must be + /// translated. This is used in the common case of `foo(bar, qux)`. ArgExprs(&'a [P]), - // Supply value of arguments as a list of LLVM value refs; frequently - // used with lang items and so forth, when the argument is an internal - // value. + /// Supply value of arguments as a list of LLVM value refs; frequently + /// used with lang items and so forth, when the argument is an internal + /// value. ArgVals(&'a [ValueRef]), - // For overloaded operators: `(lhs, Option(rhs, rhs_id), autoref)`. `lhs` - // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of - // the right-hand-side argument (if any). `autoref` indicates whether the `rhs` - // arguments should be auto-referenced - ArgOverloadedOp(Datum<'tcx, Expr>, Option<(Datum<'tcx, Expr>, ast::NodeId)>, bool), + /// For overloaded operators: `(lhs, Option(rhs))`. + /// `lhs` is the left-hand-side and `rhs` is the datum + /// of the right-hand-side argument (if any). + ArgOverloadedOp(Datum<'tcx, Expr>, Option>), - // Supply value of arguments as a list of expressions that must be - // translated, for overloaded call operators. + /// Supply value of arguments as a list of expressions that must be + /// translated, for overloaded call operators. ArgOverloadedCall(Vec<&'a hir::Expr>), } @@ -825,8 +743,7 @@ fn trans_args_under_call_abi<'blk, 'tcx>( arg_exprs: &[P], fn_ty: Ty<'tcx>, llargs: &mut Vec, - arg_cleanup_scope: cleanup::ScopeId, - ignore_self: bool) + arg_cleanup_scope: cleanup::ScopeId) -> Block<'blk, 'tcx> { let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig()); @@ -834,15 +751,12 @@ fn trans_args_under_call_abi<'blk, 'tcx>( let args = sig.inputs; // Translate the `self` argument first. - if !ignore_self { - let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0])); - bcx = trans_arg_datum(bcx, - args[0], - arg_datum, - arg_cleanup_scope, - DontAutorefArg, - llargs); - } + let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0])); + bcx = trans_arg_datum(bcx, + args[0], + arg_datum, + arg_cleanup_scope, + llargs); // Now untuple the rest of the arguments. let tuple_expr = &arg_exprs[1]; @@ -870,7 +784,6 @@ fn trans_args_under_call_abi<'blk, 'tcx>( field_type, arg_datum, arg_cleanup_scope, - DontAutorefArg, llargs); } } @@ -888,23 +801,19 @@ fn trans_overloaded_call_args<'blk, 'tcx>( arg_exprs: Vec<&hir::Expr>, fn_ty: Ty<'tcx>, llargs: &mut Vec, - arg_cleanup_scope: cleanup::ScopeId, - ignore_self: bool) + arg_cleanup_scope: cleanup::ScopeId) -> Block<'blk, 'tcx> { // Translate the `self` argument first. let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig()); let sig = infer::normalize_associated_type(bcx.tcx(), &sig); let arg_tys = sig.inputs; - if !ignore_self { - let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0])); - bcx = trans_arg_datum(bcx, - arg_tys[0], - arg_datum, - arg_cleanup_scope, - DontAutorefArg, - llargs); - } + let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0])); + bcx = trans_arg_datum(bcx, + arg_tys[0], + arg_datum, + arg_cleanup_scope, + llargs); // Now untuple the rest of the arguments. let tuple_type = arg_tys[1]; @@ -917,7 +826,6 @@ fn trans_overloaded_call_args<'blk, 'tcx>( field_type, arg_datum, arg_cleanup_scope, - DontAutorefArg, llargs); } } @@ -935,7 +843,6 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, fn_ty: Ty<'tcx>, llargs: &mut Vec, arg_cleanup_scope: cleanup::ScopeId, - ignore_self: bool, abi: Abi) -> Block<'blk, 'tcx> { debug!("trans_args(abi={})", abi); @@ -960,15 +867,11 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, arg_exprs, fn_ty, llargs, - arg_cleanup_scope, - ignore_self) + arg_cleanup_scope) } let num_formal_args = arg_tys.len(); for (i, arg_expr) in arg_exprs.iter().enumerate() { - if i == 0 && ignore_self { - continue; - } let arg_ty = if i >= num_formal_args { assert!(variadic); common::expr_ty_adjusted(cx, &arg_expr) @@ -979,7 +882,6 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_expr)); bcx = trans_arg_datum(bcx, arg_ty, arg_datum, arg_cleanup_scope, - DontAutorefArg, llargs); } } @@ -988,22 +890,19 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, arg_exprs, fn_ty, llargs, - arg_cleanup_scope, - ignore_self) + arg_cleanup_scope) } - ArgOverloadedOp(lhs, rhs, autoref) => { + ArgOverloadedOp(lhs, rhs) => { assert!(!variadic); bcx = trans_arg_datum(bcx, arg_tys[0], lhs, arg_cleanup_scope, - DontAutorefArg, llargs); - if let Some((rhs, rhs_id)) = rhs { + if let Some(rhs) = rhs { assert_eq!(arg_tys.len(), 2); bcx = trans_arg_datum(bcx, arg_tys[1], rhs, arg_cleanup_scope, - if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg }, llargs); } else { assert_eq!(arg_tys.len(), 1); @@ -1017,17 +916,10 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, bcx } -#[derive(Copy, Clone)] -pub enum AutorefArg { - DontAutorefArg, - DoAutorefArg(ast::NodeId) -} - pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, formal_arg_ty: Ty<'tcx>, arg_datum: Datum<'tcx, Expr>, arg_cleanup_scope: cleanup::ScopeId, - autoref_arg: AutorefArg, llargs: &mut Vec) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_arg_datum"); @@ -1041,37 +933,25 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!(" arg datum: {}", arg_datum.to_string(bcx.ccx())); - let mut val; - // FIXME(#3548) use the adjustments table - match autoref_arg { - DoAutorefArg(arg_id) => { - // We will pass argument by reference - // We want an lvalue, so that we can pass by reference and - let arg_datum = unpack_datum!( - bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id)); - val = arg_datum.val; - } - DontAutorefArg if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) && - !bcx.fcx.type_needs_drop(arg_datum_ty) => { - val = arg_datum.val - } - DontAutorefArg => { - // Make this an rvalue, since we are going to be - // passing ownership. - let arg_datum = unpack_datum!( - bcx, arg_datum.to_rvalue_datum(bcx, "arg")); - - // Now that arg_datum is owned, get it into the appropriate - // mode (ref vs value). - let arg_datum = unpack_datum!( - bcx, arg_datum.to_appropriate_datum(bcx)); - - // Technically, ownership of val passes to the callee. - // However, we must cleanup should we panic before the - // callee is actually invoked. - val = arg_datum.add_clean(bcx.fcx, arg_cleanup_scope); - } - } + let mut val = if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) && + !bcx.fcx.type_needs_drop(arg_datum_ty) { + arg_datum.val + } else { + // Make this an rvalue, since we are going to be + // passing ownership. + let arg_datum = unpack_datum!( + bcx, arg_datum.to_rvalue_datum(bcx, "arg")); + + // Now that arg_datum is owned, get it into the appropriate + // mode (ref vs value). + let arg_datum = unpack_datum!( + bcx, arg_datum.to_appropriate_datum(bcx)); + + // Technically, ownership of val passes to the callee. + // However, we must cleanup should we panic before the + // callee is actually invoked. + arg_datum.add_clean(bcx.fcx, arg_cleanup_scope) + }; if type_of::arg_is_indirect(ccx, formal_arg_ty) && formal_arg_ty != arg_datum_ty { // this could happen due to e.g. subtyping diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 0d9248a22b4a4..95ca250e84445 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -17,7 +17,7 @@ use trans::adt; use trans::attributes; use trans::base::*; use trans::build::*; -use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData}; +use trans::callee::{self, ArgVals, Callee}; use trans::cleanup::{CleanupMethods, CustomScope, ScopeId}; use trans::common::*; use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue}; @@ -271,24 +271,8 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, // If the closure is a Fn closure, but a FnOnce is needed (etc), // then adapt the self type - let closure_kind = ccx.tcx().closure_kind(closure_def_id); - trans_closure_adapter_shim(ccx, - closure_def_id, - substs, - closure_kind, - trait_closure_kind, - llfn) -} + let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id); -fn trans_closure_adapter_shim<'a, 'tcx>( - ccx: &'a CrateContext<'a, 'tcx>, - closure_def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - llfn_closure_kind: ty::ClosureKind, - trait_closure_kind: ty::ClosureKind, - llfn: ValueRef) - -> ValueRef -{ let _icx = push_ctxt("trans_closure_adapter_shim"); let tcx = ccx.tcx(); @@ -355,28 +339,31 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Make a version with the type of by-ref closure. let ty::ClosureTy { unsafety, abi, mut sig } = infcx.closure_type(closure_def_id, &substs); sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet - let llref_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, - abi: abi, - sig: sig.clone() }); - let llref_fn_ty = tcx.mk_fn(None, llref_bare_fn_ty); + let llref_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { + unsafety: unsafety, + abi: abi, + sig: sig.clone() + }); debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}", llref_fn_ty); + let ret_ty = tcx.erase_late_bound_regions(&sig.output()); + let ret_ty = infer::normalize_associated_type(ccx.tcx(), &ret_ty); + // Make a version of the closure type with the same arguments, but // with argument #0 being by value. assert_eq!(abi, RustCall); sig.0.inputs[0] = closure_ty; - let llonce_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety, - abi: abi, - sig: sig }); - let llonce_fn_ty = tcx.mk_fn(None, llonce_bare_fn_ty); + let llonce_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { + unsafety: unsafety, + abi: abi, + sig: sig + }); // Create the by-value helper. let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim"); let lloncefn = declare::define_internal_rust_fn(ccx, &function_name, llonce_fn_ty); - let sig = tcx.erase_late_bound_regions(&llonce_bare_fn_ty.sig); - let sig = infer::normalize_associated_type(ccx.tcx(), &sig); let (block_arena, fcx): (TypedArena<_>, FunctionContext); block_arena = TypedArena::new(); @@ -384,13 +371,13 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( lloncefn, ast::DUMMY_NODE_ID, false, - sig.output, + ret_ty, substs.func_substs, None, &block_arena); - let mut bcx = init_function(&fcx, false, sig.output); + let mut bcx = init_function(&fcx, false, ret_ty); - let llargs = get_params(fcx.llfn); + let mut llargs = get_params(fcx.llfn); // the first argument (`self`) will be the (by value) closure env. let self_scope = fcx.push_custom_cleanup_scope(); @@ -405,25 +392,21 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( debug!("trans_fn_once_adapter_shim: env_datum={}", bcx.val_to_string(env_datum.val)); + llargs[self_idx] = env_datum.val; let dest = fcx.llretslotptr.get().map( - |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))); - - let callee_data = TraitItem(MethodData { llfn: llreffn, - llself: env_datum.val }); + |_| expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot"))); - bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| { - Callee { - bcx: bcx, - data: callee_data, - ty: llref_fn_ty - } - }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx; + let callee = Callee { + data: callee::Fn(llreffn), + ty: llref_fn_ty + }; + bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx; fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope); - finish_fn(&fcx, bcx, sig.output, DebugLoc::None); + finish_fn(&fcx, bcx, ret_ty, DebugLoc::None); lloncefn } diff --git a/src/librustc_trans/trans/collector.rs b/src/librustc_trans/trans/collector.rs index b5b0f0a82d4ec..abfd127f38860 100644 --- a/src/librustc_trans/trans/collector.rs +++ b/src/librustc_trans/trans/collector.rs @@ -542,14 +542,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { debug!("visiting operand {:?}", *operand); let callee = match *operand { - mir::Operand::Constant(mir::Constant { - literal: mir::Literal::Item { - def_id, - kind, - substs - }, - .. - }) if is_function_or_method(kind) => Some((def_id, substs)), + mir::Operand::Constant(mir::Constant { ty: &ty::TyS { + sty: ty::TyFnDef(def_id, substs, _), .. + }, .. }) => Some((def_id, substs)), _ => None }; @@ -588,25 +583,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.super_operand(operand); - fn is_function_or_method(item_kind: mir::ItemKind) -> bool { - match item_kind { - mir::ItemKind::Constant => false, - mir::ItemKind::Function | - mir::ItemKind::Method => true - } - } - fn can_result_in_trans_item<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) -> bool { if !match ccx.tcx().lookup_item_type(def_id).ty.sty { - ty::TyBareFn(Some(def_id), _) => { - // Some constructors also have type TyBareFn but they are + ty::TyFnDef(def_id, _, _) => { + // Some constructors also have type TyFnDef but they are // always instantiated inline and don't result in - // translation item. + // translation item. Same for FFI functions. match ccx.tcx().map.get_if_local(def_id) { Some(hir_map::NodeVariant(_)) | - Some(hir_map::NodeStructCtor(_)) => false, + Some(hir_map::NodeStructCtor(_)) | + Some(hir_map::NodeForeignItem(_)) => false, Some(_) => true, None => { ccx.sess().cstore.variant_kind(def_id).is_none() @@ -689,7 +677,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, if can_have_local_instance(ccx, destructor_did) { let trans_item = create_fn_trans_item(ccx, destructor_did, - ccx.tcx().mk_substs(substs), + substs, &Substs::trans_empty()); output.push(trans_item); } @@ -697,17 +685,18 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Finally add the types of nested values match ty.sty { - ty::TyBool | - ty::TyChar | - ty::TyInt(_) | - ty::TyUint(_) | - ty::TyStr | - ty::TyFloat(_) | - ty::TyRawPtr(_) | - ty::TyRef(..) | - ty::TyBareFn(..) | - ty::TySlice(_) | - ty::TyTrait(_) => { + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyStr | + ty::TyFloat(_) | + ty::TyRawPtr(_) | + ty::TyRef(..) | + ty::TyFnDef(..) | + ty::TyFnPtr(_) | + ty::TySlice(_) | + ty::TyTrait(_) => { /* nothing to do */ } ty::TyStruct(ref adt_def, substs) | @@ -831,9 +820,9 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, { let callee_substs = impl_substs.with_method_from(&rcvr_substs); let impl_method = tcx.get_impl_method(impl_did, - callee_substs, + tcx.mk_substs(callee_substs), trait_method.name); - Some((impl_method.method.def_id, tcx.mk_substs(impl_method.substs))) + Some((impl_method.method.def_id, impl_method.substs)) } // If we have a closure or a function pointer, we will also encounter // the concrete closure/function somewhere else (during closure or fn @@ -991,10 +980,9 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // create translation items .filter_map(|impl_method| { if can_have_local_instance(ccx, impl_method.method.def_id) { - let substs = ccx.tcx().mk_substs(impl_method.substs); Some(create_fn_trans_item(ccx, impl_method.method.def_id, - substs, + impl_method.substs, &Substs::trans_empty())) } else { None @@ -1173,12 +1161,12 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // The substitutions we have are on the impl, so we grab // the method type from the impl to substitute into. let mth = tcx.get_impl_method(impl_def_id, - callee_substs.clone(), + callee_substs, default_impl.name); assert!(mth.is_provided); - let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs); + let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs); if !normalize_and_test_predicates(ccx, predicates.into_vec()) { continue; } @@ -1289,7 +1277,8 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, &trait_data.bounds.projection_bounds, output); }, - ty::TyBareFn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => { + ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) | + ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { if unsafety == hir::Unsafety::Unsafe { output.push_str("unsafe "); } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 3ba27a4b78756..34ef4f4acec5e 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -1228,7 +1228,7 @@ pub enum ExprOrMethodCall { pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, node: ExprOrMethodCall, param_substs: &subst::Substs<'tcx>) - -> subst::Substs<'tcx> { + -> &'tcx subst::Substs<'tcx> { let tcx = ccx.tcx(); let substs = match node { @@ -1245,9 +1245,9 @@ pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, node, substs)); } - monomorphize::apply_param_substs(tcx, - param_substs, - &substs.erase_regions()) + ccx.tcx().mk_substs(monomorphize::apply_param_substs(tcx, + param_substs, + &substs.erase_regions())) } pub fn langcall(bcx: Block, @@ -1277,7 +1277,7 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, debug!("inlined_variant_def: ctor_ty={:?} inlined_vid={:?}", ctor_ty, inlined_vid); let adt_def = match ctor_ty.sty { - ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { + ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig { output: ty::FnConverging(ty), .. }), ..}) => ty, _ => ctor_ty diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 20da15834966e..6c47cab64effe 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -28,6 +28,7 @@ use middle::def::Def; use middle::def_id::DefId; use trans::{adt, closure, debuginfo, expr, inline, machine}; use trans::base::{self, push_ctxt}; +use trans::callee::Callee; use trans::collector::{self, TransItem}; use trans::common::{self, type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt}; use trans::common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty}; @@ -211,7 +212,7 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let arg_ids = args.iter().map(|arg| arg.pat.id); let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect(); - let substs = ccx.tcx().mk_substs(node_id_substs(ccx, node, param_substs)); + let substs = node_id_substs(ccx, node, param_substs); match fn_like.body().expr { Some(ref expr) => { const_expr(ccx, &expr, substs, Some(&fn_args), trueconst).map(|(res, _)| res) @@ -355,8 +356,16 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned(); match opt_adj { Some(AdjustReifyFnPointer) => { - // FIXME(#19925) once fn item types are - // zero-sized, we'll need to do something here + match ety.sty { + ty::TyFnDef(def_id, substs, _) => { + let datum = Callee::def(cx, def_id, substs, ety).reify(cx); + llconst = datum.val; + ety_adjusted = datum.ty; + } + _ => { + unreachable!("{} cannot be reified to a fn ptr", ety) + } + } } Some(AdjustUnsafeFnPointer) | Some(AdjustMutToConstPointer) => { // purely a type-level thing @@ -413,8 +422,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, .expect("consts: unsizing got non-pointer target type").ty; let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to(); let base = ptrcast(base, ptr_ty); - let info = base::unsized_info(cx, pointee_ty, unsized_ty, - old_info, param_substs); + let info = base::unsized_info(cx, pointee_ty, unsized_ty, old_info); if old_info.is_none() { let prev_const = cx.const_unsized().borrow_mut() @@ -894,9 +902,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, cx.sess().span_bug(e.span, "const fn argument not found") } } - Def::Fn(..) | Def::Method(..) => { - expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val - } + Def::Fn(..) | Def::Method(..) => C_nil(cx), Def::Const(def_id) | Def::AssociatedConst(def_id) => { load_const(cx, try!(get_const_val(cx, def_id, e, param_substs)), ety) @@ -908,23 +914,14 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let repr = adt::represent_type(cx, ety); adt::trans_const(cx, &repr, Disr::from(vinfo.disr_val), &[]) } - ty::VariantKind::Tuple => { - expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val - } + ty::VariantKind::Tuple => C_nil(cx), ty::VariantKind::Struct => { cx.sess().span_bug(e.span, "path-expr refers to a dict variant!") } } } - Def::Struct(..) => { - if let ty::TyBareFn(..) = ety.sty { - // Tuple struct. - expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val - } else { - // Unit struct. - C_null(type_of::type_of(cx, ety)) - } - } + // Unit struct or ctor. + Def::Struct(..) => C_null(type_of::type_of(cx, ety)), _ => { cx.sess().span_bug(e.span, "expected a const, fn, struct, \ or variant def") diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index 330d4077c4101..0cd1f4e7fbf3e 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -253,7 +253,8 @@ impl<'tcx> TypeMap<'tcx> { principal.substs, &mut unique_type_id); }, - ty::TyBareFn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => { + ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) | + ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { if unsafety == hir::Unsafety::Unsafe { unique_type_id.push_str("unsafe "); } @@ -765,7 +766,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } } - ty::TyBareFn(_, ref barefnty) => { + ty::TyFnDef(_, _, ref barefnty) | ty::TyFnPtr(ref barefnty) => { let fn_metadata = subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs index 11dd631bee1fa..15275a46e9b77 100644 --- a/src/librustc_trans/trans/debuginfo/mod.rs +++ b/src/librustc_trans/trans/debuginfo/mod.rs @@ -430,7 +430,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let fn_type = monomorphize::apply_param_substs(cx.tcx(), param_substs, &fn_type); let (sig, abi) = match fn_type.sty { - ty::TyBareFn(_, ref barefnty) => { + ty::TyFnDef(_, _, ref barefnty) | ty::TyFnPtr(ref barefnty) => { let sig = cx.tcx().erase_late_bound_regions(&barefnty.sig); let sig = infer::normalize_associated_type(cx.tcx(), &sig); (sig, barefnty.abi) diff --git a/src/librustc_trans/trans/debuginfo/type_names.rs b/src/librustc_trans/trans/debuginfo/type_names.rs index f243b1e3bfaa4..cc9067677b25b 100644 --- a/src/librustc_trans/trans/debuginfo/type_names.rs +++ b/src/librustc_trans/trans/debuginfo/type_names.rs @@ -101,7 +101,8 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, push_item_name(cx, principal.def_id, false, output); push_type_params(cx, principal.substs, output); }, - ty::TyBareFn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => { + ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) | + ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { if unsafety == hir::Unsafety::Unsafe { output.push_str("unsafe "); } diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index 75b60be02f778..38e456c068829 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -106,7 +106,8 @@ pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, let function_type; // placeholder so that the memory ownership works out ok let (sig, abi, env) = match fn_type.sty { - ty::TyBareFn(_, ref f) => { + ty::TyFnDef(_, _, f) | + ty::TyFnPtr(f) => { (&f.sig, f.abi, None) } ty::TyClosure(closure_did, ref substs) => { diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index e3e53607829e6..ae03f58bce0cf 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -56,9 +56,10 @@ use llvm::{self, ValueRef, TypeKind}; use middle::const_qualif::ConstQualif; use middle::def::Def; use middle::subst::Substs; -use trans::{_match, adt, asm, base, callee, closure, consts, controlflow}; +use trans::{_match, adt, asm, base, closure, consts, controlflow}; use trans::base::*; use trans::build::*; +use trans::callee::{Callee, ArgExprs, ArgOverloadedCall, ArgOverloadedOp}; use trans::cleanup::{self, CleanupMethods, DropHintMethods}; use trans::common::*; use trans::datum::*; @@ -66,7 +67,6 @@ use trans::debuginfo::{self, DebugLoc, ToDebugLoc}; use trans::declare; use trans::glue; use trans::machine; -use trans::meth; use trans::tvec; use trans::type_of; use trans::Disr; @@ -85,7 +85,6 @@ use rustc_front::hir; use syntax::{ast, codemap}; use syntax::parse::token::InternedString; -use syntax::ptr::P; use std::mem; // Destinations @@ -349,11 +348,7 @@ fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } match adjustment { - AdjustReifyFnPointer => { - // FIXME(#19925) once fn item types are - // zero-sized, we'll need to return true here - false - } + AdjustReifyFnPointer => true, AdjustUnsafeFnPointer | AdjustMutToConstPointer => { // purely a type-level thing false @@ -388,8 +383,15 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, adjustment); match adjustment { AdjustReifyFnPointer => { - // FIXME(#19925) once fn item types are - // zero-sized, we'll need to do something here + match datum.ty.sty { + ty::TyFnDef(def_id, substs, _) => { + datum = Callee::def(bcx.ccx(), def_id, substs, datum.ty) + .reify(bcx.ccx()).to_expr_datum(); + } + _ => { + unreachable!("{} cannot be reified to a fn ptr", datum.ty) + } + } } AdjustUnsafeFnPointer | AdjustMutToConstPointer => { // purely a type-level thing @@ -492,8 +494,7 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, (val, None) }; - let info = unsized_info(bcx.ccx(), inner_source, inner_target, - old_info, bcx.fcx.param_substs); + let info = unsized_info(bcx.ccx(), inner_source, inner_target, old_info); // Compute the base pointer. This doesn't change the pointer value, // but merely its type. @@ -785,15 +786,10 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let index_expr_debug_loc = index_expr.debug_loc(); // Check for overloaded index. - let method_ty = ccx.tcx() - .tables - .borrow() - .method_map - .get(&method_call) - .map(|method| method.ty); - let elt_datum = match method_ty { - Some(method_ty) => { - let method_ty = monomorphize_type(bcx, method_ty); + let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned(); + let elt_datum = match method { + Some(method) => { + let method_ty = monomorphize_type(bcx, method.ty); let base_datum = unpack_datum!(bcx, trans(bcx, base)); @@ -811,19 +807,16 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Some(elt_tm) => elt_tm.ty, }; - // Overloaded. Evaluate `trans_overloaded_op`, which will - // invoke the user's index() method, which basically yields - // a `&T` pointer. We can then proceed down the normal - // path (below) to dereference that `&T`. + // Overloaded. Invoke the index() method, which basically + // yields a `&T` pointer. We can then proceed down the + // normal path (below) to dereference that `&T`. let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_index_elt"); - unpack_result!(bcx, - trans_overloaded_op(bcx, - index_expr, - method_call, - base_datum, - Some((ix_datum, idx.id)), - Some(SaveIn(scratch.val)), - false)); + + bcx = Callee::method(bcx, method) + .call(bcx, index_expr_debug_loc, + ArgOverloadedOp(base_datum, Some(ix_datum)), + Some(SaveIn(scratch.val))).bcx; + let datum = scratch.to_expr_datum(); let lval = Lvalue::new("expr::trans_index overload"); if type_is_sized(bcx.tcx(), elt_ty) { @@ -899,24 +892,18 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let _icx = push_ctxt("trans_def_lvalue"); match def { - Def::Fn(..) | Def::Method(..) | - Def::Struct(..) | Def::Variant(..) => { - let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def, - bcx.fcx.param_substs); - DatumBlock::new(bcx, datum.to_expr_datum()) - } Def::Static(did, _) => { let const_ty = expr_ty(bcx, ref_expr); let val = get_static_val(bcx.ccx(), did, const_ty); let lval = Lvalue::new("expr::trans_def"); DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr(lval))) } - Def::Const(_) | Def::AssociatedConst(_) => { - bcx.sess().span_bug(ref_expr.span, - "constant expression should not reach expr::trans_def") + Def::Local(..) | Def::Upvar(..) => { + DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum()) } _ => { - DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum()) + bcx.sess().span_bug(ref_expr.span, + &format!("{:?} should not reach expr::trans_def", def)) } } } @@ -1024,17 +1011,18 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } hir::ExprAssignOp(op, ref dst, ref src) => { - let has_method_map = bcx.tcx() - .tables - .borrow() - .method_map - .contains_key(&MethodCall::expr(expr.id)); + let method = bcx.tcx().tables + .borrow() + .method_map + .get(&MethodCall::expr(expr.id)).cloned(); - if has_method_map { + if let Some(method) = method { let dst = unpack_datum!(bcx, trans(bcx, &dst)); let src_datum = unpack_datum!(bcx, trans(bcx, &src)); - trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), dst, - Some((src_datum, src.id)), None, false).bcx + + Callee::method(bcx, method) + .call(bcx, expr.debug_loc(), + ArgOverloadedOp(dst, Some(src_datum)), None).bcx } else { trans_assign_op(bcx, expr, op, &dst, &src) } @@ -1061,6 +1049,9 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debuginfo::set_source_location(bcx.fcx, expr.id, expr.span); + // Entry into the method table if this is an overloaded call/op. + let method_call = MethodCall::expr(expr.id); + match expr.node { hir::ExprType(ref e, _) => { trans_into(bcx, &e, dest) @@ -1144,47 +1135,54 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, &expr.attrs).unwrap_or(bcx) } hir::ExprCall(ref f, ref args) => { - if bcx.tcx().is_method_call(expr.id) { - trans_overloaded_call(bcx, - expr, - &f, - &args[..], - Some(dest)) + let method = bcx.tcx().tables.borrow().method_map.get(&method_call).cloned(); + let (callee, args) = if let Some(method) = method { + let mut all_args = vec![&**f]; + all_args.extend(args.iter().map(|e| &**e)); + + (Callee::method(bcx, method), ArgOverloadedCall(all_args)) } else { - callee::trans_call(bcx, - expr, - &f, - callee::ArgExprs(&args[..]), - dest) - } + let f = unpack_datum!(bcx, trans(bcx, f)); + (match f.ty.sty { + ty::TyFnDef(def_id, substs, _) => { + Callee::def(bcx.ccx(), def_id, substs, f.ty) + } + ty::TyFnPtr(_) => { + let f = unpack_datum!(bcx, + f.to_rvalue_datum(bcx, "callee")); + Callee::ptr(f) + } + _ => { + bcx.tcx().sess.span_bug(expr.span, + &format!("type of callee is not a fn: {}", f.ty)); + } + }, ArgExprs(&args)) + }; + callee.call(bcx, expr.debug_loc(), args, Some(dest)).bcx } hir::ExprMethodCall(_, _, ref args) => { - callee::trans_method_call(bcx, - expr, - &args[0], - callee::ArgExprs(&args[..]), - dest) + Callee::method_call(bcx, method_call) + .call(bcx, expr.debug_loc(), ArgExprs(&args), Some(dest)).bcx } - hir::ExprBinary(op, ref lhs, ref rhs) => { + hir::ExprBinary(op, ref lhs, ref rhs_expr) => { // if not overloaded, would be RvalueDatumExpr let lhs = unpack_datum!(bcx, trans(bcx, &lhs)); - let rhs_datum = unpack_datum!(bcx, trans(bcx, &rhs)); - trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs, - Some((rhs_datum, rhs.id)), Some(dest), - !rustc_front::util::is_by_value_binop(op.node)).bcx + let mut rhs = unpack_datum!(bcx, trans(bcx, &rhs_expr)); + if !rustc_front::util::is_by_value_binop(op.node) { + rhs = unpack_datum!(bcx, auto_ref(bcx, rhs, rhs_expr)); + } + + Callee::method_call(bcx, method_call) + .call(bcx, expr.debug_loc(), + ArgOverloadedOp(lhs, Some(rhs)), Some(dest)).bcx } - hir::ExprUnary(op, ref subexpr) => { + hir::ExprUnary(_, ref subexpr) => { // if not overloaded, would be RvalueDatumExpr let arg = unpack_datum!(bcx, trans(bcx, &subexpr)); - trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), - arg, None, Some(dest), !rustc_front::util::is_by_value_unop(op)).bcx - } - hir::ExprIndex(ref base, ref idx) => { - // if not overloaded, would be RvalueDatumExpr - let base = unpack_datum!(bcx, trans(bcx, &base)); - let idx_datum = unpack_datum!(bcx, trans(bcx, &idx)); - trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base, - Some((idx_datum, idx.id)), Some(dest), true).bcx + + Callee::method_call(bcx, method_call) + .call(bcx, expr.debug_loc(), + ArgOverloadedOp(arg, None), Some(dest)).bcx } hir::ExprCast(..) => { // Trait casts used to come this way, now they should be coercions. @@ -1218,26 +1216,22 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Ignore => { return bcx; } }; + let ty = expr_ty(bcx, ref_expr); + if let ty::TyFnDef(..) = ty.sty { + // Zero-sized function or ctor. + return bcx; + } + match def { Def::Variant(tid, vid) => { let variant = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid); - if let ty::VariantKind::Tuple = variant.kind() { - // N-ary variant. - 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 { - // Nullary variant. - let ty = expr_ty(bcx, ref_expr); - let repr = adt::represent_type(bcx.ccx(), ty); - adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val)); - return bcx; - } + // Nullary variant. + let ty = expr_ty(bcx, ref_expr); + let repr = adt::represent_type(bcx.ccx(), ty); + adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val)); + bcx } Def::Struct(..) => { - let ty = expr_ty(bcx, ref_expr); match ty.sty { ty::TyStruct(def, _) if def.has_dtor() => { let repr = adt::represent_type(bcx.ccx(), ty); @@ -1255,41 +1249,6 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - ref_expr: &hir::Expr, - def: Def, - param_substs: &'tcx Substs<'tcx>) - -> Datum<'tcx, Rvalue> { - let _icx = push_ctxt("trans_def_datum_unadjusted"); - - match def { - Def::Fn(did) | - Def::Struct(did) | Def::Variant(_, did) => { - callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs) - } - Def::Method(method_did) => { - match ccx.tcx().impl_or_trait_item(method_did).container() { - ty::ImplContainer(_) => { - callee::trans_fn_ref(ccx, method_did, - ExprId(ref_expr.id), - param_substs) - } - ty::TraitContainer(trait_did) => { - meth::trans_static_method_callee(ccx, method_did, - trait_did, ref_expr.id, - param_substs) - } - } - } - _ => { - ccx.tcx().sess.span_bug(ref_expr.span, &format!( - "trans_def_fn_unadjusted invoked on: {:?} for {:?}", - def, - ref_expr)); - } - } -} - /// Translates a reference to a local variable or argument. This always results in an lvalue datum. pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, def: Def) @@ -1898,51 +1857,6 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - method_call: MethodCall, - lhs: Datum<'tcx, Expr>, - rhs: Option<(Datum<'tcx, Expr>, ast::NodeId)>, - dest: Option, - autoref: bool) - -> Result<'blk, 'tcx> { - callee::trans_call_inner(bcx, - expr.debug_loc(), - |bcx, arg_cleanup_scope| { - meth::trans_method_callee(bcx, - method_call, - None, - arg_cleanup_scope) - }, - callee::ArgOverloadedOp(lhs, rhs, autoref), - dest) -} - -fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - expr: &hir::Expr, - callee: &'a hir::Expr, - args: &'a [P], - dest: Option) - -> Block<'blk, 'tcx> { - debug!("trans_overloaded_call {}", expr.id); - let method_call = MethodCall::expr(expr.id); - let mut all_args = vec!(callee); - all_args.extend(args.iter().map(|e| &**e)); - unpack_result!(bcx, - callee::trans_call_inner(bcx, - expr.debug_loc(), - |bcx, arg_cleanup_scope| { - meth::trans_method_callee( - bcx, - method_call, - None, - arg_cleanup_scope) - }, - callee::ArgOverloadedCall(all_args), - dest)); - bcx -} - pub fn cast_is_noop<'tcx>(tcx: &TyCtxt<'tcx>, expr: &hir::Expr, t_in: Ty<'tcx>, @@ -2179,18 +2093,12 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let mut bcx = bcx; // Check for overloaded deref. - let method_ty = ccx.tcx() - .tables - .borrow() - .method_map - .get(&method_call).map(|method| method.ty); - - let datum = match method_ty { - Some(method_ty) => { - let method_ty = monomorphize_type(bcx, method_ty); - - // Overloaded. Evaluate `trans_overloaded_op`, which will - // invoke the user's deref() method, which basically + let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned(); + let datum = match method { + Some(method) => { + let method_ty = monomorphize_type(bcx, method.ty); + + // Overloaded. Invoke the deref() method, which basically // converts from the `Smaht` pointer that we have into // a `&T` pointer. We can then proceed down the normal // path (below) to dereference that `&T`. @@ -2205,9 +2113,10 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap(); let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref"); - unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call, - datum, None, Some(SaveIn(scratch.val)), - false)); + bcx = Callee::method(bcx, method) + .call(bcx, expr.debug_loc(), + ArgOverloadedOp(datum, None), + Some(SaveIn(scratch.val))).bcx; scratch.to_expr_datum() } None => { @@ -2524,18 +2433,13 @@ fn expr_kind(tcx: &TyCtxt, expr: &hir::Expr) -> ExprKind { match expr.node { hir::ExprPath(..) => { match tcx.resolve_expr(expr) { - Def::Struct(..) | Def::Variant(..) => { - if let ty::TyBareFn(..) = tcx.node_id_to_type(expr.id).sty { - // ctor function - ExprKind::RvalueDatum - } else { - ExprKind::RvalueDps - } + // Put functions and ctors with the ADTs, as they + // are zero-sized, so DPS is the cheapest option. + Def::Struct(..) | Def::Variant(..) | + Def::Fn(..) | Def::Method(..) => { + ExprKind::RvalueDps } - // Fn pointers are just scalar values. - Def::Fn(..) | Def::Method(..) => ExprKind::RvalueDatum, - // Note: there is actually a good case to be made that // DefArg's, particularly those of immediate type, ought to // considered rvalues. diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 2a2178dd63b9f..cace98a230f61 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -262,7 +262,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ccx.tn().val_to_string(llretptr)); let (fn_abi, fn_sig) = match callee_ty.sty { - ty::TyBareFn(_, ref fn_ty) => (fn_ty.abi, &fn_ty.sig), + ty::TyFnDef(_, _, ref fn_ty) | + ty::TyFnPtr(ref fn_ty) => (fn_ty.abi, &fn_ty.sig), _ => ccx.sess().bug("trans_native_call called on non-function type") }; let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig); @@ -501,7 +502,8 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &hir::ForeignMod) { abi => { let ty = ccx.tcx().node_id_to_type(foreign_item.id); match ty.sty { - ty::TyBareFn(_, bft) => gate_simd_ffi(ccx.tcx(), &decl, bft), + ty::TyFnDef(_, _, bft) | + ty::TyFnPtr(bft) => gate_simd_ffi(ccx.tcx(), &decl, bft), _ => ccx.tcx().sess.span_bug(foreign_item.span, "foreign fn's sty isn't a bare_fn_ty?") } @@ -552,7 +554,7 @@ pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let tys = foreign_types_for_fn_ty(ccx, t); let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys); let cconv = match t.sty { - ty::TyBareFn(_, ref fn_ty) => { + ty::TyFnDef(_, _, ref fn_ty) | ty::TyFnPtr(ref fn_ty) => { llvm_calling_convention(ccx, fn_ty.abi) } _ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi") @@ -574,7 +576,7 @@ pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext, let t = ccx.tcx().node_id_to_type(node_id); let cconv = match t.sty { - ty::TyBareFn(_, ref fn_ty) => { + ty::TyFnDef(_, _, ref fn_ty) | ty::TyFnPtr(ref fn_ty) => { llvm_calling_convention(ccx, fn_ty.abi) } _ => panic!("expected bare fn in register_rust_fn_with_foreign_abi") @@ -634,7 +636,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Compute the type that the function would have if it were just a // normal Rust function. This will be the type of the wrappee fn. match t.sty { - ty::TyBareFn(_, ref f) => { + ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f)=> { assert!(f.abi != Abi::Rust); assert!(f.abi != Abi::RustIntrinsic); assert!(f.abi != Abi::PlatformIntrinsic); @@ -957,7 +959,7 @@ fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> ForeignTypes<'tcx> { let fn_sig = match ty.sty { - ty::TyBareFn(_, ref fn_ty) => &fn_ty.sig, + ty::TyFnDef(_, _, ref fn_ty) | ty::TyFnPtr(ref fn_ty) => &fn_ty.sig, _ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type") }; let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig); diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 0b2ab58a835a2..d5f8cff495600 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -356,27 +356,18 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, &unsized_args }; - bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| { - let trait_ref = ty::Binder(ty::TraitRef { - def_id: tcx.lang_items.drop_trait().unwrap(), - substs: tcx.mk_substs(Substs::trans_empty().with_self_ty(t)) - }); - let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) { - traits::VtableImpl(data) => data, - _ => tcx.sess.bug(&format!("dtor for {:?} is not an impl???", t)) - }; - let dtor_did = def.destructor().unwrap(); - let datum = callee::trans_fn_ref_with_substs(bcx.ccx(), - dtor_did, - ExprId(0), - bcx.fcx.param_substs, - vtbl.substs); - callee::Callee { - bcx: bcx, - data: callee::Fn(datum.val), - ty: datum.ty - } - }, callee::ArgVals(args), Some(expr::Ignore)).bcx; + let trait_ref = ty::Binder(ty::TraitRef { + def_id: tcx.lang_items.drop_trait().unwrap(), + substs: tcx.mk_substs(Substs::trans_empty().with_self_ty(t)) + }); + let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) { + traits::VtableImpl(data) => data, + _ => tcx.sess.bug(&format!("dtor for {:?} is not an impl???", t)) + }; + let dtor_did = def.destructor().unwrap(); + bcx = callee::Callee::ptr(callee::trans_fn_ref_with_substs( + bcx.ccx(), dtor_did, None, vtbl.substs)) + .call(bcx, DebugLoc::None, callee::ArgVals(args), Some(expr::Ignore)).bcx; bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope) } diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index b7b520f6c8259..96c1d6a4d691a 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -22,7 +22,7 @@ use trans::adt; use trans::attributes; use trans::base::*; use trans::build::*; -use trans::callee; +use trans::callee::{self, Callee}; use trans::cleanup; use trans::cleanup::CleanupMethods; use trans::common::*; @@ -45,6 +45,7 @@ use syntax::ast; use syntax::ptr::P; use syntax::parse::token; +use rustc::lint; use rustc::session::Session; use syntax::codemap::Span; @@ -125,29 +126,41 @@ pub fn check_intrinsics(ccx: &CrateContext) { transmute_restriction.substituted_to); let from_type_size = machine::llbitsize_of_real(ccx, llfromtype); let to_type_size = machine::llbitsize_of_real(ccx, lltotype); + + if let ty::TyFnDef(..) = transmute_restriction.substituted_from.sty { + if to_type_size == machine::llbitsize_of_real(ccx, ccx.int_type()) { + // FIXME #19925 Remove this warning after a release cycle. + lint::raw_emit_lint(&ccx.tcx().sess, + &ccx.tcx().sess.lint_store.borrow(), + lint::builtin::TRANSMUTE_FROM_FN_ITEM_TYPES, + (lint::Warn, lint::LintSource::Default), + Some(transmute_restriction.span), + &format!("`{}` is now zero-sized and has to be cast \ + to a pointer before transmuting to `{}`", + transmute_restriction.substituted_from, + transmute_restriction.substituted_to)); + continue; + } + } if from_type_size != to_type_size { last_failing_id = Some(transmute_restriction.id); if transmute_restriction.original_from != transmute_restriction.substituted_from { span_transmute_size_error(ccx.sess(), transmute_restriction.span, &format!("transmute called with differently sized types: \ - {} (could be {} bit{}) to {} (could be {} bit{})", + {} (could be {} bits) to {} (could be {} bits)", transmute_restriction.original_from, - from_type_size as usize, - if from_type_size == 1 {""} else {"s"}, + from_type_size, transmute_restriction.original_to, - to_type_size as usize, - if to_type_size == 1 {""} else {"s"})); + to_type_size)); } else { span_transmute_size_error(ccx.sess(), transmute_restriction.span, &format!("transmute called with differently sized types: \ - {} ({} bit{}) to {} ({} bit{})", + {} ({} bits) to {} ({} bits)", transmute_restriction.original_from, - from_type_size as usize, - if from_type_size == 1 {""} else {"s"}, + from_type_size, transmute_restriction.original_to, - to_type_size as usize, - if to_type_size == 1 {""} else {"s"})); + to_type_size)); } } } @@ -163,7 +176,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, cleanup_scope: cleanup::CustomScopeIndex, args: callee::CallArgs<'a, 'tcx>, dest: expr::Dest, - substs: subst::Substs<'tcx>, + substs: &'tcx subst::Substs<'tcx>, call_info: NodeIdAndSpan) -> Result<'blk, 'tcx> { let fcx = bcx.fcx; @@ -179,6 +192,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let foreign_item = tcx.map.expect_foreign_item(node); let name = foreign_item.name.as_str(); + let call_debug_location = DebugLoc::At(call_info.id, call_info.span); + // For `transmute` we can just trans the input expr directly into dest if name == "transmute" { let llret_ty = type_of::type_of(ccx, ret_ty.unwrap()); @@ -194,6 +209,27 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let in_type_size = machine::llbitsize_of_real(ccx, llintype); let out_type_size = machine::llbitsize_of_real(ccx, llouttype); + if let ty::TyFnDef(def_id, substs, _) = in_type.sty { + if out_type_size != 0 { + // FIXME #19925 Remove this hack after a release cycle. + let _ = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0])); + let llfn = Callee::def(ccx, def_id, substs, in_type).reify(ccx).val; + let llfnty = val_ty(llfn); + let llresult = match dest { + expr::SaveIn(d) => d, + expr::Ignore => alloc_ty(bcx, out_type, "ret") + }; + Store(bcx, llfn, PointerCast(bcx, llresult, llfnty.ptr_to())); + if dest == expr::Ignore { + bcx = glue::drop_ty(bcx, llresult, out_type, + call_debug_location); + } + fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); + fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope); + return Result::new(bcx, llresult); + } + } + // This should be caught by the intrinsicck pass assert_eq!(in_type_size, out_type_size); @@ -311,8 +347,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } - let call_debug_location = DebugLoc::At(call_info.id, call_info.span); - // For `try` we need some custom control flow if &name[..] == "try" { if let callee::ArgExprs(ref exprs) = args { @@ -364,7 +398,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, callee_ty, &mut llargs, cleanup::CustomScope(cleanup_scope), - false, Abi::RustIntrinsic); fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean(); @@ -1264,7 +1297,7 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, // Define the type up front for the signature of the rust_try function. let tcx = ccx.tcx(); let i8p = tcx.mk_mut_ptr(tcx.types.i8); - let fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + let fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -1273,9 +1306,8 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, variadic: false, }), }); - let fn_ty = tcx.mk_fn(None, fn_ty); let output = ty::FnOutput::FnConverging(tcx.types.i32); - let try_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + let try_fn_ty = ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -1283,8 +1315,8 @@ fn get_rust_try_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, output: output, variadic: false, }), - }); - let rust_try = gen_fn(fcx, "__rust_try", tcx.mk_fn(None, try_fn_ty), output, + }; + let rust_try = gen_fn(fcx, "__rust_try", tcx.mk_fn_ptr(try_fn_ty), output, trans); *ccx.rust_try_fn().borrow_mut() = Some(rust_try); return rust_try @@ -1353,7 +1385,7 @@ fn generate_filter_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, // going on here, all I can say is that there's a few tests cases in // LLVM's test suite which follow this pattern of instructions, so we // just do the same. - let filter_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + let filter_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -1362,7 +1394,6 @@ fn generate_filter_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, variadic: false, }), }); - let filter_fn_ty = tcx.mk_fn(None, filter_fn_ty); gen_fn(fcx, "__rustc_try_filter", filter_fn_ty, output, &mut |bcx| { let ebp = Call(bcx, frameaddress, &[C_i32(ccx, 1)], None, dloc); let exn = InBoundsGEP(bcx, ebp, &[C_i32(ccx, -20)]); @@ -1373,7 +1404,7 @@ fn generate_filter_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, // Conveniently on x86_64 the EXCEPTION_POINTERS handle and base pointer // are passed in as arguments to the filter function, so we just pass // those along. - let filter_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { + let filter_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -1382,7 +1413,6 @@ fn generate_filter_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, variadic: false, }), }); - let filter_fn_ty = tcx.mk_fn(None, filter_fn_ty); gen_fn(fcx, "__rustc_try_filter", filter_fn_ty, output, &mut |bcx| { let exn = llvm::get_param(bcx.fcx.llfn, 0); let rbp = llvm::get_param(bcx.fcx.llfn, 1); @@ -1400,7 +1430,7 @@ fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) { fn generic_simd_intrinsic<'blk, 'tcx, 'a> (bcx: Block<'blk, 'tcx>, name: &str, - substs: subst::Substs<'tcx>, + substs: &'tcx subst::Substs<'tcx>, callee_ty: Ty<'tcx>, args: Option<&[P]>, llargs: &[ValueRef], @@ -1508,11 +1538,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a> None => bcx.sess().span_bug(call_info.span, "intrinsic call with unexpected argument shape"), }; - let vector = match consts::const_expr( - bcx.ccx(), - vector, - tcx.mk_substs(substs), - None, + let vector = match consts::const_expr(bcx.ccx(), vector, substs, None, consts::TrueConst::Yes, // this should probably help simd error reporting ) { Ok((vector, _)) => vector, diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 221d17e6641d5..78b86dafa18ad 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -18,9 +18,8 @@ use middle::subst; use middle::traits; use trans::base::*; use trans::build::*; -use trans::callee::*; -use trans::callee; -use trans::cleanup; +use trans::callee::{Callee, Virtual, ArgVals, + trans_fn_pointer_shim, trans_fn_ref_with_substs}; use trans::closure; use trans::common::*; use trans::consts; @@ -30,11 +29,9 @@ use trans::declare; use trans::expr; use trans::glue; use trans::machine; -use trans::monomorphize; use trans::type_::Type; use trans::type_of::*; use middle::ty::{self, Ty, TyCtxt}; -use middle::ty::MethodCall; use syntax::ast; use syntax::attr; @@ -92,264 +89,99 @@ pub fn trans_impl(ccx: &CrateContext, } } -pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - method_call: MethodCall, - self_expr: Option<&hir::Expr>, - arg_cleanup_scope: cleanup::ScopeId) - -> Callee<'blk, 'tcx> { - let _icx = push_ctxt("meth::trans_method_callee"); - - let method = bcx.tcx().tables.borrow().method_map[&method_call]; - - match bcx.tcx().impl_or_trait_item(method.def_id).container() { - ty::ImplContainer(_) => { - debug!("trans_method_callee: static, {:?}", method.def_id); - let datum = callee::trans_fn_ref(bcx.ccx(), - method.def_id, - MethodCallKey(method_call), - bcx.fcx.param_substs); - Callee { - bcx: bcx, - data: Fn(datum.val), - ty: datum.ty - } - } - - ty::TraitContainer(trait_def_id) => { - let trait_ref = method.substs.to_trait_ref(bcx.tcx(), trait_def_id); - let trait_ref = ty::Binder(bcx.monomorphize(&trait_ref)); - let span = bcx.tcx().map.span(method_call.expr_id); - debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}", - method_call, - trait_ref, - trait_ref.0.def_id, - trait_ref.0.substs); - let origin = fulfill_obligation(bcx.ccx(), span, trait_ref); - debug!("origin = {:?}", origin); - trans_monomorphized_callee(bcx, - method_call, - self_expr, - trait_def_id, - method.def_id, - method.ty, - origin, - arg_cleanup_scope) - } - } -} - -pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - method_id: DefId, - trait_id: DefId, - expr_id: ast::NodeId, - param_substs: &'tcx subst::Substs<'tcx>) - -> Datum<'tcx, Rvalue> -{ - let _icx = push_ctxt("meth::trans_static_method_callee"); - let tcx = ccx.tcx(); - - debug!("trans_static_method_callee(method_id={:?}, trait_id={}, \ - expr_id={})", - method_id, - tcx.item_path_str(trait_id), - expr_id); - - let mname = tcx.item_name(method_id); - - debug!("trans_static_method_callee: method_id={:?}, expr_id={}, \ - name={}", method_id, expr_id, mname); - - // 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(ccx, ExprId(expr_id), param_substs); - debug!("rcvr_substs={:?}", rcvr_substs); - let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id)); - let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref); - - // Now that we know which impl is being used, we can dispatch to - // the actual function: - match vtbl { - traits::VtableImpl(traits::VtableImplData { - impl_def_id: impl_did, - substs: impl_substs, - nested: _ }) => - { - let callee_substs = impl_substs.with_method_from(&rcvr_substs); - let mth = tcx.get_impl_method(impl_did, callee_substs, mname); - trans_fn_ref_with_substs(ccx, mth.method.def_id, ExprId(expr_id), - param_substs, - mth.substs) - } - traits::VtableObject(ref data) => { - let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id); - trans_object_shim(ccx, - data.upcast_trait_ref.clone(), - method_id, - idx) - } - _ => { - // FIXME(#20847): handle at least VtableFnPointer - tcx.sess.bug(&format!("static call to invalid vtable: {:?}", - vtbl)); - } - } -} - -fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - method_call: MethodCall, - self_expr: Option<&hir::Expr>, - trait_id: DefId, - method_id: DefId, - method_ty: Ty<'tcx>, - vtable: traits::Vtable<'tcx, ()>, - arg_cleanup_scope: cleanup::ScopeId) - -> Callee<'blk, 'tcx> { - let _icx = push_ctxt("meth::trans_monomorphized_callee"); +/// Compute the appropriate callee, give na method's ID, trait ID, +/// substitutions and a Vtable for that trait. +pub fn callee_for_trait_impl<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + method_id: DefId, + substs: &'tcx subst::Substs<'tcx>, + trait_id: DefId, + method_ty: Ty<'tcx>, + vtable: traits::Vtable<'tcx, ()>) + -> Callee<'tcx> { + let _icx = push_ctxt("meth::callee_for_trait_impl"); match vtable { traits::VtableImpl(vtable_impl) => { - let ccx = bcx.ccx(); let impl_did = vtable_impl.impl_def_id; - let mname = match ccx.tcx().impl_or_trait_item(method_id) { - ty::MethodTraitItem(method) => method.name, - _ => { - bcx.tcx().sess.bug("can't monomorphize a non-method trait \ - item") - } - }; + let mname = ccx.tcx().item_name(method_id); // create a concatenated set of substitutions which includes // those from the impl and those from the method: - let meth_substs = node_id_substs(ccx, - MethodCallKey(method_call), - bcx.fcx.param_substs); - let impl_substs = vtable_impl.substs.with_method_from(&meth_substs); - let mth = bcx.tcx().get_impl_method(impl_did, impl_substs, mname); - // translate the function - let datum = trans_fn_ref_with_substs(bcx.ccx(), - mth.method.def_id, - MethodCallKey(method_call), - bcx.fcx.param_substs, - mth.substs); - - Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty } + let impl_substs = vtable_impl.substs.with_method_from(&substs); + let substs = ccx.tcx().mk_substs(impl_substs); + let mth = ccx.tcx().get_impl_method(impl_did, substs, mname); + + // Translate the function, bypassing Callee::def. + // That is because default methods have the same ID as the + // trait method used to look up the impl method that ended + // up here, so calling Callee::def would infinitely recurse. + Callee::ptr(trans_fn_ref_with_substs(ccx, mth.method.def_id, + Some(method_ty), mth.substs)) } traits::VtableClosure(vtable_closure) => { // The substitutions should have no type parameters remaining // after passing through fulfill_obligation - let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); - let llfn = closure::trans_closure_method(bcx.ccx(), + let trait_closure_kind = ccx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); + let llfn = closure::trans_closure_method(ccx, vtable_closure.closure_def_id, vtable_closure.substs, trait_closure_kind); - Callee { - bcx: bcx, - data: Fn(llfn), - ty: monomorphize_type(bcx, method_ty) - } + let fn_ptr_ty = match method_ty.sty { + ty::TyFnDef(_, _, fty) => ccx.tcx().mk_ty(ty::TyFnPtr(fty)), + _ => unreachable!("expected fn item type, found {}", + method_ty) + }; + Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty)) } traits::VtableFnPointer(fn_ty) => { - let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); - let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty); - Callee { - bcx: bcx, - data: Fn(llfn), - ty: monomorphize_type(bcx, method_ty) - } + let trait_closure_kind = ccx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); + let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty); + let fn_ptr_ty = match method_ty.sty { + ty::TyFnDef(_, _, fty) => ccx.tcx().mk_ty(ty::TyFnPtr(fty)), + _ => unreachable!("expected fn item type, found {}", + method_ty) + }; + Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty)) } traits::VtableObject(ref data) => { - let idx = traits::get_vtable_index_of_object_method(bcx.tcx(), data, method_id); - if let Some(self_expr) = self_expr { - if let ty::TyBareFn(_, ref fty) = monomorphize_type(bcx, method_ty).sty { - let ty = bcx.tcx().mk_fn(None, opaque_method_ty(bcx.tcx(), fty)); - return trans_trait_callee(bcx, ty, idx, self_expr, arg_cleanup_scope); - } + Callee { + data: Virtual(traits::get_vtable_index_of_object_method( + ccx.tcx(), data, method_id)), + ty: method_ty } - let datum = trans_object_shim(bcx.ccx(), - data.upcast_trait_ref.clone(), - method_id, - idx); - Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty } } traits::VtableBuiltin(..) | traits::VtableDefaultImpl(..) | traits::VtableParam(..) => { - bcx.sess().bug( + ccx.sess().bug( &format!("resolved vtable bad vtable {:?} in trans", vtable)); } } } -/// Create a method callee where the method is coming from a trait object (e.g., Box type). -/// In this case, we must pull the fn pointer out of the vtable that is packaged up with the -/// object. Objects are represented as a pair, so we first evaluate the self expression and then -/// extract the self data and vtable out of the pair. -fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - opaque_fn_ty: Ty<'tcx>, - vtable_index: usize, - self_expr: &hir::Expr, - arg_cleanup_scope: cleanup::ScopeId) - -> Callee<'blk, 'tcx> { - let _icx = push_ctxt("meth::trans_trait_callee"); - let mut bcx = bcx; - - // Translate self_datum and take ownership of the value by - // converting to an rvalue. - let self_datum = unpack_datum!( - bcx, expr::trans(bcx, self_expr)); - - let llval = if bcx.fcx.type_needs_drop(self_datum.ty) { - let self_datum = unpack_datum!( - bcx, self_datum.to_rvalue_datum(bcx, "trait_callee")); - - // Convert to by-ref since `trans_trait_callee_from_llval` wants it - // that way. - let self_datum = unpack_datum!( - bcx, self_datum.to_ref_datum(bcx)); - - // Arrange cleanup in case something should go wrong before the - // actual call occurs. - self_datum.add_clean(bcx.fcx, arg_cleanup_scope) - } else { - // We don't have to do anything about cleanups for &Trait and &mut Trait. - assert!(self_datum.kind.is_by_ref()); - self_datum.val - }; - - let llself = Load(bcx, expr::get_dataptr(bcx, llval)); - let llvtable = Load(bcx, expr::get_meta(bcx, llval)); - trans_trait_callee_from_llval(bcx, opaque_fn_ty, vtable_index, llself, llvtable) -} - -/// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object -/// pair. -fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - opaque_fn_ty: Ty<'tcx>, - vtable_index: usize, - llself: ValueRef, - llvtable: ValueRef) - -> Callee<'blk, 'tcx> { - let _icx = push_ctxt("meth::trans_trait_callee"); +/// Extracts a method from a trait object's vtable, at the +/// specified index, and casts it to the given type. +pub fn get_virtual_method<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + llvtable: ValueRef, + vtable_index: usize, + method_ty: Ty<'tcx>) + -> Datum<'tcx, Rvalue> { + let _icx = push_ctxt("meth::get_virtual_method"); let ccx = bcx.ccx(); // Load the data pointer from the object. - debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llself={}, llvtable={})", - opaque_fn_ty, + debug!("get_virtual_method(callee_ty={}, vtable_index={}, llvtable={})", + method_ty, vtable_index, - bcx.val_to_string(llself), bcx.val_to_string(llvtable)); - // Replace the self type (&Self or Box) with an opaque pointer. let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET])); - let llcallee_ty = type_of_fn_from_ty(ccx, opaque_fn_ty); - Callee { - bcx: bcx, - data: TraitItem(MethodData { - llfn: PointerCast(bcx, mptr, llcallee_ty.ptr_to()), - llself: PointerCast(bcx, llself, Type::i8p(ccx)), - }), - ty: opaque_fn_ty + // Replace the self type (&Self or Box) with an opaque pointer. + if let ty::TyFnDef(_, _, fty) = method_ty.sty { + let opaque_ty = opaque_method_ty(ccx.tcx(), fty); + immediate_rvalue(PointerCast(bcx, mptr, type_of(ccx, opaque_ty)), opaque_ty) + } else { + immediate_rvalue(mptr, method_ty) } } @@ -374,46 +206,29 @@ fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// /// In fact, all virtual calls can be thought of as normal trait calls /// that go through this shim function. -pub fn trans_object_shim<'a, 'tcx>( - ccx: &'a CrateContext<'a, 'tcx>, - upcast_trait_ref: ty::PolyTraitRef<'tcx>, - method_id: DefId, - vtable_index: usize) - -> Datum<'tcx, Rvalue> -{ +pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, + method_ty: Ty<'tcx>, + vtable_index: usize) + -> Datum<'tcx, Rvalue> { let _icx = push_ctxt("trans_object_shim"); let tcx = ccx.tcx(); - debug!("trans_object_shim(upcast_trait_ref={:?}, method_id={:?})", - upcast_trait_ref, - method_id); + debug!("trans_object_shim(vtable_index={}, method_ty={:?})", + vtable_index, + method_ty); - // Upcast to the trait in question and extract out the substitutions. - let upcast_trait_ref = tcx.erase_late_bound_regions(&upcast_trait_ref); - let object_substs = upcast_trait_ref.substs.clone().erase_regions(); - debug!("trans_object_shim: object_substs={:?}", object_substs); + let ret_ty = tcx.erase_late_bound_regions(&method_ty.fn_ret()); + let ret_ty = infer::normalize_associated_type(tcx, &ret_ty); - // Lookup the type of this method as declared in the trait and apply substitutions. - let method_ty = match tcx.impl_or_trait_item(method_id) { - ty::MethodTraitItem(method) => method, - _ => { - tcx.sess.bug("can't create a method shim for a non-method item") - } + let shim_fn_ty = match method_ty.sty { + ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)), + _ => unreachable!("expected fn item type, found {}", method_ty) }; - let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty); - let fty = tcx.mk_bare_fn(fty); - let method_ty = opaque_method_ty(tcx, fty); - debug!("trans_object_shim: fty={:?} method_ty={:?}", fty, method_ty); // - let shim_fn_ty = tcx.mk_fn(None, fty); - let method_bare_fn_ty = tcx.mk_fn(None, method_ty); let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty); - let sig = ccx.tcx().erase_late_bound_regions(&fty.sig); - let sig = infer::normalize_associated_type(ccx.tcx(), &sig); - let empty_substs = tcx.mk_substs(Substs::trans_empty()); let (block_arena, fcx): (TypedArena<_>, FunctionContext); block_arena = TypedArena::new(); @@ -421,11 +236,11 @@ pub fn trans_object_shim<'a, 'tcx>( llfn, ast::DUMMY_NODE_ID, false, - sig.output, + ret_ty, empty_substs, None, &block_arena); - let mut bcx = init_function(&fcx, false, sig.output); + let mut bcx = init_function(&fcx, false, ret_ty); let llargs = get_params(fcx.llfn); @@ -440,21 +255,18 @@ pub fn trans_object_shim<'a, 'tcx>( let dest = fcx.llretslotptr.get().map( - |_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))); + |_| expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot"))); debug!("trans_object_shim: method_offset_in_vtable={}", vtable_index); - bcx = trans_call_inner(bcx, - DebugLoc::None, - |bcx, _| trans_trait_callee_from_llval(bcx, - method_bare_fn_ty, - vtable_index, - llself, llvtable), - ArgVals(&llargs[(self_idx + 2)..]), - dest).bcx; + let callee = Callee { + data: Virtual(vtable_index), + ty: method_ty + }; + bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx; - finish_fn(&fcx, bcx, sig.output, DebugLoc::None); + finish_fn(&fcx, bcx, ret_ty, DebugLoc::None); immediate_rvalue(llfn, shim_fn_ty) } @@ -466,8 +278,7 @@ pub fn trans_object_shim<'a, 'tcx>( /// making an object `Foo` from a value of type `Foo`, then /// `trait_ref` would map `T:Trait`. pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - param_substs: &'tcx subst::Substs<'tcx>) + trait_ref: ty::PolyTraitRef<'tcx>) -> ValueRef { let tcx = ccx.tcx(); @@ -503,8 +314,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Some(mth) => { trans_fn_ref_with_substs(ccx, mth.method.def_id, - ExprId(0), - param_substs, + None, mth.substs).val } None => nullptr @@ -567,7 +377,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, impl_id: DefId, - substs: subst::Substs<'tcx>) + substs: &'tcx subst::Substs<'tcx>) -> Vec>> { let tcx = ccx.tcx(); @@ -618,7 +428,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // The substitutions we have are on the impl, so we grab // the method type from the impl to substitute into. - let mth = tcx.get_impl_method(impl_id, substs.clone(), name); + let mth = tcx.get_impl_method(impl_id, substs, name); debug!("get_vtable_methods: mth={:?}", mth); @@ -628,7 +438,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // method could then never be called, so we do not want to // try and trans it, in that case. Issue #23435. if mth.is_provided { - let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs); + let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs); if !normalize_and_test_predicates(ccx, predicates.into_vec()) { debug!("get_vtable_methods: predicates do not hold"); return None; @@ -642,11 +452,11 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, /// Replace the self type (&Self or Box) with an opaque pointer. fn opaque_method_ty<'tcx>(tcx: &TyCtxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>) - -> &'tcx ty::BareFnTy<'tcx> { + -> Ty<'tcx> { let mut inputs = method_ty.sig.0.inputs.clone(); inputs[0] = tcx.mk_mut_ptr(tcx.mk_mach_int(ast::IntTy::I8)); - tcx.mk_bare_fn(ty::BareFnTy { + tcx.mk_fn_ptr(ty::BareFnTy { unsafety: method_ty.unsafety, abi: method_ty.abi, sig: ty::Binder(ty::FnSig { diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index a9fee18ded8f4..50283c0959c3f 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -9,72 +9,27 @@ // except according to those terms. use llvm::{BasicBlockRef, ValueRef, OperandBundleDef}; -use rustc::middle::ty::{self, Ty}; +use rustc::middle::ty; use rustc::mir::repr as mir; use syntax::abi::Abi; use trans::adt; use trans::attributes; use trans::base; use trans::build; +use trans::callee::{Callee, Fn, Virtual}; use trans::common::{self, Block, BlockAndBuilder}; use trans::debuginfo::DebugLoc; use trans::Disr; use trans::foreign; +use trans::meth; use trans::type_of; use trans::glue; use trans::type_::Type; use super::{MirContext, drop}; use super::operand::OperandValue::{FatPtr, Immediate, Ref}; -use super::operand::OperandRef; - -#[derive(PartialEq, Eq)] -enum AbiStyle { - Foreign, - RustCall, - Rust -} impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { - fn abi_style(&self, fn_ty: Ty<'tcx>) -> AbiStyle { - if let ty::TyBareFn(_, ref f) = fn_ty.sty { - // We do not translate intrinsics here (they shouldn’t be functions) - assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic); - - match f.abi { - Abi::Rust => AbiStyle::Rust, - Abi::RustCall => AbiStyle::RustCall, - _ => AbiStyle::Foreign - } - } else { - unreachable!() - } - } - - fn arg_operands(&mut self, - bcx: &BlockAndBuilder<'bcx, 'tcx>, - abi_style: AbiStyle, - args: &[mir::Operand<'tcx>]) - -> Vec> - { - match abi_style { - AbiStyle::Foreign | AbiStyle::Rust => { - args.iter().map(|arg| self.trans_operand(bcx, arg)).collect() - } - AbiStyle::RustCall => match args.split_last() { - None => vec![], - Some((tup, self_ty)) => { - // we can reorder safely because of MIR - let untupled_args = self.trans_operand_untupled(bcx, tup); - self_ty - .iter().map(|arg| self.trans_operand(bcx, arg)) - .chain(untupled_args.into_iter()) - .collect() - } - } - } - } - pub fn trans_block(&mut self, bb: mir::BasicBlock) { debug!("trans_block({:?})", bb); @@ -197,9 +152,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } mir::Terminator::Call { ref func, ref args, ref destination, ref cleanup } => { - // Create the callee. This will always be a fn ptr and hence a kind of scalar. + // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.trans_operand(&bcx, func); - let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty); let debugloc = DebugLoc::None; // The arguments we'll be passing. Plus one to account for outptr, if used. let mut llargs = Vec::with_capacity(args.len() + 1); @@ -207,9 +161,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // filled when `is_foreign` is `true` and foreign calls are minority of the cases. let mut arg_tys = Vec::new(); + let (callee, fty) = match callee.ty.sty { + ty::TyFnDef(def_id, substs, f) => { + (Callee::def(bcx.ccx(), def_id, substs, callee.ty), f) + } + ty::TyFnPtr(f) => { + (Callee { + data: Fn(callee.immediate()), + ty: callee.ty + }, f) + } + _ => unreachable!("{} is not callable", callee.ty) + }; + + // We do not translate intrinsics here (they shouldn’t be functions) + assert!(fty.abi != Abi::RustIntrinsic && fty.abi != Abi::PlatformIntrinsic); // Foreign-ABI functions are translated differently - let abi_style = self.abi_style(callee.ty); - let is_foreign = abi_style == AbiStyle::Foreign; + let is_foreign = fty.abi != Abi::Rust && fty.abi != Abi::RustCall; // Prepare the return value destination let (ret_dest_ty, must_copy_dest) = if let Some((ref d, _)) = *destination { @@ -225,19 +193,58 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { (None, false) }; - // Process the rest of the args. - for operand in self.arg_operands(&bcx, abi_style, args) { - match operand.val { - Ref(llval) | Immediate(llval) => llargs.push(llval), - FatPtr(b, e) => { - llargs.push(b); - llargs.push(e); + // Split the rust-call tupled arguments off. + let (args, rest) = if fty.abi == Abi::RustCall && !args.is_empty() { + let (tup, args) = args.split_last().unwrap(); + // we can reorder safely because of MIR + (args, self.trans_operand_untupled(&bcx, tup)) + } else { + (&args[..], vec![]) + }; + + let datum = { + let mut arg_ops = args.iter().map(|arg| { + self.trans_operand(&bcx, arg) + }).chain(rest.into_iter()); + + // Get the actual pointer we can call. + // This can involve vtable accesses or reification. + let datum = if let Virtual(idx) = callee.data { + assert!(!is_foreign); + + // Grab the first argument which is a trait object. + let vtable = match arg_ops.next().unwrap().val { + FatPtr(data, vtable) => { + llargs.push(data); + vtable + } + _ => unreachable!("expected FatPtr for Virtual call") + }; + + bcx.with_block(|bcx| { + meth::get_virtual_method(bcx, vtable, idx, callee.ty) + }) + } else { + callee.reify(bcx.ccx()) + }; + + // Process the rest of the args. + for operand in arg_ops { + match operand.val { + Ref(llval) | Immediate(llval) => llargs.push(llval), + FatPtr(b, e) => { + llargs.push(b); + llargs.push(e); + } + } + if is_foreign { + arg_tys.push(operand.ty); } } - if is_foreign { - arg_tys.push(operand.ty); - } - } + + datum + }; + let attrs = attributes::from_fn_type(bcx.ccx(), datum.ty); // Many different ways to call a function handled here match (is_foreign, cleanup, destination) { @@ -246,7 +253,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let cleanup = self.bcx(cleanup); let landingpad = self.make_landing_pad(cleanup); let unreachable_blk = self.unreachable_block(); - bcx.invoke(callee.immediate(), + bcx.invoke(datum.val, &llargs[..], unreachable_blk.llbb, landingpad.llbb(), @@ -259,7 +266,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { (false, &Some(cleanup), &Some((_, success))) => { let cleanup = self.bcx(cleanup); let landingpad = self.make_landing_pad(cleanup); - let invokeret = bcx.invoke(callee.immediate(), + let invokeret = bcx.invoke(datum.val, &llargs[..], self.llblock(success), landingpad.llbb(), @@ -282,7 +289,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { }); }, (false, _, &None) => { - bcx.call(callee.immediate(), + bcx.call(datum.val, &llargs[..], cleanup_bundle.as_ref(), Some(attrs)); @@ -290,7 +297,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { bcx.unreachable(); } (false, _, &Some((_, target))) => { - let llret = bcx.call(callee.immediate(), + let llret = bcx.call(datum.val, &llargs[..], cleanup_bundle.as_ref(), Some(attrs)); @@ -312,8 +319,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { .expect("return destination is not set"); bcx = bcx.map_block(|bcx| { foreign::trans_native_call(bcx, - callee.ty, - callee.immediate(), + datum.ty, + datum.val, dest.llval, &llargs[..], arg_tys, diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs index 7f03069385fec..a0615a6cf5b18 100644 --- a/src/librustc_trans/trans/mir/constant.rs +++ b/src/librustc_trans/trans/mir/constant.rs @@ -10,14 +10,14 @@ use back::abi; use llvm::ValueRef; -use middle::subst::Substs; use middle::ty::{Ty, TypeFoldable}; -use rustc::middle::const_eval::ConstVal; +use rustc::middle::const_eval::{self, ConstVal}; use rustc::mir::repr as mir; use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral, - C_str_slice}; + C_str_slice, C_nil, C_undef}; use trans::consts; use trans::expr; +use trans::inline; use trans::type_of; use super::operand::{OperandRef, OperandValue}; @@ -32,7 +32,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { -> OperandRef<'tcx> { let ccx = bcx.ccx(); - let val = self.trans_constval_inner(bcx, cv, ty, bcx.fcx().param_substs); + let val = self.trans_constval_inner(bcx, cv, ty); let val = if common::type_is_immediate(ccx, ty) { OperandValue::Immediate(val) } else if common::type_is_fat_ptr(bcx.tcx(), ty) { @@ -55,8 +55,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { fn trans_constval_inner(&mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>, cv: &ConstVal, - ty: Ty<'tcx>, - param_substs: &'tcx Substs<'tcx>) + ty: Ty<'tcx>) -> ValueRef { let ccx = bcx.ccx(); @@ -75,8 +74,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { expr::trans(bcx, expr).datum.val }) }, - ConstVal::Function(did) => - self.trans_fn_ref(bcx, ty, param_substs, did).immediate() + ConstVal::Function(_) => C_nil(ccx) } } @@ -85,13 +83,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { constant: &mir::Constant<'tcx>) -> OperandRef<'tcx> { + let ty = bcx.monomorphize(&constant.ty); match constant.literal { - mir::Literal::Item { def_id, kind, substs } => { + mir::Literal::Item { def_id, substs } => { + // Shortcut for zero-sized types, including function item + // types, which would not work with lookup_const_by_id. + if common::type_is_zero_size(bcx.ccx(), ty) { + let llty = type_of::type_of(bcx.ccx(), ty); + return OperandRef { + val: OperandValue::Immediate(C_undef(llty)), + ty: ty + }; + } + let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs)); - self.trans_item_ref(bcx, constant.ty, kind, substs, def_id) + let def_id = inline::maybe_instantiate_inline(bcx.ccx(), def_id); + let expr = const_eval::lookup_const_by_id(bcx.tcx(), def_id, None, Some(substs)) + .expect("def was const, but lookup_const_by_id failed"); + // FIXME: this is falling back to translating from HIR. This is not easy to fix, + // because we would have somehow adapt const_eval to work on MIR rather than HIR. + let d = bcx.with_block(|bcx| { + expr::trans(bcx, expr) + }); + OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum) } mir::Literal::Value { ref value } => { - let ty = bcx.monomorphize(&constant.ty); self.trans_constval(bcx, value, ty) } } diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs deleted file mode 100644 index 3741b07d248e2..0000000000000 --- a/src/librustc_trans/trans/mir/did.rs +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2015 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. - -//! Code for translating references to other items (DefIds). - -use syntax::codemap::DUMMY_SP; -use rustc::front::map; -use rustc::middle::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::middle::subst::Substs; -use rustc::middle::const_eval; -use rustc::middle::def_id::DefId; -use rustc::middle::traits; -use rustc::mir::repr::ItemKind; -use trans::common::{BlockAndBuilder, fulfill_obligation}; -use trans::base; -use trans::closure; -use trans::expr; -use trans::monomorphize; -use trans::meth; -use trans::inline; - -use super::MirContext; -use super::operand::{OperandRef, OperandValue}; - -impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { - /// Translate reference to item. - pub fn trans_item_ref(&mut self, - bcx: &BlockAndBuilder<'bcx, 'tcx>, - ty: Ty<'tcx>, - kind: ItemKind, - substs: &'tcx Substs<'tcx>, - did: DefId) - -> OperandRef<'tcx> { - debug!("trans_item_ref(ty={:?}, kind={:?}, substs={:?}, did={})", - ty, kind, substs, bcx.tcx().item_path_str(did)); - - match kind { - ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did), - ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() { - ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did), - ty::TraitContainer(tdid) => self.trans_trait_method(bcx, ty, did, tdid, substs) - }, - ItemKind::Constant => { - let did = inline::maybe_instantiate_inline(bcx.ccx(), did); - let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None, Some(substs)) - .expect("def was const, but lookup_const_by_id failed"); - // FIXME: this is falling back to translating from HIR. This is not easy to fix, - // because we would have somehow adapt const_eval to work on MIR rather than HIR. - let d = bcx.with_block(|bcx| { - expr::trans(bcx, expr) - }); - OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum) - } - } - } - - /// Translates references to a function-like items. - /// - /// That includes regular functions, non-static methods, struct and enum variant constructors, - /// closures and possibly more. - /// - /// This is an adaptation of callee::trans_fn_ref_with_substs. - pub fn trans_fn_ref(&mut self, - bcx: &BlockAndBuilder<'bcx, 'tcx>, - ty: Ty<'tcx>, - substs: &'tcx Substs<'tcx>, - did: DefId) - -> OperandRef<'tcx> { - debug!("trans_fn_ref(ty={:?}, substs={:?}, did={})", - ty, substs, bcx.tcx().item_path_str(did)); - - let did = inline::maybe_instantiate_inline(bcx.ccx(), did); - - if !substs.types.is_empty() || is_named_tuple_constructor(bcx.tcx(), did) { - let (val, fn_ty, _) = monomorphize::monomorphic_fn(bcx.ccx(), did, substs, None); - // FIXME: cast fnptr to proper type if necessary - OperandRef { - ty: fn_ty, - val: OperandValue::Immediate(val) - } - } else { - let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) { - base::get_item_val(bcx.ccx(), node_id) - } else { - base::trans_external_path(bcx.ccx(), did, ty) - }; - // FIXME: cast fnptr to proper type if necessary - OperandRef { - ty: ty, - val: OperandValue::Immediate(val) - } - } - } - - /// Translates references to trait methods. - /// - /// This is an adaptation of meth::trans_static_method_callee - pub fn trans_trait_method(&mut self, - bcx: &BlockAndBuilder<'bcx, 'tcx>, - ty: Ty<'tcx>, - method_id: DefId, - trait_id: DefId, - substs: &'tcx Substs<'tcx>) - -> OperandRef<'tcx> { - debug!("trans_static_method(ty={:?}, method={}, trait={}, substs={:?})", - ty, - bcx.tcx().item_path_str(method_id), - bcx.tcx().item_path_str(trait_id), - substs); - - let ccx = bcx.ccx(); - let tcx = bcx.tcx(); - let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id)); - let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref); - match vtbl { - traits::VtableImpl(traits::VtableImplData { - impl_def_id, substs: impl_substs, .. - }) => { - assert!(!impl_substs.types.needs_infer()); - - let mname = tcx.item_name(method_id); - - let callee_substs = impl_substs.with_method_from(substs); - let mth = tcx.get_impl_method(impl_def_id, callee_substs, mname); - let mth_substs = tcx.mk_substs(mth.substs); - self.trans_fn_ref(bcx, ty, mth_substs, mth.method.def_id) - }, - traits::VtableClosure(data) => { - let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap(); - let llfn = closure::trans_closure_method(bcx.ccx(), - data.closure_def_id, - data.substs, - trait_closure_kind); - OperandRef { - ty: ty, - val: OperandValue::Immediate(llfn) - } - }, - traits::VtableObject(ref data) => { - let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id); - OperandRef::from_rvalue_datum( - meth::trans_object_shim(ccx, data.upcast_trait_ref.clone(), method_id, idx) - ) - } - _ => { - tcx.sess.bug(&format!("static call to invalid vtable: {:?}", vtbl)); - } - } - } -} - -fn is_named_tuple_constructor(tcx: &TyCtxt, def_id: DefId) -> bool { - let node_id = match tcx.map.as_local_node_id(def_id) { - Some(n) => n, - None => { return false; } - }; - match tcx.map.find(node_id).expect("local item should be in ast map") { - map::NodeVariant(v) => { - v.node.data.is_tuple() - } - map::NodeStructCtor(_) => true, - _ => false - } -} diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index 40dc22e31aa6c..4ad2e035945f3 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -196,7 +196,6 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>, mod analyze; mod block; mod constant; -mod did; mod drop; mod lvalue; mod operand; diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index 541df43b49b9a..ce10ed425f63a 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -15,6 +15,7 @@ use rustc::mir::repr as mir; use trans::asm; use trans::base; +use trans::callee::Callee; use trans::common::{self, BlockAndBuilder, Result}; use trans::debuginfo::DebugLoc; use trans::declare; @@ -193,9 +194,20 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let cast_ty = bcx.monomorphize(&cast_ty); let val = match *kind { - mir::CastKind::ReifyFnPointer | + mir::CastKind::ReifyFnPointer => { + match operand.ty.sty { + ty::TyFnDef(def_id, substs, _) => { + OperandValue::Immediate( + Callee::def(bcx.ccx(), def_id, substs, operand.ty) + .reify(bcx.ccx()).val) + } + _ => { + unreachable!("{} cannot be reified to a fn ptr", operand.ty) + } + } + } mir::CastKind::UnsafeFnPointer => { - // these are no-ops at the LLVM level + // this is a no-op at the LLVM level operand.val } mir::CastKind::Unsize => { diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 9edda3d2b5c9b..c6119416e47ed 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -37,16 +37,9 @@ use std::hash::{Hasher, Hash, SipHasher}; pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: DefId, - psubsts: &'tcx subst::Substs<'tcx>, - ref_id: Option) + psubsts: &'tcx subst::Substs<'tcx>) -> (ValueRef, Ty<'tcx>, bool) { - debug!("monomorphic_fn(\ - fn_id={:?}, \ - real_substs={:?}, \ - ref_id={:?})", - fn_id, - psubsts, - ref_id); + debug!("monomorphic_fn(fn_id={:?}, real_substs={:?})", fn_id, psubsts); assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types()); diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 24a7fd372f636..b78bf9bfc3fb2 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -150,26 +150,6 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Type::func(&atys[..], &lloutputtype) } -// Given a function type and a count of ty params, construct an llvm type -pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) -> Type { - match fty.sty { - ty::TyBareFn(_, ref f) => { - // FIXME(#19925) once fn item types are - // zero-sized, we'll need to do something here - if f.abi == Abi::Rust || f.abi == Abi::RustCall { - let sig = cx.tcx().erase_late_bound_regions(&f.sig); - let sig = infer::normalize_associated_type(cx.tcx(), &sig); - type_of_rust_fn(cx, None, &sig, f.abi) - } else { - foreign::lltype_for_foreign_fn(cx, fty) - } - } - _ => { - cx.sess().bug("type_of_fn_from_ty given non-closure, non-bare-fn") - } - } -} - // A "sizing type" is an LLVM type, the size and alignment of which are // guaranteed to be equivalent to what you would get out of `type_of()`. It's // useful because: @@ -210,7 +190,8 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ } } - ty::TyBareFn(..) => Type::i8p(cx), + ty::TyFnDef(..) => Type::nil(cx), + ty::TyFnPtr(_) => Type::i8p(cx), ty::TyArray(ty, size) => { let llty = sizing_type_of(cx, ty); @@ -415,8 +396,15 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ty::TySlice(ty) => in_memory_type_of(cx, ty), ty::TyStr | ty::TyTrait(..) => Type::i8(cx), - ty::TyBareFn(..) => { - type_of_fn_from_ty(cx, t).ptr_to() + ty::TyFnDef(..) => Type::nil(cx), + ty::TyFnPtr(f) => { + if f.abi == Abi::Rust || f.abi == Abi::RustCall { + let sig = cx.tcx().erase_late_bound_regions(&f.sig); + let sig = infer::normalize_associated_type(cx.tcx(), &sig); + type_of_rust_fn(cx, None, &sig, f.abi).ptr_to() + } else { + foreign::lltype_for_foreign_fn(cx, t).ptr_to() + } } ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx), ty::TyTuple(..) => { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 134da7a3bb0bb..1938fa7582918 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1636,8 +1636,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, } hir::TyBareFn(ref bf) => { require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span); - let bare_fn = ty_of_bare_fn(this, bf.unsafety, bf.abi, &bf.decl); - tcx.mk_fn(None, tcx.mk_bare_fn(bare_fn)) + tcx.mk_fn_ptr(ty_of_bare_fn(this, bf.unsafety, bf.abi, &bf.decl)) } hir::TyPolyTraitRef(ref bounds) => { conv_ty_poly_trait_ref(this, rscope, ast_ty.span, bounds) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 548f5ee5e949d..305970db9e72e 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -15,9 +15,10 @@ use middle::pat_util::pat_is_resolved_const; use middle::subst::Substs; use middle::ty::{self, Ty, TypeFoldable, LvaluePreference}; use check::{check_expr, check_expr_has_type, check_expr_with_expectation}; -use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation}; +use check::{demand, FnCtxt, Expectation}; use check::{check_expr_with_lvalue_pref}; use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type}; +use check::coercion; use lint; use require_same_types; use util::nodemap::FnvHashMap; @@ -492,54 +493,67 @@ pub fn check_match<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // of execution reach it, we will panic, so bottom is an appropriate // type in that case) let expected = expected.adjust_for_branches(fcx); - let result_ty = arms.iter().fold(fcx.infcx().next_diverging_ty_var(), |result_ty, arm| { - let bty = match expected { - // We don't coerce to `()` so that if the match expression is a - // statement it's branches can have any consistent type. That allows - // us to give better error messages (pointing to a usually better - // arm for inconsistent arms or to the whole match when a `()` type - // is required). - Expectation::ExpectHasType(ety) if ety != fcx.tcx().mk_nil() => { - check_expr_coercable_to_type(fcx, &arm.body, ety); - ety - } - _ => { - check_expr_with_expectation(fcx, &arm.body, expected); - fcx.node_ty(arm.body.id) + let mut result_ty = fcx.infcx().next_diverging_ty_var(); + let coerce_first = match expected { + // We don't coerce to `()` so that if the match expression is a + // statement it's branches can have any consistent type. That allows + // us to give better error messages (pointing to a usually better + // arm for inconsistent arms or to the whole match when a `()` type + // is required). + Expectation::ExpectHasType(ety) if ety != fcx.tcx().mk_nil() => { + ety + } + _ => result_ty + }; + for (i, arm) in arms.iter().enumerate() { + if let Some(ref e) = arm.guard { + check_expr_has_type(fcx, e, tcx.types.bool); + } + check_expr_with_expectation(fcx, &arm.body, expected); + let arm_ty = fcx.expr_ty(&arm.body); + + if result_ty.references_error() || arm_ty.references_error() { + result_ty = tcx.types.err; + continue; + } + + // Handle the fallback arm of a desugared if-let like a missing else. + let is_if_let_fallback = match match_src { + hir::MatchSource::IfLetDesugar { contains_else_clause: false } => { + i == arms.len() - 1 && arm_ty.is_nil() } + _ => false }; - if let Some(ref e) = arm.guard { - check_expr_has_type(fcx, &e, tcx.types.bool); - } + let origin = if is_if_let_fallback { + TypeOrigin::IfExpressionWithNoElse(expr.span) + } else { + TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src) + }; - if result_ty.references_error() || bty.references_error() { - tcx.types.err + let result = if is_if_let_fallback { + fcx.infcx().eq_types(true, origin, arm_ty, result_ty).map(|_| arm_ty) + } else if i == 0 { + // Special-case the first arm, as it has no "previous expressions". + coercion::try(fcx, &arm.body, coerce_first) } else { - let (origin, expected, found) = match match_src { - /* if-let construct without an else block */ - hir::MatchSource::IfLetDesugar { contains_else_clause } - if !contains_else_clause => ( - TypeOrigin::IfExpressionWithNoElse(expr.span), - bty, - result_ty, - ), - _ => ( - TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src), - result_ty, - bty, - ), - }; + let prev_arms = || arms[..i].iter().map(|arm| &*arm.body); + coercion::try_find_lub(fcx, origin, prev_arms, result_ty, &arm.body) + }; - infer::common_supertype( - fcx.infcx(), - origin, - true, - expected, - found, - ) - } - }); + result_ty = match result { + Ok(ty) => ty, + Err(e) => { + let (expected, found) = if is_if_let_fallback { + (arm_ty, result_ty) + } else { + (result_ty, arm_ty) + }; + fcx.infcx().report_mismatched_types(origin, expected, found, e); + fcx.tcx().types.err + } + }; + } fcx.write_ty(expr.id, result_ty); } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 42ea3cc2aaa7b..bf60f435a2213 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -82,7 +82,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, autoderef(fcx, callee_expr.span, original_callee_ty, - Some(callee_expr), + || Some(callee_expr), UnresolvedTypeAction::Error, LvaluePreference::NoPreference, |adj_ty, idx| { @@ -130,7 +130,7 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // If the callee is a bare function or a closure, then we're all set. match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty { - ty::TyBareFn(..) => { + ty::TyFnDef(..) | ty::TyFnPtr(_) => { fcx.write_autoderef_adjustment(callee_expr.id, autoderefs); return Some(CallStep::Builtin); } @@ -225,7 +225,8 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, let error_fn_sig; let fn_sig = match callee_ty.sty { - ty::TyBareFn(_, &ty::BareFnTy {ref sig, ..}) => { + ty::TyFnDef(_, _, &ty::BareFnTy {ref sig, ..}) | + ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => { sig } _ => { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 2ea0df280db21..b5cd5d7f8e5a3 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -55,7 +55,7 @@ use syntax::ast; /// Reifies a cast check to be checked once we have full type information for /// a function context. pub struct CastCheck<'tcx> { - expr: hir::Expr, + expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span, @@ -109,7 +109,7 @@ enum CastError { } impl<'tcx> CastCheck<'tcx> { - pub fn new(expr: hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span) + pub fn new(expr: &'tcx hir::Expr, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, span: Span) -> CastCheck<'tcx> { CastCheck { expr: expr, @@ -235,6 +235,20 @@ impl<'tcx> CastCheck<'tcx> { let (t_from, t_cast) = match (CastTy::from_ty(self.expr_ty), CastTy::from_ty(self.cast_ty)) { (Some(t_from), Some(t_cast)) => (t_from, t_cast), + // Function item types may need to be reified before casts. + (None, Some(t_cast)) => { + if let ty::TyFnDef(_, _, f) = self.expr_ty.sty { + // Attempt a coercion to a fn pointer type. + let res = coercion::try(fcx, self.expr, + fcx.tcx().mk_ty(ty::TyFnPtr(f))); + if !res.is_ok() { + return Err(CastError::NonScalar); + } + (FnPtr, t_cast) + } else { + return Err(CastError::NonScalar); + } + } _ => { return Err(CastError::NonScalar) } @@ -376,14 +390,7 @@ impl<'tcx> CastCheck<'tcx> { } fn try_coercion_cast<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> bool { - if let Ok(()) = coercion::mk_assignty(fcx, - &self.expr, - self.expr_ty, - self.cast_ty) { - true - } else { - false - } + coercion::try(fcx, self.expr, self.cast_ty).is_ok() } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 5ab3c6f983f96..aa359c95e2d14 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -62,7 +62,7 @@ use check::{autoderef, FnCtxt, UnresolvedTypeAction}; -use middle::infer::{self, Coercion, TypeOrigin}; +use middle::infer::{Coercion, TypeOrigin, TypeTrace}; use middle::traits::{self, ObligationCause}; use middle::traits::{predicate_for_trait_def, report_selection_error}; use middle::ty::adjustment::{AutoAdjustment, AutoDerefRef, AdjustDerefRef}; @@ -71,7 +71,7 @@ use middle::ty::adjustment::{AdjustUnsafeFnPointer, AdjustMutToConstPointer}; use middle::ty::{self, LvaluePreference, TypeAndMut, Ty, TyCtxt}; use middle::ty::fold::TypeFoldable; use middle::ty::error::TypeError; -use middle::ty::relate::RelateResult; +use middle::ty::relate::{relate_substs, RelateResult, TypeRelation}; use util::common::indent; use std::cell::RefCell; @@ -80,42 +80,75 @@ use rustc_front::hir; struct Coerce<'a, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'tcx>, - origin: infer::TypeOrigin, + origin: TypeOrigin, + use_lub: bool, unsizing_obligations: RefCell>>, } -type CoerceResult<'tcx> = RelateResult<'tcx, Option>>; +type CoerceResult<'tcx> = RelateResult<'tcx, (Ty<'tcx>, AutoAdjustment<'tcx>)>; + +fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, + to_mutbl: hir::Mutability) + -> RelateResult<'tcx, ()> { + match (from_mutbl, to_mutbl) { + (hir::MutMutable, hir::MutMutable) | + (hir::MutImmutable, hir::MutImmutable) | + (hir::MutMutable, hir::MutImmutable) => Ok(()), + (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability) + } +} impl<'f, 'tcx> Coerce<'f, 'tcx> { + fn new(fcx: &'f FnCtxt<'f, 'tcx>, origin: TypeOrigin) -> Self { + Coerce { + fcx: fcx, + origin: origin, + use_lub: false, + unsizing_obligations: RefCell::new(vec![]) + } + } + fn tcx(&self) -> &TyCtxt<'tcx> { self.fcx.tcx() } - fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b)); - Ok(None) // No coercion required. + /// Unify two types (using sub or lub) and produce a noop coercion. + fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { + let infcx = self.fcx.infcx(); + infcx.commit_if_ok(|_| { + let trace = TypeTrace::types(self.origin, false, a, b); + if self.use_lub { + infcx.lub(false, trace).relate(&a, &b) + } else { + infcx.sub(false, trace).relate(&a, &b) + } + }).and_then(|ty| self.identity(ty)) } - fn unpack_actual_value(&self, a: Ty<'tcx>, f: F) -> T where - F: FnOnce(Ty<'tcx>) -> T, - { - f(self.fcx.infcx().shallow_resolve(a)) + /// Synthesize an identity adjustment. + fn identity(&self, ty: Ty<'tcx>) -> CoerceResult<'tcx> { + Ok((ty, AdjustDerefRef(AutoDerefRef { + autoderefs: 0, + autoref: None, + unsize: None + }))) } - fn coerce(&self, - expr_a: &hir::Expr, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> CoerceResult<'tcx> { - debug!("Coerce.tys({:?} => {:?})", - a, - b); + fn coerce<'a, E, I>(&self, + exprs: &E, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> CoerceResult<'tcx> + // FIXME(eddyb) use copyable iterators when that becomes ergonomic. + where E: Fn() -> I, + I: IntoIterator { let a = self.fcx.infcx().shallow_resolve(a); + debug!("Coerce.tys({:?} => {:?})", a, b); // Just ignore error types. if a.references_error() || b.references_error() { - return Ok(None); + return self.identity(b); } // Consider coercing the subtype to a DST @@ -134,27 +167,27 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } ty::TyRef(_, mt_b) => { - return self.coerce_borrowed_pointer(expr_a, a, b, mt_b.mutbl); + return self.coerce_borrowed_pointer(exprs, a, b, mt_b.mutbl); } _ => {} } match a.sty { - ty::TyBareFn(Some(_), a_f) => { + ty::TyFnDef(_, _, a_f) => { // Function items are coercible to any closure // type; function pointers are not (that would // require double indirection). self.coerce_from_fn_item(a, a_f, b) } - ty::TyBareFn(None, a_f) => { + ty::TyFnPtr(a_f) => { // We permit coercion of fn pointers to drop the // unsafe qualifier. self.coerce_from_fn_pointer(a, a_f, b) } _ => { - // Otherwise, just use subtyping rules. - self.subtype(a, b) + // Otherwise, just use unification rules. + self.unify(a, b) } } } @@ -162,15 +195,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`. /// To match `A` with `B`, autoderef will be performed, /// calling `deref`/`deref_mut` where necessary. - fn coerce_borrowed_pointer(&self, - expr_a: &hir::Expr, - a: Ty<'tcx>, - b: Ty<'tcx>, - mutbl_b: hir::Mutability) - -> CoerceResult<'tcx> { - debug!("coerce_borrowed_pointer(a={:?}, b={:?})", - a, - b); + fn coerce_borrowed_pointer<'a, E, I>(&self, + exprs: &E, + a: Ty<'tcx>, + b: Ty<'tcx>, + mutbl_b: hir::Mutability) + -> CoerceResult<'tcx> + // FIXME(eddyb) use copyable iterators when that becomes ergonomic. + where E: Fn() -> I, + I: IntoIterator { + + debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); // If we have a parameter of type `&M T_a` and the value // provided is `expr`, we will be adding an implicit borrow, @@ -182,20 +217,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::TyRef(_, mt_a) => { try!(coerce_mutbls(mt_a.mutbl, mutbl_b)); } - _ => return self.subtype(a, b) + _ => return self.unify(a, b) } - let coercion = Coercion(self.origin.span()); + let span = self.origin.span(); + let coercion = Coercion(span); let r_borrow = self.fcx.infcx().next_region_var(coercion); let r_borrow = self.tcx().mk_region(r_borrow); let autoref = Some(AutoPtr(r_borrow, mutbl_b)); let lvalue_pref = LvaluePreference::from_mutbl(mutbl_b); let mut first_error = None; - let (_, autoderefs, success) = autoderef(self.fcx, - expr_a.span, - a, - Some(expr_a), + let (_, autoderefs, success) = autoderef(self.fcx, span, a, exprs, UnresolvedTypeAction::Ignore, lvalue_pref, |inner_ty, autoderef| { @@ -206,19 +239,20 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } let ty = self.tcx().mk_ref(r_borrow, TypeAndMut {ty: inner_ty, mutbl: mutbl_b}); - if let Err(err) = self.subtype(ty, b) { - if first_error.is_none() { - first_error = Some(err); + match self.unify(ty, b) { + Err(err) => { + if first_error.is_none() { + first_error = Some(err); + } + None } - None - } else { - Some(()) + Ok((ty, _)) => Some(ty) } }); match success { - Some(_) => { - Ok(Some(AdjustDerefRef(AutoDerefRef { + Some(ty) => { + Ok((ty, AdjustDerefRef(AutoDerefRef { autoderefs: autoderefs, autoref: autoref, unsize: None @@ -329,9 +363,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } } - let mut obligations = self.unsizing_obligations.borrow_mut(); - assert!(obligations.is_empty()); - *obligations = leftover_predicates; + *self.unsizing_obligations.borrow_mut() = leftover_predicates; let adjustment = AutoDerefRef { autoderefs: if reborrow.is_some() { 1 } else { 0 }, @@ -339,7 +371,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { unsize: Some(target) }; debug!("Success, coerced with {:?}", adjustment); - Ok(Some(AdjustDerefRef(adjustment))) + Ok((target, AdjustDerefRef(adjustment))) } fn coerce_from_fn_pointer(&self, @@ -353,22 +385,21 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { * into a closure or a `proc`. */ - self.unpack_actual_value(b, |b| { - debug!("coerce_from_fn_pointer(a={:?}, b={:?})", - a, b); + let b = self.fcx.infcx().shallow_resolve(b); + debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b); - if let ty::TyBareFn(None, fn_ty_b) = b.sty { - match (fn_ty_a.unsafety, fn_ty_b.unsafety) { - (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { - let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a); - try!(self.subtype(unsafe_a, b)); - return Ok(Some(AdjustUnsafeFnPointer)); - } - _ => {} + if let ty::TyFnPtr(fn_ty_b) = b.sty { + match (fn_ty_a.unsafety, fn_ty_b.unsafety) { + (hir::Unsafety::Normal, hir::Unsafety::Unsafe) => { + let unsafe_a = self.tcx().safe_to_unsafe_fn_ty(fn_ty_a); + return self.unify(unsafe_a, b).map(|(ty, _)| { + (ty, AdjustUnsafeFnPointer) + }); } + _ => {} } - self.subtype(a, b) - }) + } + self.unify(a, b) } fn coerce_from_fn_item(&self, @@ -381,19 +412,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { * into a closure or a `proc`. */ - self.unpack_actual_value(b, |b| { - debug!("coerce_from_fn_item(a={:?}, b={:?})", - a, b); + let b = self.fcx.infcx().shallow_resolve(b); + debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); - match b.sty { - ty::TyBareFn(None, _) => { - let a_fn_pointer = self.tcx().mk_fn(None, fn_ty_a); - try!(self.subtype(a_fn_pointer, b)); - Ok(Some(AdjustReifyFnPointer)) - } - _ => self.subtype(a, b) + match b.sty { + ty::TyFnPtr(_) => { + let a_fn_pointer = self.tcx().mk_ty(ty::TyFnPtr(fn_ty_a)); + self.unify(a_fn_pointer, b).map(|(ty, _)| { + (ty, AdjustReifyFnPointer) + }) } - }) + _ => self.unify(a, b) + } } fn coerce_unsafe_ptr(&self, @@ -409,74 +439,192 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::TyRef(_, mt) => (true, mt), ty::TyRawPtr(mt) => (false, mt), _ => { - return self.subtype(a, b); + return self.unify(a, b); } }; // Check that the types which they point at are compatible. let a_unsafe = self.tcx().mk_ptr(ty::TypeAndMut{ mutbl: mutbl_b, ty: mt_a.ty }); - try!(self.subtype(a_unsafe, b)); + let (ty, noop) = try!(self.unify(a_unsafe, b)); try!(coerce_mutbls(mt_a.mutbl, mutbl_b)); // Although references and unsafe ptrs have the same // representation, we still register an AutoDerefRef so that // regionck knows that the region for `a` must be valid here. - if is_ref { - Ok(Some(AdjustDerefRef(AutoDerefRef { + Ok((ty, if is_ref { + AdjustDerefRef(AutoDerefRef { autoderefs: 1, autoref: Some(AutoUnsafe(mutbl_b)), unsize: None - }))) + }) } else if mt_a.mutbl != mutbl_b { - Ok(Some(AdjustMutToConstPointer)) + AdjustMutToConstPointer } else { - Ok(None) - } + noop + })) } } -pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &hir::Expr, +fn apply<'a, 'b, 'tcx, E, I>(coerce: &mut Coerce<'a, 'tcx>, + exprs: &E, a: Ty<'tcx>, b: Ty<'tcx>) - -> RelateResult<'tcx, ()> { - debug!("mk_assignty({:?} -> {:?})", a, b); - let mut unsizing_obligations = vec![]; - let adjustment = try!(indent(|| { - fcx.infcx().commit_if_ok(|_| { - let coerce = Coerce { - fcx: fcx, - origin: TypeOrigin::ExprAssignable(expr.span), - unsizing_obligations: RefCell::new(vec![]) - }; - let adjustment = try!(coerce.coerce(expr, a, b)); - unsizing_obligations = coerce.unsizing_obligations.into_inner(); - Ok(adjustment) - }) - })); + -> CoerceResult<'tcx> + where E: Fn() -> I, + I: IntoIterator { - if let Some(AdjustDerefRef(auto)) = adjustment { + let (ty, adjustment) = try!(indent(|| coerce.coerce(exprs, a, b))); + + let fcx = coerce.fcx; + if let AdjustDerefRef(auto) = adjustment { if auto.unsize.is_some() { - for obligation in unsizing_obligations { + let mut obligations = coerce.unsizing_obligations.borrow_mut(); + for obligation in obligations.drain(..) { fcx.register_predicate(obligation); } } } - if let Some(adjustment) = adjustment { - debug!("Success, coerced with {:?}", adjustment); - fcx.write_adjustment(expr.id, adjustment); - } - Ok(()) + Ok((ty, adjustment)) } -fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability, - to_mutbl: hir::Mutability) - -> CoerceResult<'tcx> { - match (from_mutbl, to_mutbl) { - (hir::MutMutable, hir::MutMutable) | - (hir::MutImmutable, hir::MutImmutable) | - (hir::MutMutable, hir::MutImmutable) => Ok(None), - (hir::MutImmutable, hir::MutMutable) => Err(TypeError::Mutability) +/// Attempt to coerce an expression to a type, and return the +/// adjusted type of the expression, if successful. +/// Adjustments are only recorded if the coercion succeeded. +/// The expressions *must not* have any pre-existing adjustments. +pub fn try<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + expr: &hir::Expr, + target: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> { + let source = fcx.resolve_type_vars_if_possible(fcx.expr_ty(expr)); + debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target); + + let mut coerce = Coerce::new(fcx, TypeOrigin::ExprAssignable(expr.span)); + fcx.infcx().commit_if_ok(|_| { + let (ty, adjustment) = + try!(apply(&mut coerce, &|| Some(expr), source, target)); + if !adjustment.is_identity() { + debug!("Success, coerced with {:?}", adjustment); + assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id)); + fcx.write_adjustment(expr.id, adjustment); + } + Ok(ty) + }) +} + +/// Given some expressions, their known unified type and another expression, +/// tries to unify the types, potentially inserting coercions on any of the +/// provided expressions and returns their LUB (aka "common supertype"). +pub fn try_find_lub<'a, 'b, 'tcx, E, I>(fcx: &FnCtxt<'a, 'tcx>, + origin: TypeOrigin, + exprs: E, + prev_ty: Ty<'tcx>, + new: &'b hir::Expr) + -> RelateResult<'tcx, Ty<'tcx>> + // FIXME(eddyb) use copyable iterators when that becomes ergonomic. + where E: Fn() -> I, + I: IntoIterator { + + let prev_ty = fcx.resolve_type_vars_if_possible(prev_ty); + let new_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(new)); + debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty); + + let trace = TypeTrace::types(origin, true, prev_ty, new_ty); + let mut lub = fcx.infcx().lub(true, trace); + + // Special-case that coercion alone cannot handle: + // Two function item types of differing IDs or Substs. + match (&prev_ty.sty, &new_ty.sty) { + (&ty::TyFnDef(a_def_id, a_substs, a_fty), + &ty::TyFnDef(b_def_id, b_substs, b_fty)) => { + // The signature must always match. + let fty = try!(lub.relate(a_fty, b_fty)); + + if a_def_id == b_def_id { + // Same function, maybe the parameters match. + let substs = fcx.infcx().commit_if_ok(|_| { + relate_substs(&mut lub, None, a_substs, b_substs) + }).map(|s| fcx.tcx().mk_substs(s)); + + if let Ok(substs) = substs { + // We have a LUB of prev_ty and new_ty, just return it. + return Ok(fcx.tcx().mk_fn_def(a_def_id, substs, fty)); + } + } + + // Reify both sides and return the reified fn pointer type. + for expr in exprs().into_iter().chain(Some(new)) { + // No adjustments can produce a fn item, so this should never trip. + assert!(!fcx.inh.tables.borrow().adjustments.contains_key(&expr.id)); + fcx.write_adjustment(expr.id, AdjustReifyFnPointer); + } + return Ok(fcx.tcx().mk_fn_ptr(fty)); + } + _ => {} + } + + let mut coerce = Coerce::new(fcx, origin); + coerce.use_lub = true; + + // First try to coerce the new expression to the type of the previous ones, + // but only if the new expression has no coercion already applied to it. + let mut first_error = None; + if !fcx.inh.tables.borrow().adjustments.contains_key(&new.id) { + let result = fcx.infcx().commit_if_ok(|_| { + apply(&mut coerce, &|| Some(new), new_ty, prev_ty) + }); + match result { + Ok((ty, adjustment)) => { + if !adjustment.is_identity() { + fcx.write_adjustment(new.id, adjustment); + } + return Ok(ty); + } + Err(e) => first_error = Some(e) + } + } + + // Then try to coerce the previous expressions to the type of the new one. + // This requires ensuring there are no coercions applied to *any* of the + // previous expressions, other than noop reborrows (ignoring lifetimes). + for expr in exprs() { + let noop = match fcx.inh.tables.borrow().adjustments.get(&expr.id) { + Some(&AdjustDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(AutoPtr(_, mutbl_adj)), + unsize: None + })) => match fcx.expr_ty(expr).sty { + ty::TyRef(_, mt_orig) => { + // Reborrow that we can safely ignore. + mutbl_adj == mt_orig.mutbl + } + _ => false + }, + Some(_) => false, + None => true + }; + + if !noop { + return fcx.infcx().commit_if_ok(|_| lub.relate(&prev_ty, &new_ty)); + } + } + + match fcx.infcx().commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) { + Err(_) => { + // Avoid giving strange errors on failed attempts. + if let Some(e) = first_error { + Err(e) + } else { + fcx.infcx().commit_if_ok(|_| lub.relate(&prev_ty, &new_ty)) + } + } + Ok((ty, adjustment)) => { + if !adjustment.is_identity() { + for expr in exprs() { + fcx.write_adjustment(expr.id, adjustment); + } + } + Ok(ty) + } } } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 2bf7d65e33147..ff7b809577f64 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -276,9 +276,9 @@ pub fn compare_impl_method<'tcx>(tcx: &TyCtxt<'tcx>, // type. // Compute skolemized form of impl and trait method tys. - let impl_fty = tcx.mk_fn(None, tcx.mk_bare_fn(impl_m.fty.clone())); + let impl_fty = tcx.mk_fn_ptr(impl_m.fty.clone()); let impl_fty = impl_fty.subst(tcx, impl_to_skol_substs); - let trait_fty = tcx.mk_fn(None, tcx.mk_bare_fn(trait_m.fty.clone())); + let trait_fty = tcx.mk_fn_ptr(trait_m.fty.clone()); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); let err = infcx.commit_if_ok(|snapshot| { @@ -296,11 +296,11 @@ pub fn compare_impl_method<'tcx>(tcx: &TyCtxt<'tcx>, impl_m_span, impl_m_body_id, &impl_sig); - let impl_fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + let impl_fty = tcx.mk_fn_ptr(ty::BareFnTy { unsafety: impl_m.fty.unsafety, abi: impl_m.fty.abi, sig: ty::Binder(impl_sig) - })); + }); debug!("compare_impl_method: impl_fty={:?}", impl_fty); @@ -314,11 +314,11 @@ pub fn compare_impl_method<'tcx>(tcx: &TyCtxt<'tcx>, impl_m_span, impl_m_body_id, &trait_sig); - let trait_fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + let trait_fty = tcx.mk_fn_ptr(ty::BareFnTy { unsafety: trait_m.fty.unsafety, abi: trait_m.fty.abi, sig: ty::Binder(trait_sig) - })); + }); debug!("compare_impl_method: trait_fty={:?}", trait_fty); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 63dac49b384a7..1f61198bef921 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -10,45 +10,27 @@ use check::{coercion, FnCtxt}; -use middle::ty::{self, Ty}; -use middle::infer::{self, TypeOrigin}; +use middle::ty::Ty; +use middle::infer::TypeOrigin; -use std::result::Result::{Err, Ok}; use syntax::codemap::Span; use rustc_front::hir; // Requires that the two types unify, and prints an error message if // they don't. pub fn suptype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, - ty_expected: Ty<'tcx>, ty_actual: Ty<'tcx>) { - suptype_with_fn(fcx, sp, false, ty_expected, ty_actual, - |sp, e, a, s| { fcx.report_mismatched_types(sp, e, a, s) }) -} - -/// As `suptype`, but call `handle_err` if unification for subtyping fails. -pub fn suptype_with_fn<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, - sp: Span, - b_is_expected: bool, - ty_a: Ty<'tcx>, - ty_b: Ty<'tcx>, - handle_err: F) where - F: FnOnce(Span, Ty<'tcx>, Ty<'tcx>, &ty::error::TypeError<'tcx>), -{ - // n.b.: order of actual, expected is reversed - match infer::mk_subty(fcx.infcx(), b_is_expected, TypeOrigin::Misc(sp), - ty_b, ty_a) { - Ok(()) => { /* ok */ } - Err(ref err) => { - handle_err(sp, ty_a, ty_b, err); - } + expected: Ty<'tcx>, actual: Ty<'tcx>) { + let origin = TypeOrigin::Misc(sp); + if let Err(e) = fcx.infcx().sub_types(false, origin, actual, expected) { + fcx.infcx().report_mismatched_types(origin, expected, actual, e); } } pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { - match infer::mk_eqty(fcx.infcx(), false, TypeOrigin::Misc(sp), actual, expected) { - Ok(()) => { /* ok */ } - Err(ref err) => { fcx.report_mismatched_types(sp, expected, actual, err); } + let origin = TypeOrigin::Misc(sp); + if let Err(e) = fcx.infcx().eq_types(false, origin, actual, expected) { + fcx.infcx().report_mismatched_types(origin, expected, actual, e); } } @@ -57,16 +39,10 @@ pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span, expected: Ty<'tcx>, expr: &hir::Expr) { - let expr_ty = fcx.expr_ty(expr); - debug!("demand::coerce(expected = {:?}, expr_ty = {:?})", - expected, - expr_ty); - let expr_ty = fcx.resolve_type_vars_if_possible(expr_ty); let expected = fcx.resolve_type_vars_if_possible(expected); - match coercion::mk_assignty(fcx, expr, expr_ty, expected) { - Ok(()) => { /* ok */ } - Err(ref err) => { - fcx.report_mismatched_types(sp, expected, expr_ty, err); - } + if let Err(e) = coercion::try(fcx, expr, expected) { + let origin = TypeOrigin::Misc(sp); + let expr_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(expr)); + fcx.infcx().report_mismatched_types(origin, expected, expr_ty, e); } } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 78faef473ddf6..4ebe4c25dd1d3 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -479,7 +479,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( Ok(()) } - ty::TyBareFn(..) => { + ty::TyFnDef(..) | ty::TyFnPtr(_) => { // FIXME(#26656): this type is always destruction-safe, but // it implicitly witnesses Self: Fn, which can be false. Ok(()) diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 6d8fff3caca2c..a05329bc4a402 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -13,7 +13,7 @@ use astconv::AstConv; use intrinsics; -use middle::subst; +use middle::subst::{self, Substs}; use middle::ty::FnSig; use middle::ty::{self, Ty, TyCtxt}; use middle::ty::fold::TypeFolder; @@ -33,7 +33,13 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: &TyCtxt<'tcx>, it: &hir::ForeignItem, abi: Abi, inputs: Vec>, output: ty::FnOutput<'tcx>) { - let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + let def_id = tcx.map.local_def_id(it.id); + let i_ty = tcx.lookup_item_type(def_id); + + let mut substs = Substs::empty(); + substs.types = i_ty.generics.types.map(|def| tcx.mk_param_from_def(def)); + + let fty = tcx.mk_fn_def(def_id, tcx.mk_substs(substs), ty::BareFnTy { unsafety: hir::Unsafety::Unsafe, abi: abi, sig: ty::Binder(FnSig { @@ -41,8 +47,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: &TyCtxt<'tcx>, it: &hir::ForeignItem, output: output, variadic: false, }), - })); - let i_ty = tcx.lookup_item_type(tcx.map.local_def_id(it.id)); + }); let i_n_tps = i_ty.generics.types.len(subst::FnSpace); if i_n_tps != n_tps { span_err!(tcx.sess, it.span, E0094, @@ -296,8 +301,7 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { variadic: false, }), }; - let fn_ty = tcx.mk_bare_fn(fn_ty); - (0, vec![tcx.mk_fn(None, fn_ty), mut_u8, mut_u8], tcx.types.i32) + (0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32) } ref other => { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index f2f2eb664444f..f4268deee37c5 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -98,27 +98,29 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let InstantiatedMethodSig { method_sig, all_substs, method_predicates } = self.instantiate_method_sig(&pick, all_substs); + let all_substs = self.tcx().mk_substs(all_substs); let method_self_ty = method_sig.inputs[0]; // Unify the (adjusted) self type with what the method expects. self.unify_receivers(self_ty, method_self_ty); // Create the method type + let def_id = pick.item.def_id(); let method_ty = pick.item.as_opt_method().unwrap(); - let fty = self.tcx().mk_fn(None, self.tcx().mk_bare_fn(ty::BareFnTy { + let fty = self.tcx().mk_fn_def(def_id, all_substs, ty::BareFnTy { sig: ty::Binder(method_sig), unsafety: method_ty.fty.unsafety, abi: method_ty.fty.abi.clone(), - })); + }); // Add any trait/regions obligations specified on the method's type parameters. - self.add_obligations(fty, &all_substs, &method_predicates); + self.add_obligations(fty, all_substs, &method_predicates); // Create the final `MethodCallee`. let callee = ty::MethodCallee { - def_id: pick.item.def_id(), + def_id: def_id, ty: fty, - substs: self.tcx().mk_substs(all_substs) + substs: all_substs }; // If this is an `&mut self` method, bias the receiver // expression towards mutability (this will switch @@ -156,7 +158,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let (autoderefd_ty, n, result) = check::autoderef(self.fcx, self.span, unadjusted_self_ty, - Some(self.self_expr), + || Some(self.self_expr), UnresolvedTypeAction::Error, NoPreference, |_, n| { @@ -285,7 +287,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { let (_, _, result) = check::autoderef(self.fcx, self.span, self_ty, - None, + || None, UnresolvedTypeAction::Error, NoPreference, |ty, _| { @@ -457,7 +459,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { fn fixup_derefs_on_method_receiver_if_necessary(&self, method_callee: &ty::MethodCallee) { let sig = match method_callee.ty.sty { - ty::TyBareFn(_, ref f) => f.sig.clone(), + ty::TyFnDef(_, _, ref f) => f.sig.clone(), _ => return, }; @@ -507,7 +509,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { check::autoderef(self.fcx, expr.span, self.fcx.expr_ty(expr), - Some(expr), + || Some(expr), UnresolvedTypeAction::Error, PreferMutLvalue, |_, autoderefs| { @@ -520,92 +522,94 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> { } // Don't retry the first one or we might infinite loop! - if i != 0 { - match expr.node { - hir::ExprIndex(ref base_expr, ref index_expr) => { - // If this is an overloaded index, the - // adjustment will include an extra layer of - // autoref because the method is an &self/&mut - // self method. We have to peel it off to get - // the raw adjustment that `try_index_step` - // expects. This is annoying and horrible. We - // ought to recode this routine so it doesn't - // (ab)use the normal type checking paths. - let adj = self.fcx.inh.tables.borrow().adjustments.get(&base_expr.id) - .cloned(); - let (autoderefs, unsize) = match adj { - Some(AdjustDerefRef(adr)) => match adr.autoref { - None => { - assert!(adr.unsize.is_none()); - (adr.autoderefs, None) - } - Some(AutoPtr(_, _)) => { - (adr.autoderefs, adr.unsize.map(|target| { - target.builtin_deref(false, NoPreference) - .expect("fixup: AutoPtr is not &T").ty - })) - } - Some(_) => { - self.tcx().sess.span_bug( - base_expr.span, - &format!("unexpected adjustment autoref {:?}", - adr)); - } - }, - None => (0, None), + if i == 0 { + continue; + } + match expr.node { + hir::ExprIndex(ref base_expr, ref index_expr) => { + // If this is an overloaded index, the + // adjustment will include an extra layer of + // autoref because the method is an &self/&mut + // self method. We have to peel it off to get + // the raw adjustment that `try_index_step` + // expects. This is annoying and horrible. We + // ought to recode this routine so it doesn't + // (ab)use the normal type checking paths. + let adj = self.fcx.inh.tables.borrow().adjustments.get(&base_expr.id) + .cloned(); + let (autoderefs, unsize) = match adj { + Some(AdjustDerefRef(adr)) => match adr.autoref { + None => { + assert!(adr.unsize.is_none()); + (adr.autoderefs, None) + } + Some(AutoPtr(_, _)) => { + (adr.autoderefs, adr.unsize.map(|target| { + target.builtin_deref(false, NoPreference) + .expect("fixup: AutoPtr is not &T").ty + })) + } Some(_) => { self.tcx().sess.span_bug( base_expr.span, - "unexpected adjustment type"); + &format!("unexpected adjustment autoref {:?}", + adr)); } - }; - - let (adjusted_base_ty, unsize) = if let Some(target) = unsize { - (target, true) - } else { - (self.fcx.adjust_expr_ty(base_expr, - Some(&AdjustDerefRef(AutoDerefRef { - autoderefs: autoderefs, - autoref: None, - unsize: None - }))), false) - }; - let index_expr_ty = self.fcx.expr_ty(&index_expr); - - let result = check::try_index_step( - self.fcx, - ty::MethodCall::expr(expr.id), - expr, - &base_expr, - adjusted_base_ty, - autoderefs, - unsize, - PreferMutLvalue, - index_expr_ty); - - if let Some((input_ty, return_ty)) = result { - demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty); - - let expr_ty = self.fcx.expr_ty(&expr); - demand::suptype(self.fcx, expr.span, expr_ty, return_ty); + }, + None => (0, None), + Some(_) => { + self.tcx().sess.span_bug( + base_expr.span, + "unexpected adjustment type"); } + }; + + let (adjusted_base_ty, unsize) = if let Some(target) = unsize { + (target, true) + } else { + (self.fcx.adjust_expr_ty(base_expr, + Some(&AdjustDerefRef(AutoDerefRef { + autoderefs: autoderefs, + autoref: None, + unsize: None + }))), false) + }; + let index_expr_ty = self.fcx.expr_ty(&index_expr); + + let result = check::try_index_step( + self.fcx, + ty::MethodCall::expr(expr.id), + expr, + &base_expr, + adjusted_base_ty, + autoderefs, + unsize, + PreferMutLvalue, + index_expr_ty); + + if let Some((input_ty, return_ty)) = result { + demand::suptype(self.fcx, index_expr.span, input_ty, index_expr_ty); + + let expr_ty = self.fcx.expr_ty(&expr); + demand::suptype(self.fcx, expr.span, expr_ty, return_ty); } - hir::ExprUnary(hir::UnDeref, ref base_expr) => { - // if this is an overloaded deref, then re-evaluate with - // a preference for mut - let method_call = ty::MethodCall::expr(expr.id); - if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) { - check::try_overloaded_deref( - self.fcx, - expr.span, - Some(method_call), - Some(&base_expr), - self.fcx.expr_ty(&base_expr), - PreferMutLvalue); - } + } + hir::ExprUnary(hir::UnDeref, ref base_expr) => { + // if this is an overloaded deref, then re-evaluate with + // a preference for mut + let method_call = ty::MethodCall::expr(expr.id); + if self.fcx.inh.tables.borrow().method_map.contains_key(&method_call) { + let method = check::try_overloaded_deref( + self.fcx, + expr.span, + Some(&base_expr), + self.fcx.expr_ty(&base_expr), + PreferMutLvalue); + let method = method.expect("re-trying deref failed"); + self.fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); } - _ => {} } + _ => {} } } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index fce4468341305..e74623eda6d42 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -230,11 +230,12 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, &method_ty.fty.sig).0; let fn_sig = fcx.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); let transformed_self_ty = fn_sig.inputs[0]; - let fty = tcx.mk_fn(None, tcx.mk_bare_fn(ty::BareFnTy { + let def_id = method_item.def_id(); + let fty = tcx.mk_fn_def(def_id, trait_ref.substs, ty::BareFnTy { sig: ty::Binder(fn_sig), unsafety: method_ty.fty.unsafety, abi: method_ty.fty.abi.clone(), - })); + }); debug!("lookup_in_trait_adjusted: matched method fty={:?} obligation={:?}", fty, @@ -318,7 +319,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } let callee = ty::MethodCallee { - def_id: method_item.def_id(), + def_id: def_id, ty: fty, substs: trait_ref.substs }; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 4a8a893cc4696..d11a07cb41ff7 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -200,7 +200,7 @@ fn create_steps<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let (final_ty, dereferences, _) = check::autoderef(fcx, span, self_ty, - None, + || None, UnresolvedTypeAction::Error, NoPreference, |t, d| { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index e7d84efdaa2f7..7dc9d46c303f0 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -101,7 +101,7 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, match field_ty.sty { // Not all of these (e.g. unsafe fns) implement FnOnce // so we look for these beforehand - ty::TyClosure(..) | ty::TyBareFn(..) => { + ty::TyClosure(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => { span_stored_function!(); } // If it's not a simple function, look for things which implement FnOnce @@ -351,7 +351,7 @@ fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, return is_local(fcx.resolve_type_vars_if_possible(rcvr_ty)); } - check::autoderef(fcx, span, rcvr_ty, None, + check::autoderef(fcx, span, rcvr_ty, || None, check::UnresolvedTypeAction::Ignore, ty::NoPreference, |ty, _| { if is_local(ty) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index eee3d23283107..0743c0b9e187b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -89,7 +89,7 @@ use middle::cstore::LOCAL_CRATE; use middle::def::{self, Def}; use middle::def_id::DefId; use middle::infer; -use middle::infer::{TypeOrigin, type_variable}; +use middle::infer::{TypeOrigin, TypeTrace, type_variable}; use middle::pat_util::{self, pat_id_map}; use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace}; use middle::traits::{self, report_fulfillment_errors}; @@ -101,6 +101,7 @@ use middle::ty::{MethodCall, MethodCallee}; use middle::ty::adjustment; use middle::ty::error::TypeError; use middle::ty::fold::{TypeFolder, TypeFoldable}; +use middle::ty::relate::TypeRelation; use middle::ty::util::Representability; use require_c_abi_if_variadic; use rscope::{ElisionFailureInfo, RegionScope}; @@ -434,7 +435,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, param_env: ty::ParameterEnvironment<'a, 'tcx>) { match raw_fty.sty { - ty::TyBareFn(_, ref fn_ty) => { + ty::TyFnDef(_, _, ref fn_ty) => { let tables = RefCell::new(ty::Tables::empty()); let inh = Inherited::new(ccx.tcx, &tables, param_env); @@ -1622,14 +1623,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.infcx().type_error_struct(sp, mk_msg, actual_ty, err) } - pub fn report_mismatched_types(&self, - sp: Span, - e: Ty<'tcx>, - a: Ty<'tcx>, - err: &TypeError<'tcx>) { - self.infcx().report_mismatched_types(sp, e, a, err) - } - /// Registers an obligation for checking later, during regionck, that the type `ty` must /// outlive the region `r`. pub fn register_region_obligation(&self, @@ -1709,6 +1702,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // FIXME(arielb1): use this instead of field.ty everywhere + // Only for fields! Returns for methods> + // Indifferent to privacy flags pub fn field_ty(&self, span: Span, field: ty::FieldDef<'tcx>, @@ -1719,8 +1714,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &field.ty(self.tcx(), substs)) } - // Only for fields! Returns for methods> - // Indifferent to privacy flags fn check_casts(&self) { let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut(); for cast in deferred_cast_checks.drain(..) { @@ -2061,20 +2054,21 @@ pub enum UnresolvedTypeAction { /// /// Note: this method does not modify the adjustments table. The caller is responsible for /// inserting an AutoAdjustment record into the `fcx` using one of the suitable methods. -pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, - sp: Span, - base_ty: Ty<'tcx>, - opt_expr: Option<&hir::Expr>, - unresolved_type_action: UnresolvedTypeAction, - mut lvalue_pref: LvaluePreference, - mut should_stop: F) - -> (Ty<'tcx>, usize, Option) - where F: FnMut(Ty<'tcx>, usize) -> Option, +pub fn autoderef<'a, 'b, 'tcx, E, I, T, F>(fcx: &FnCtxt<'a, 'tcx>, + sp: Span, + base_ty: Ty<'tcx>, + maybe_exprs: E, + unresolved_type_action: UnresolvedTypeAction, + mut lvalue_pref: LvaluePreference, + mut should_stop: F) + -> (Ty<'tcx>, usize, Option) + // FIXME(eddyb) use copyable iterators when that becomes ergonomic. + where E: Fn() -> I, + I: IntoIterator, + F: FnMut(Ty<'tcx>, usize) -> Option, { - debug!("autoderef(base_ty={:?}, opt_expr={:?}, lvalue_pref={:?})", - base_ty, - opt_expr, - lvalue_pref); + debug!("autoderef(base_ty={:?}, lvalue_pref={:?})", + base_ty, lvalue_pref); let mut t = base_ty; for autoderefs in 0..fcx.tcx().sess.recursion_limit.get() { @@ -2087,7 +2081,7 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, // (i.e. it is an inference variable) because `Ty::builtin_deref` // and `try_overloaded_deref` both simply return `None` // in such a case without producing spurious errors. - fcx.resolve_type_vars_if_possible(t) + fcx.infcx().resolve_type_vars_if_possible(&t) } }; if resolved_t.references_error() { @@ -2100,34 +2094,34 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, } // Otherwise, deref if type is derefable: - let mt = match resolved_t.builtin_deref(false, lvalue_pref) { - Some(mt) => Some(mt), - None => { - let method_call = - opt_expr.map(|expr| MethodCall::autoderef(expr.id, autoderefs as u32)); - - // Super subtle: it might seem as though we should - // pass `opt_expr` to `try_overloaded_deref`, so that - // the (implicit) autoref of using an overloaded deref - // would get added to the adjustment table. However we - // do not do that, because it's kind of a - // "meta-adjustment" -- instead, we just leave it - // unrecorded and know that there "will be" an - // autoref. regionck and other bits of the code base, - // when they encounter an overloaded autoderef, have - // to do some reconstructive surgery. This is a pretty - // complex mess that is begging for a proper MIR. - try_overloaded_deref(fcx, sp, method_call, None, resolved_t, lvalue_pref) + + // Super subtle: it might seem as though we should + // pass `opt_expr` to `try_overloaded_deref`, so that + // the (implicit) autoref of using an overloaded deref + // would get added to the adjustment table. However we + // do not do that, because it's kind of a + // "meta-adjustment" -- instead, we just leave it + // unrecorded and know that there "will be" an + // autoref. regionck and other bits of the code base, + // when they encounter an overloaded autoderef, have + // to do some reconstructive surgery. This is a pretty + // complex mess that is begging for a proper MIR. + let mt = if let Some(mt) = resolved_t.builtin_deref(false, lvalue_pref) { + mt + } else if let Some(method) = try_overloaded_deref(fcx, sp, None, + resolved_t, lvalue_pref) { + for expr in maybe_exprs() { + let method_call = MethodCall::autoderef(expr.id, autoderefs as u32); + fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); } + make_overloaded_lvalue_return_type(fcx.tcx(), method) + } else { + return (resolved_t, autoderefs, None); }; - match mt { - Some(mt) => { - t = mt.ty; - if mt.mutbl == hir::MutImmutable { - lvalue_pref = NoPreference; - } - } - None => return (resolved_t, autoderefs, None) + + t = mt.ty; + if mt.mutbl == hir::MutImmutable { + lvalue_pref = NoPreference; } } @@ -2140,11 +2134,10 @@ pub fn autoderef<'a, 'tcx, T, F>(fcx: &FnCtxt<'a, 'tcx>, fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, span: Span, - method_call: Option, base_expr: Option<&hir::Expr>, base_ty: Ty<'tcx>, lvalue_pref: LvaluePreference) - -> Option> + -> Option> { // Try DerefMut first, if preferred. let method = match (lvalue_pref, fcx.tcx().lang_items.deref_mut_trait()) { @@ -2166,33 +2159,23 @@ fn try_overloaded_deref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, (method, _) => method }; - make_overloaded_lvalue_return_type(fcx, method_call, method) + method } /// For the overloaded lvalue expressions (`*x`, `x[3]`), the trait returns a type of `&T`, but the /// actual type we assign to the *expression* is `T`. So this function just peels off the return -/// type by one layer to yield `T`. It also inserts the `method-callee` into the method map. -fn make_overloaded_lvalue_return_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - method_call: Option, - method: Option>) - -> Option> +/// type by one layer to yield `T`. +fn make_overloaded_lvalue_return_type<'tcx>(tcx: &TyCtxt<'tcx>, + method: MethodCallee<'tcx>) + -> ty::TypeAndMut<'tcx> { - match method { - Some(method) => { - // extract method return type, which will be &T; - // all LB regions should have been instantiated during method lookup - let ret_ty = method.ty.fn_ret(); - let ret_ty = fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap(); - - if let Some(method_call) = method_call { - fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); - } + // extract method return type, which will be &T; + // all LB regions should have been instantiated during method lookup + let ret_ty = method.ty.fn_ret(); + let ret_ty = tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap(); - // method returns &T, but the type as visible to user is T, so deref - ret_ty.builtin_deref(true, NoPreference) - } - None => None, - } + // method returns &T, but the type as visible to user is T, so deref + ret_ty.builtin_deref(true, NoPreference).unwrap() } fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, @@ -2210,7 +2193,7 @@ fn lookup_indexing<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, let (ty, autoderefs, final_mt) = autoderef(fcx, base_expr.span, base_ty, - Some(base_expr), + || Some(base_expr), UnresolvedTypeAction::Error, lvalue_pref, |adj_ty, idx| { @@ -2307,10 +2290,10 @@ fn try_index_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, // If some lookup succeeds, write callee into table and extract index/element // type from the method signature. // If some lookup succeeded, install method in table - method.and_then(|method| { + method.map(|method| { debug!("try_index_step: success, using overloaded indexing"); - make_overloaded_lvalue_return_type(fcx, Some(method_call), Some(method)). - map(|ret| (input_ty, ret.ty)) + fcx.inh.tables.borrow_mut().method_map.insert(method_call, method); + (input_ty, make_overloaded_lvalue_return_type(fcx.tcx(), method).ty) }) } @@ -2340,7 +2323,7 @@ fn check_method_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ty::FnConverging(fcx.tcx().types.err) } else { match method_fn_ty.sty { - ty::TyBareFn(_, ref fty) => { + ty::TyFnDef(_, _, ref fty) => { // HACK(eddyb) ignore self in the definition (see above). let expected_arg_tys = expected_types_for_fn_args(fcx, sp, @@ -2509,20 +2492,17 @@ fn check_argument_types<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, Expectation::rvalue_hint(fcx.tcx(), ty) }); - check_expr_with_unifier(fcx, - &arg, - expected.unwrap_or(ExpectHasType(formal_ty)), - NoPreference, || { - // 2. Coerce to the most detailed type that could be coerced - // to, which is `expected_ty` if `rvalue_hint` returns an - // `ExprHasType(expected_ty)`, or the `formal_ty` otherwise. - let coerce_ty = expected.and_then(|e| e.only_has_type(fcx)); - demand::coerce(fcx, arg.span, coerce_ty.unwrap_or(formal_ty), &arg); - - // 3. Relate the expected type and the formal one, - // if the expected type was used for the coercion. - coerce_ty.map(|ty| demand::suptype(fcx, arg.span, formal_ty, ty)); - }); + check_expr_with_expectation(fcx, &arg, + expected.unwrap_or(ExpectHasType(formal_ty))); + // 2. Coerce to the most detailed type that could be coerced + // to, which is `expected_ty` if `rvalue_hint` returns an + // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. + let coerce_ty = expected.and_then(|e| e.only_has_type(fcx)); + demand::coerce(fcx, arg.span, coerce_ty.unwrap_or(formal_ty), &arg); + + // 3. Relate the expected type and the formal one, + // if the expected type was used for the coercion. + coerce_ty.map(|ty| demand::suptype(fcx, arg.span, formal_ty, ty)); } if let Some(&arg_ty) = fcx.inh.tables.borrow().node_types.get(&arg.id) { @@ -2619,7 +2599,7 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, ty::TyInt(_) | ty::TyUint(_) => Some(ty), ty::TyChar => Some(tcx.types.u8), ty::TyRawPtr(..) => Some(tcx.types.usize), - ty::TyBareFn(..) => Some(tcx.types.usize), + ty::TyFnDef(..) | ty::TyFnPtr(_) => Some(tcx.types.usize), _ => None } }); @@ -2644,57 +2624,42 @@ fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, fn check_expr_eq_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, expected: Ty<'tcx>) { - check_expr_with_unifier( - fcx, expr, ExpectHasType(expected), NoPreference, - || demand::eqtype(fcx, expr.span, expected, fcx.expr_ty(expr))); + check_expr_with_hint(fcx, expr, expected); + demand::eqtype(fcx, expr.span, expected, fcx.expr_ty(expr)); } pub fn check_expr_has_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, expected: Ty<'tcx>) { - check_expr_with_unifier( - fcx, expr, ExpectHasType(expected), NoPreference, - || demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr))); + check_expr_with_hint(fcx, expr, expected); + demand::suptype(fcx, expr.span, expected, fcx.expr_ty(expr)); } fn check_expr_coercable_to_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, expected: Ty<'tcx>) { - check_expr_with_unifier( - fcx, expr, ExpectHasType(expected), NoPreference, - || demand::coerce(fcx, expr.span, expected, expr)); + check_expr_with_hint(fcx, expr, expected); + demand::coerce(fcx, expr.span, expected, expr); } fn check_expr_with_hint<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, expected: Ty<'tcx>) { - check_expr_with_unifier( - fcx, expr, ExpectHasType(expected), NoPreference, - || ()) + check_expr_with_expectation(fcx, expr, ExpectHasType(expected)) } fn check_expr_with_expectation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr, expected: Expectation<'tcx>) { - check_expr_with_unifier( - fcx, expr, expected, NoPreference, - || ()) -} - -fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - expected: Expectation<'tcx>, - lvalue_pref: LvaluePreference) -{ - check_expr_with_unifier(fcx, expr, expected, lvalue_pref, || ()) + check_expr_with_expectation_and_lvalue_pref(fcx, expr, expected, NoPreference) } fn check_expr<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx hir::Expr) { - check_expr_with_unifier(fcx, expr, NoExpectation, NoPreference, || ()) + check_expr_with_expectation(fcx, expr, NoExpectation) } fn check_expr_with_lvalue_pref<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx hir::Expr, lvalue_pref: LvaluePreference) { - check_expr_with_unifier(fcx, expr, NoExpectation, lvalue_pref, || ()) + check_expr_with_expectation_and_lvalue_pref(fcx, expr, NoExpectation, lvalue_pref) } // determine the `self` type, using fresh variables for all variables @@ -2796,13 +2761,10 @@ fn expected_types_for_fn_args<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, /// Note that inspecting a type's structure *directly* may expose the fact /// that there are actually multiple representations for `TyError`, so avoid /// that when err needs to be handled differently. -fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, - expr: &'tcx hir::Expr, - expected: Expectation<'tcx>, - lvalue_pref: LvaluePreference, - unifier: F) where - F: FnOnce(), -{ +fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, + expr: &'tcx hir::Expr, + expected: Expectation<'tcx>, + lvalue_pref: LvaluePreference) { debug!(">> typechecking: expr={:?} expected={:?}", expr, expected); @@ -2873,30 +2835,52 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, check_block_with_expected(fcx, then_blk, expected); let then_ty = fcx.node_ty(then_blk.id); - let branches_ty = match opt_else_expr { - Some(ref else_expr) => { - check_expr_with_expectation(fcx, &else_expr, expected); - let else_ty = fcx.expr_ty(&else_expr); - infer::common_supertype(fcx.infcx(), - TypeOrigin::IfExpression(sp), - true, - then_ty, - else_ty) - } - None => { - infer::common_supertype(fcx.infcx(), - TypeOrigin::IfExpressionWithNoElse(sp), - false, - then_ty, - fcx.tcx().mk_nil()) - } - }; + let unit = fcx.tcx().mk_nil(); + let (origin, expected, found, result) = + if let Some(else_expr) = opt_else_expr { + check_expr_with_expectation(fcx, else_expr, expected); + let else_ty = fcx.expr_ty(else_expr); + let origin = TypeOrigin::IfExpression(sp); + + // Only try to coerce-unify if we have a then expression + // to assign coercions to, otherwise it's () or diverging. + let result = if let Some(ref then) = then_blk.expr { + let res = coercion::try_find_lub(fcx, origin, || Some(&**then), + then_ty, else_expr); + + // In case we did perform an adjustment, we have to update + // the type of the block, because old trans still uses it. + let adj = fcx.inh.tables.borrow().adjustments.get(&then.id).cloned(); + if res.is_ok() && adj.is_some() { + fcx.write_ty(then_blk.id, fcx.adjust_expr_ty(then, adj.as_ref())); + } - let cond_ty = fcx.expr_ty(cond_expr); - let if_ty = if cond_ty.references_error() { - fcx.tcx().types.err + res + } else { + fcx.infcx().commit_if_ok(|_| { + let trace = TypeTrace::types(origin, true, then_ty, else_ty); + fcx.infcx().lub(true, trace).relate(&then_ty, &else_ty) + }) + }; + (origin, then_ty, else_ty, result) } else { - branches_ty + let origin = TypeOrigin::IfExpressionWithNoElse(sp); + (origin, unit, then_ty, + fcx.infcx().eq_types(true, origin, unit, then_ty).map(|_| unit)) + }; + + let if_ty = match result { + Ok(ty) => { + if fcx.expr_ty(cond_expr).references_error() { + fcx.tcx().types.err + } else { + ty + } + } + Err(e) => { + fcx.infcx().report_mismatched_types(origin, expected, found, e); + fcx.tcx().types.err + } }; fcx.write_ty(id, if_ty); @@ -2915,7 +2899,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let (_, autoderefs, field_ty) = autoderef(fcx, expr.span, expr_t, - Some(base), + || Some(base), UnresolvedTypeAction::Error, lvalue_pref, |base_t, _| { @@ -3013,7 +2997,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let (_, autoderefs, field_ty) = autoderef(fcx, expr.span, expr_t, - Some(base), + || Some(base), UnresolvedTypeAction::Error, lvalue_pref, |base_t, _| { @@ -3261,21 +3245,21 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, match unop { hir::UnDeref => { oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t); - oprnd_t = match oprnd_t.builtin_deref(true, NoPreference) { - Some(mt) => mt.ty, - None => match try_overloaded_deref(fcx, expr.span, - Some(MethodCall::expr(expr.id)), - Some(&oprnd), oprnd_t, lvalue_pref) { - Some(mt) => mt.ty, - None => { - fcx.type_error_message(expr.span, |actual| { - format!("type `{}` cannot be \ - dereferenced", actual) - }, oprnd_t, None); - tcx.types.err - } - } - }; + + if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) { + oprnd_t = mt.ty; + } else if let Some(method) = try_overloaded_deref( + fcx, expr.span, Some(&oprnd), oprnd_t, lvalue_pref) { + oprnd_t = make_overloaded_lvalue_return_type(tcx, method).ty; + fcx.inh.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id), + method); + } else { + fcx.type_error_message(expr.span, |actual| { + format!("type `{}` cannot be \ + dereferenced", actual) + }, oprnd_t, None); + oprnd_t = tcx.types.err; + } } hir::UnNot => { oprnd_t = structurally_resolved_type(fcx, oprnd.span, @@ -3519,7 +3503,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, // Defer other checks until we're done type checking. let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut(); - let cast_check = cast::CastCheck::new((**e).clone(), t_expr, t_cast, expr.span); + let cast_check = cast::CastCheck::new(e, t_expr, t_cast, expr.span); deferred_cast_checks.push(cast_check); } } @@ -3536,23 +3520,30 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } }); - let typ = match uty { - Some(uty) => { - for e in args { - check_expr_coercable_to_type(fcx, &e, uty); - } - uty - } - None => { - let t: Ty = fcx.infcx().next_ty_var(); - for e in args { - check_expr_has_type(fcx, &e, t); + let mut unified = fcx.infcx().next_ty_var(); + let coerce_to = uty.unwrap_or(unified); + + for (i, e) in args.iter().enumerate() { + check_expr_with_hint(fcx, e, coerce_to); + let e_ty = fcx.expr_ty(e); + let origin = TypeOrigin::Misc(e.span); + + // Special-case the first element, as it has no "previous expressions". + let result = if i == 0 { + coercion::try(fcx, e, coerce_to) + } else { + let prev_elems = || args[..i].iter().map(|e| &**e); + coercion::try_find_lub(fcx, origin, prev_elems, unified, e) + }; + + match result { + Ok(ty) => unified = ty, + Err(e) => { + fcx.infcx().report_mismatched_types(origin, unified, e_ty, e); } - t } - }; - let typ = tcx.mk_array(typ, args.len()); - fcx.write_ty(id, typ); + } + fcx.write_ty(id, tcx.mk_array(unified, args.len())); } hir::ExprRepeat(ref element, ref count_expr) => { check_expr_has_type(fcx, &count_expr, tcx.types.usize); @@ -3680,8 +3671,6 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, debug!("... {:?}, expected is {:?}", fcx.expr_ty(expr), expected); - - unifier(); } pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index f6225cf6ca768..e428fc927f05c 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -881,7 +881,7 @@ fn constrain_callee(rcx: &mut Rcx, _callee_expr: &hir::Expr) { let callee_ty = rcx.resolve_node_type(callee_id); match callee_ty.sty { - ty::TyBareFn(..) => { } + ty::TyFnDef(..) | ty::TyFnPtr(_) => { } _ => { // this should not happen, but it does if the program is // erroneous diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 997f56bd449c6..a8ada8061317e 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -255,9 +255,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id)); let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty); let bare_fn_ty = match item_ty.sty { - ty::TyBareFn(_, ref bare_fn_ty) => bare_fn_ty, + ty::TyFnDef(_, _, ref bare_fn_ty) => bare_fn_ty, _ => { - this.tcx().sess.span_bug(item.span, "Fn item without bare fn type"); + this.tcx().sess.span_bug(item.span, "Fn item without fn type"); } }; diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 6106011433027..cad321c0b2374 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -27,7 +27,7 @@ use middle::ty::{Ty, TyBool, TyChar, TyEnum, TyError}; use middle::ty::{TyParam, TyRawPtr}; use middle::ty::{TyRef, TyStruct, TyTrait, TyTuple}; use middle::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; -use middle::ty::{TyUint, TyClosure, TyBox, TyBareFn}; +use middle::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr}; use middle::ty::TyProjection; use middle::ty::util::CopyImplementationError; use middle::free_region::FreeRegionMap; @@ -67,8 +67,8 @@ fn get_base_type_def_id<'a, 'tcx>(inference_context: &InferCtxt<'a, 'tcx>, } TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | - TyStr | TyArray(..) | TySlice(..) | TyBareFn(..) | TyTuple(..) | - TyParam(..) | TyError | + TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) | + TyTuple(..) | TyParam(..) | TyError | TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => { None } @@ -385,11 +385,12 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env)); + let origin = TypeOrigin::Misc(span); let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>, mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| { if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) { - infcx.report_mismatched_types(span, mk_ptr(mt_b.ty), - target, &ty::error::TypeError::Mutability); + infcx.report_mismatched_types(origin, mk_ptr(mt_b.ty), + target, ty::error::TypeError::Mutability); } (mt_a.ty, mt_b.ty, unsize_trait, None) }; @@ -418,7 +419,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { return; } - let origin = TypeOrigin::Misc(span); let fields = &def_a.struct_variant().fields; let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| { let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b)); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index b3305fdb9a044..3ce03e245785a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -543,6 +543,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, sig, untransformed_rcvr_ty); let def_id = ccx.tcx.map.local_def_id(id); + let substs = ccx.tcx.mk_substs(mk_item_substs(ccx, &ty_generics)); + let ty_method = ty::Method::new(name, ty_generics, ty_generic_predicates, @@ -552,8 +554,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, def_id, container); - let fty = ccx.tcx.mk_fn(Some(def_id), - ccx.tcx.mk_bare_fn(ty_method.fty.clone())); + let fty = ccx.tcx.mk_fn_def(def_id, substs, ty_method.fty.clone()); debug!("method {} (id {}) has type {:?}", name, id, fty); ccx.tcx.register_item_type(def_id, TypeScheme { @@ -715,17 +716,13 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { tcx.register_item_type(def_id, TypeScheme { generics: ty_generics.clone(), ty: selfty }); - if let &Some(ref ast_trait_ref) = opt_trait_ref { - tcx.impl_trait_refs.borrow_mut().insert( - def_id, - Some(astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), - &ExplicitRscope, - ast_trait_ref, - Some(selfty))) - ); - } else { - tcx.impl_trait_refs.borrow_mut().insert(def_id, None); - } + let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| { + astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates), + &ExplicitRscope, + ast_trait_ref, + Some(selfty)) + }); + tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref); enforce_impl_params_are_constrained(tcx, generics, &mut ty_predicates, def_id); tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone()); @@ -902,7 +899,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } if !struct_def.is_struct() { - convert_variant_ctor(tcx, struct_def.id(), variant, scheme, predicates); + convert_variant_ctor(ccx, struct_def.id(), variant, scheme, predicates); } }, hir::ItemTy(_, ref generics) => { @@ -920,11 +917,12 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { } } -fn convert_variant_ctor<'a, 'tcx>(tcx: &TyCtxt<'tcx>, +fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ctor_id: ast::NodeId, variant: ty::VariantDef<'tcx>, scheme: ty::TypeScheme<'tcx>, predicates: ty::GenericPredicates<'tcx>) { + let tcx = ccx.tcx; let ctor_ty = match variant.kind() { VariantKind::Unit | VariantKind::Struct => scheme.ty, VariantKind::Tuple => { @@ -933,9 +931,17 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: &TyCtxt<'tcx>, .iter() .map(|field| field.unsubst_ty()) .collect(); - tcx.mk_ctor_fn(tcx.map.local_def_id(ctor_id), - &inputs[..], - scheme.ty) + let def_id = tcx.map.local_def_id(ctor_id); + let substs = tcx.mk_substs(mk_item_substs(ccx, &scheme.generics)); + tcx.mk_fn_def(def_id, substs, ty::BareFnTy { + unsafety: hir::Unsafety::Normal, + abi: abi::Abi::Rust, + sig: ty::Binder(ty::FnSig { + inputs: inputs, + output: ty::FnConverging(scheme.ty), + variadic: false + }) + }) } }; write_ty_to_tcx(tcx, ctor_id, ctor_ty); @@ -961,7 +967,7 @@ fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, // Convert the ctor, if any. This also registers the variant as // an item. convert_variant_ctor( - ccx.tcx, + ccx, variant.node.data.id(), ty_variant, scheme.clone(), @@ -1436,7 +1442,9 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, hir::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty()); let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl); - let ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(it.id)), tcx.mk_bare_fn(tofd)); + let def_id = ccx.tcx.map.local_def_id(it.id); + let substs = tcx.mk_substs(mk_item_substs(ccx, &ty_generics)); + let ty = tcx.mk_fn_def(def_id, substs, tofd); ty::TypeScheme { ty: ty, generics: ty_generics } } hir::ItemTy(ref t, ref generics) => { @@ -1556,7 +1564,9 @@ fn compute_type_scheme_of_foreign_item<'a, 'tcx>( { match it.node { hir::ForeignItemFn(ref fn_decl, ref generics) => { - compute_type_scheme_of_foreign_fn_decl(ccx, fn_decl, generics, abi) + compute_type_scheme_of_foreign_fn_decl( + ccx, ccx.tcx.map.local_def_id(it.id), + fn_decl, generics, abi) } hir::ForeignItemStatic(ref t, _) => { ty::TypeScheme { @@ -2107,6 +2117,7 @@ fn conv_param_bounds<'a,'tcx>(astconv: &AstConv<'tcx>, fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( ccx: &CrateCtxt<'a, 'tcx>, + id: DefId, decl: &hir::FnDecl, ast_generics: &hir::Generics, abi: abi::Abi) @@ -2140,14 +2151,14 @@ fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>( ty::FnDiverging }; - let t_fn = ccx.tcx.mk_fn(None, - ccx.tcx.mk_bare_fn(ty::BareFnTy { - abi: abi, - unsafety: hir::Unsafety::Unsafe, - sig: ty::Binder(ty::FnSig {inputs: input_tys, - output: output, - variadic: decl.variadic}), - })); + let substs = ccx.tcx.mk_substs(mk_item_substs(ccx, &ty_generics)); + let t_fn = ccx.tcx.mk_fn_def(id, substs, ty::BareFnTy { + abi: abi, + unsafety: hir::Unsafety::Unsafe, + sig: ty::Binder(ty::FnSig {inputs: input_tys, + output: output, + variadic: decl.variadic}), + }); ty::TypeScheme { generics: ty_generics, diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 336bff26e2c7f..907ee15c41ba0 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -72,7 +72,8 @@ fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec { parameters_for_regions_in_substs(&pi.trait_ref.substs), ty::TyBool | ty::TyChar | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyBox(..) | ty::TyStr | - ty::TyArray(..) | ty::TySlice(..) | ty::TyBareFn(..) | + ty::TyArray(..) | ty::TySlice(..) | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyTuple(..) | ty::TyRawPtr(..) | ty::TyInfer(..) | ty::TyClosure(..) | ty::TyError => vec![] diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index a103cbc928b49..035f8c6050022 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -103,7 +103,7 @@ use dep_graph::DepNode; use front::map as hir_map; use middle::def::Def; use middle::infer::{self, TypeOrigin}; -use middle::subst; +use middle::subst::Substs; use middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use session::{config, CompileResult}; use util::common::time; @@ -128,7 +128,7 @@ pub mod coherence; pub mod variance; pub struct TypeAndSubsts<'tcx> { - pub substs: subst::Substs<'tcx>, + pub substs: Substs<'tcx>, pub ty: Ty<'tcx>, } @@ -220,7 +220,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, let tcx = ccx.tcx; let main_t = tcx.node_id_to_type(main_id); match main_t.sty { - ty::TyBareFn(..) => { + ty::TyFnDef(..) => { match tcx.map.find(main_id) { Some(hir_map::NodeItem(it)) => { match it.node { @@ -236,7 +236,8 @@ fn check_main_fn_ty(ccx: &CrateCtxt, _ => () } let main_def_id = tcx.map.local_def_id(main_id); - let se_ty = tcx.mk_fn(Some(main_def_id), tcx.mk_bare_fn(ty::BareFnTy { + let substs = tcx.mk_substs(Substs::empty()); + let se_ty = tcx.mk_fn_def(main_def_id, substs, ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -244,7 +245,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, output: ty::FnConverging(tcx.mk_nil()), variadic: false }) - })); + }); require_same_types(tcx, None, false, main_span, main_t, se_ty, || { @@ -266,7 +267,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, let tcx = ccx.tcx; let start_t = tcx.node_id_to_type(start_id); match start_t.sty { - ty::TyBareFn(..) => { + ty::TyFnDef(..) => { match tcx.map.find(start_id) { Some(hir_map::NodeItem(it)) => { match it.node { @@ -282,8 +283,9 @@ fn check_start_fn_ty(ccx: &CrateCtxt, _ => () } - let se_ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(start_id)), - tcx.mk_bare_fn(ty::BareFnTy { + let start_def_id = ccx.tcx.map.local_def_id(start_id); + let substs = tcx.mk_substs(Substs::empty()); + let se_ty = tcx.mk_fn_def(start_def_id, substs, ty::BareFnTy { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, sig: ty::Binder(ty::FnSig { @@ -294,7 +296,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, output: ty::FnConverging(tcx.types.isize), variadic: false, }), - })); + }); require_same_types(tcx, None, false, start_span, start_t, se_ty, || { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 0c9fa9fd0ab4f..aecc588c3e286 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -429,7 +429,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } } - ty::TyBareFn(_, &ty::BareFnTy { ref sig, .. }) => { + ty::TyFnDef(_, _, &ty::BareFnTy { ref sig, .. }) | + ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => { self.add_constraints_from_sig(generics, sig, variance); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 32f3706675ad2..c14e4af810310 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -164,7 +164,7 @@ pub fn build_external_trait(cx: &DocContext, tcx: &TyCtxt, fn build_external_function(cx: &DocContext, tcx: &TyCtxt, did: DefId) -> clean::Function { let t = tcx.lookup_item_type(did); let (decl, style, abi) = match t.ty.sty { - ty::TyBareFn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi), + ty::TyFnDef(_, _, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi), _ => panic!("bad function"), }; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 6c9ee52878201..5921093bcac1e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1663,7 +1663,8 @@ impl<'tcx> Clean for ty::Ty<'tcx> { mutability: mt.mutbl.clean(cx), type_: box mt.ty.clean(cx), }, - ty::TyBareFn(_, ref fty) => BareFunction(box BareFunctionDecl { + ty::TyFnDef(_, _, ref fty) | + ty::TyFnPtr(ref fty) => BareFunction(box BareFunctionDecl { unsafety: fty.unsafety, generics: Generics { lifetimes: Vec::new(), diff --git a/src/test/auxiliary/issue13507.rs b/src/test/auxiliary/issue13507.rs index 78d0394a6e5ad..4cb846b51868f 100644 --- a/src/test/auxiliary/issue13507.rs +++ b/src/test/auxiliary/issue13507.rs @@ -14,26 +14,26 @@ pub mod testtypes { use std::any::TypeId; pub fn type_ids() -> Vec { - let mut ids = vec!(); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::<&'static FooTrait>()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids + vec![ + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::() + ] } - // Tests ty_nil - pub type FooNil = (); - - // Skipping ty_bot - // Tests TyBool pub type FooBool = bool; @@ -49,25 +49,26 @@ pub mod testtypes { // Tests TyFloat (does not test all variants of FloatTy) pub type FooFloat = f64; - // For TyStr, what kind of string should I use? &'static str? String? Raw str? + // Tests TyStr + pub type FooStr = str; - // Tests TyEnum - pub enum FooEnum { - VarA(usize), - VarB(usize, usize) - } + // Tests TyArray + pub type FooArray = [u8; 1]; - // Tests TyBox (of u8) - pub type FooUniq = Box; + // Tests TySlice + pub type FooSlice = [u8]; - // As with TyStr, what type should be used for TyArray? + // Tests TyBox (of u8) + pub type FooBox = Box; // Tests TyRawPtr pub type FooPtr = *const u8; - // Skipping TyRef + // Tests TyRef + pub type FooRef = &'static u8; - // Skipping TyBareFn (how do you get a bare function type, rather than proc or closure?) + // Tests TyFnPtr + pub type FooFnPtr = fn(u8) -> bool; // Tests TyTrait pub trait FooTrait { @@ -80,14 +81,17 @@ pub mod testtypes { foo_field: usize } + // Tests TyEnum + pub enum FooEnum { + VarA(usize), + VarB(usize, usize) + } + // Tests TyTuple + pub type FooNil = (); pub type FooTuple = (u8, i8, bool); - // Skipping ty_param - - // Skipping ty_self - - // Skipping ty_self + // Skipping TyParam // Skipping TyInfer diff --git a/src/test/compile-fail/fn-item-type.rs b/src/test/compile-fail/fn-item-type.rs index 5015810ff4774..2fbd1ddb1e6b9 100644 --- a/src/test/compile-fail/fn-item-type.rs +++ b/src/test/compile-fail/fn-item-type.rs @@ -11,23 +11,37 @@ // Test that the types of distinct fn items are not compatible by // default. See also `run-pass/fn-item-type-*.rs`. -fn foo(x: isize) -> isize { x * 2 } -fn bar(x: isize) -> isize { x * 4 } +fn foo(x: isize) -> isize { x * 2 } +fn bar(x: isize) -> isize { x * 4 } fn eq(x: T, y: T) { } +trait Foo { fn foo() { /* this is a default fn */ } } +impl Foo for T { /* `foo` is still default here */ } + fn main() { - let f = if true { foo } else { bar }; - //~^ ERROR if and else have incompatible types - //~| expected `fn(isize) -> isize {foo}` - //~| found `fn(isize) -> isize {bar}` - //~| expected fn item, - //~| found a different fn item - - eq(foo, bar); + eq(foo::, bar::); //~^ ERROR mismatched types - //~| expected `fn(isize) -> isize {foo}` - //~| found `fn(isize) -> isize {bar}` + //~| expected `fn(isize) -> isize {foo::}` + //~| found `fn(isize) -> isize {bar::}` //~| expected fn item //~| found a different fn item + + eq(foo::, foo::); + //~^ ERROR mismatched types + //~| expected `fn(isize) -> isize {foo::}` + //~| found `fn(isize) -> isize {foo::}` + + eq(bar::, bar::>); + //~^ ERROR mismatched types + //~| expected `fn(isize) -> isize {bar::}` + //~| found `fn(isize) -> isize {bar::>}` + //~| expected struct `collections::string::String` + //~| found struct `collections::vec::Vec` + + // Make sure we distinguish between trait methods correctly. + eq(::foo, ::foo); + //~^ ERROR mismatched types + //~| expected `fn() {Foo::foo}` + //~| found `fn() {Foo::foo}` } diff --git a/src/test/compile-fail/invalid-intrinsic.rs b/src/test/compile-fail/invalid-intrinsic.rs new file mode 100644 index 0000000000000..2aa2546cb9fe1 --- /dev/null +++ b/src/test/compile-fail/invalid-intrinsic.rs @@ -0,0 +1,16 @@ +// Copyright 2015 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(intrinsics)] +extern "rust-intrinsic" { + pub static breakpoint : unsafe extern "rust-intrinsic" fn(); + //~^ ERROR intrinsic has wrong type +} +fn main() { unsafe { breakpoint(); } } \ No newline at end of file diff --git a/src/test/compile-fail/issue-13482-2.rs b/src/test/compile-fail/issue-13482-2.rs index f907be161fa08..e1fe2d06993d5 100644 --- a/src/test/compile-fail/issue-13482-2.rs +++ b/src/test/compile-fail/issue-13482-2.rs @@ -17,7 +17,7 @@ fn main() { let y = match x { [] => None, //~^ ERROR mismatched types -//~| expected `[_#0i; 2]` +//~| expected `[_#1i; 2]` //~| found `[_#7t; 0]` //~| expected an array with a fixed size of 2 elements //~| found one with 0 elements diff --git a/src/test/compile-fail/issue-17728.rs b/src/test/compile-fail/issue-17728.rs index 83e52216be29b..787eb7a3b8878 100644 --- a/src/test/compile-fail/issue-17728.rs +++ b/src/test/compile-fail/issue-17728.rs @@ -107,7 +107,7 @@ impl Debug for Player { } fn str_to_direction(to_parse: &str) -> RoomDirection { - match to_parse { + match to_parse { //~ ERROR match arms have incompatible types "w" | "west" => RoomDirection::West, "e" | "east" => RoomDirection::East, "n" | "north" => RoomDirection::North, @@ -116,7 +116,7 @@ fn str_to_direction(to_parse: &str) -> RoomDirection { "out" => RoomDirection::Out, "up" => RoomDirection::Up, "down" => RoomDirection::Down, - _ => None //~ ERROR mismatched types + _ => None //~ NOTE match arm with an incompatible type } } diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index 256c5d8e6f72c..9143a226a2483 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -21,5 +21,5 @@ impl vec_monad for Vec { } fn main() { ["hi"].bind(|x| [x] ); - //~^ ERROR no method named `bind` found for type `[&str; 1]` in the current scope + //~^ ERROR no method named `bind` found for type `[&'static str; 1]` in the current scope } diff --git a/src/test/compile-fail/transmute-from-fn-item-types-lint.rs b/src/test/compile-fail/transmute-from-fn-item-types-lint.rs new file mode 100644 index 0000000000000..3eae76f9492a2 --- /dev/null +++ b/src/test/compile-fail/transmute-from-fn-item-types-lint.rs @@ -0,0 +1,51 @@ +// Copyright 2016 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. + +use std::mem; + +unsafe fn foo() -> (isize, *const (), Option) { + let i = mem::transmute(bar); + //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting + //~^^ WARN was previously accepted + + let p = mem::transmute(foo); + //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting + //~^^ WARN was previously accepted + + let of = mem::transmute(main); + //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting + //~^^ WARN was previously accepted + + (i, p, of) +} + +unsafe fn bar() { + mem::transmute::<_, *mut ()>(foo); + //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting + //~^^ WARN was previously accepted + + mem::transmute::<_, fn()>(bar); + //~^ WARN is now zero-sized and has to be cast to a pointer before transmuting + //~^^ WARN was previously accepted + + // No error if a coercion would otherwise occur. + mem::transmute::(main); + + // Error, still, if the resulting type is not pointer-sized. + mem::transmute::<_, u8>(main); + //~^ ERROR transmute called with differently sized types +} + +fn main() { + unsafe { + foo(); + bar(); + } +} diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs index 94055450bc6bb..1d5ebdbae3e2e 100644 --- a/src/test/compile-fail/variadic-ffi-3.rs +++ b/src/test/compile-fail/variadic-ffi-3.rs @@ -22,7 +22,7 @@ fn main() { let x: unsafe extern "C" fn(f: isize, x: u8) = foo; //~^ ERROR: mismatched types //~| expected `unsafe extern "C" fn(isize, u8)` - //~| found `unsafe extern "C" fn(isize, u8, ...)` + //~| found `unsafe extern "C" fn(isize, u8, ...) {foo}` //~| expected non-variadic fn //~| found variadic function diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 835f7fc96c63f..0347631aeb336 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -86,8 +86,10 @@ pub fn use_id() { let _ = ((id::<[i32; (3 as usize)]> as - fn([i32; 3]) -> [i32; 3] {id})(([(1 as i32), (2 as i32), - (3 as i32)] as [i32; 3])) as + fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32), + (2 as i32), + (3 as i32)] as + [i32; 3])) as [i32; 3]); } fn main() { } diff --git a/src/test/run-pass/coerce-unify.rs b/src/test/run-pass/coerce-unify.rs new file mode 100644 index 0000000000000..3d690146931d9 --- /dev/null +++ b/src/test/run-pass/coerce-unify.rs @@ -0,0 +1,77 @@ +// Copyright 2016 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. + +// Check that coercions can unify if-else, match arms and array elements. + +// Try to construct if-else chains, matches and arrays out of given expressions. +macro_rules! check { + ($last:expr $(, $rest:expr)+) => { + // Last expression comes first because of whacky ifs and matches. + let _ = $(if false { $rest })else+ else { $last }; + + let _ = match 0 { $(_ if false => $rest,)+ _ => $last }; + + let _ = [$($rest,)+ $last]; + } +} + +// Check all non-uniform cases of 2 and 3 expressions of 2 types. +macro_rules! check2 { + ($a:expr, $b:expr) => { + check!($a, $b); + check!($b, $a); + + check!($a, $a, $b); + check!($a, $b, $a); + check!($a, $b, $b); + + check!($b, $a, $a); + check!($b, $a, $b); + check!($b, $b, $a); + } +} + +// Check all non-uniform cases of 2 and 3 expressions of 3 types. +macro_rules! check3 { + ($a:expr, $b:expr, $c:expr) => { + // Delegate to check2 for cases where a type repeats. + check2!($a, $b); + check2!($b, $c); + check2!($a, $c); + + // Check the remaining cases, i.e. permutations of ($a, $b, $c). + check!($a, $b, $c); + check!($a, $c, $b); + check!($b, $a, $c); + check!($b, $c, $a); + check!($c, $a, $b); + check!($c, $b, $a); + } +} + +use std::mem::size_of; + +fn foo() {} +fn bar() {} + +pub fn main() { + check3!(foo, bar, foo as fn()); + check3!(size_of::, size_of::, size_of:: as fn() -> usize); + + let s = String::from("bar"); + check2!("foo", &s); + + let a = [1, 2, 3]; + let v = vec![1, 2, 3]; + check2!(&a[..], &v); + + // Make sure in-array coercion still works. + let _ = [("a", Default::default()), (Default::default(), "b"), (&s, &s)]; +} diff --git a/src/test/run-pass/enum-clike-ffi-as-int.rs b/src/test/run-pass/enum-clike-ffi-as-int.rs index 8be3634c88add..fdaad9e1fabce 100644 --- a/src/test/run-pass/enum-clike-ffi-as-int.rs +++ b/src/test/run-pass/enum-clike-ffi-as-int.rs @@ -25,16 +25,17 @@ #[repr(u32)] enum Foo { - A = 0, - B = 23 + A = 0, + B = 23 } #[inline(never)] extern "C" fn foo(_x: usize) -> Foo { Foo::B } pub fn main() { - unsafe { - let f: extern "C" fn(usize) -> u32 = ::std::mem::transmute(foo); - assert_eq!(f(0xDEADBEEF), Foo::B as u32); - } + unsafe { + let f: extern "C" fn(usize) -> u32 = + ::std::mem::transmute(foo as extern "C" fn(usize) -> Foo); + assert_eq!(f(0xDEADBEEF), Foo::B as u32); + } } diff --git a/src/test/run-pass/fn-item-type-zero-sized.rs b/src/test/run-pass/fn-item-type-zero-sized.rs new file mode 100644 index 0000000000000..5fdaf083d078f --- /dev/null +++ b/src/test/run-pass/fn-item-type-zero-sized.rs @@ -0,0 +1,22 @@ +// Copyright 2016 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. + +// Test that fn item types are zero-sized. + +use std::mem::{size_of, size_of_val}; + +fn main() { + assert_eq!(size_of_val(&main), 0); + + let (a, b) = (size_of::, size_of::); + assert_eq!(size_of_val(&a), 0); + assert_eq!(size_of_val(&b), 0); + assert_eq!((a(), b()), (1, 2)); +} diff --git a/src/test/run-pass/issue-13507-2.rs b/src/test/run-pass/issue-13507-2.rs index 91ec3e8540442..084b7a166cdd3 100644 --- a/src/test/run-pass/issue-13507-2.rs +++ b/src/test/run-pass/issue-13507-2.rs @@ -19,23 +19,29 @@ use issue13507::testtypes; use std::any::TypeId; pub fn type_ids() -> Vec { - let mut ids = vec!(); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::<&'static testtypes::FooTrait>()); - ids.push(TypeId::of::()); - ids.push(TypeId::of::()); - ids + use issue13507::testtypes::*; + vec![ + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::(), + TypeId::of::() + ] } pub fn main() { - let othercrate = testtypes::type_ids(); + let othercrate = issue13507::testtypes::type_ids(); let thiscrate = type_ids(); assert_eq!(thiscrate, othercrate); } diff --git a/src/test/run-pass/mir_refs_correct.rs b/src/test/run-pass/mir_refs_correct.rs index 93953e3f58ae0..67baf2f9c49c1 100644 --- a/src/test/run-pass/mir_refs_correct.rs +++ b/src/test/run-pass/mir_refs_correct.rs @@ -204,48 +204,41 @@ fn t24() -> fn(u8) -> S { C4 } -fn main(){ - unsafe { - assert_eq!(t1()(), regular()); - - assert!(::std::mem::transmute::<_, *mut ()>(t2()) == - ::std::mem::transmute::<_, *mut ()>(E::U)); - assert!(::std::mem::transmute::<_, *mut ()>(t3()) == - ::std::mem::transmute::<_, *mut ()>(S)); - - assert_eq!(t4()(), S::hey()); - let s = S(42); - assert_eq!(t5()(&s), ::hoy(&s)); - - - assert_eq!(t6()(), ext::regular_fn()); - assert!(::std::mem::transmute::<_, *mut ()>(t7()) == - ::std::mem::transmute::<_, *mut ()>(ext::E::U)); - assert!(::std::mem::transmute::<_, *mut ()>(t8()) == - ::std::mem::transmute::<_, *mut ()>(ext::S)); - - assert_eq!(t9()(), ext::S::hey()); - let sext = ext::S(6); - assert_eq!(t10()(&sext), ::hoy(&sext)); - - let p = parametric::; - assert!(::std::mem::transmute::<_, *mut ()>(t11()) == - ::std::mem::transmute::<_, *mut ()>(p)); - - assert_eq!(t12(), C); - assert_eq!(t13(), C2); - assert_eq!(t13_2(), C3); - - assert_eq!(t14()(), ::hoy2()); - assert_eq!(t15()(&s), S::hey2(&s)); - assert_eq!(t16()(10u32, 20u32), F::f(10u32, 20u32)); - assert_eq!(t17()(30u32, 10u64), F::f(30u32, 10u64)); - assert_eq!(t18()(50u64, 5u64), F::f(50u64, 5u64)); - assert_eq!(t19()(322u64, 2u32), F::f(322u64, 2u32)); - assert_eq!(t20()(123u64, 38u32), >::staticmeth(123, 38)); - assert_eq!(t21(), Unit); - assert_eq!(t22(), None); - assert_eq!(t23(), (CEnum::A, CEnum::B)); - assert_eq!(t24(), C4); - } +fn main() { + assert_eq!(t1()(), regular()); + + assert_eq!(t2() as *mut (), E::U as *mut ()); + assert_eq!(t3() as *mut (), S as *mut ()); + + assert_eq!(t4()(), S::hey()); + let s = S(42); + assert_eq!(t5()(&s), ::hoy(&s)); + + + assert_eq!(t6()(), ext::regular_fn()); + assert_eq!(t7() as *mut (), ext::E::U as *mut ()); + assert_eq!(t8() as *mut (), ext::S as *mut ()); + + assert_eq!(t9()(), ext::S::hey()); + let sext = ext::S(6); + assert_eq!(t10()(&sext), ::hoy(&sext)); + + let p = parametric::; + assert_eq!(t11() as *mut (), p as *mut ()); + + assert_eq!(t12(), C); + assert_eq!(t13(), C2); + assert_eq!(t13_2(), C3); + + assert_eq!(t14()(), ::hoy2()); + assert_eq!(t15()(&s), S::hey2(&s)); + assert_eq!(t16()(10u32, 20u32), F::f(10u32, 20u32)); + assert_eq!(t17()(30u32, 10u64), F::f(30u32, 10u64)); + assert_eq!(t18()(50u64, 5u64), F::f(50u64, 5u64)); + assert_eq!(t19()(322u64, 2u32), F::f(322u64, 2u32)); + assert_eq!(t20()(123u64, 38u32), >::staticmeth(123, 38)); + assert_eq!(t21(), Unit); + assert_eq!(t22(), None); + assert_eq!(t23(), (CEnum::A, CEnum::B)); + assert_eq!(t24(), C4); } diff --git a/src/test/run-pass/nullable-pointer-ffi-compat.rs b/src/test/run-pass/nullable-pointer-ffi-compat.rs index 224111900d60c..2b7cf6c668247 100644 --- a/src/test/run-pass/nullable-pointer-ffi-compat.rs +++ b/src/test/run-pass/nullable-pointer-ffi-compat.rs @@ -24,13 +24,14 @@ use std::mem; #[inline(never)] -extern "C" fn foo<'a>(x: &'a isize) -> Option<&'a isize> { Some(x) } +extern "C" fn foo(x: &isize) -> Option<&isize> { Some(x) } static FOO: isize = 0xDEADBEE; pub fn main() { unsafe { - let f: for<'a> extern "C" fn(&'a isize) -> &'a isize = mem::transmute(foo); + let f: extern "C" fn(&isize) -> &isize = + mem::transmute(foo as extern "C" fn(&isize) -> Option<&isize>); assert_eq!(*f(&FOO), FOO); } } diff --git a/src/test/run-pass/nullable-pointer-iotareduction.rs b/src/test/run-pass/nullable-pointer-iotareduction.rs index cfd3bb49f34d4..dffdcfe0af562 100644 --- a/src/test/run-pass/nullable-pointer-iotareduction.rs +++ b/src/test/run-pass/nullable-pointer-iotareduction.rs @@ -12,8 +12,6 @@ #![allow(unknown_features)] #![feature(box_syntax)] -use std::{option, mem}; - // Iota-reduction is a rule in the Calculus of (Co-)Inductive Constructions, // which "says that a destructor applied to an object built from a constructor // behaves as expected". -- http://coq.inria.fr/doc/Reference-Manual006.html @@ -43,9 +41,9 @@ macro_rules! check_option { check_option!($e, $T, |ptr| assert_eq!(*ptr, $e)); }}; ($e:expr, $T:ty, |$v:ident| $chk:expr) => {{ - assert!(option::Option::None::<$T>.is_none()); + assert!(None::<$T>.is_none()); let e = $e; - let s_ = option::Option::Some::<$T>(e); + let s_ = Some::<$T>(e); let $v = s_.as_ref().unwrap(); $chk }} @@ -78,9 +76,8 @@ pub fn main() { check_type!(&17, &isize); check_type!(box 18, Box); check_type!("foo".to_string(), String); - check_type!(vec!(20, 22), Vec ); - let mint: usize = unsafe { mem::transmute(main) }; + check_type!(vec!(20, 22), Vec); check_type!(main, fn(), |pthing| { - assert_eq!(mint, unsafe { mem::transmute(*pthing) }) + assert_eq!(main as fn(), *pthing as fn()) }); } diff --git a/src/test/run-pass/transmute-from-fn-item-types.rs b/src/test/run-pass/transmute-from-fn-item-types.rs new file mode 100644 index 0000000000000..574a90e2ad697 --- /dev/null +++ b/src/test/run-pass/transmute-from-fn-item-types.rs @@ -0,0 +1,27 @@ +// Copyright 2016 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. + +#![allow(transmute_from_fn_item_types)] + +use std::mem; + +fn main() { + unsafe { + let u = mem::transmute(main); + let p = mem::transmute(main); + let f = mem::transmute(main); + let tuple: (usize, *mut (), fn()) = (u, p, f); + assert_eq!(mem::transmute::<_, [usize; 3]>(tuple), [main as usize; 3]); + + mem::transmute::<_, usize>(main); + mem::transmute::<_, *mut ()>(main); + mem::transmute::<_, fn()>(main); + } +}