Auto merge of #31710 - eddyb:reify, r=nikomatsakis
Distinguish fn item types to allow reification from nothing to fn pointers. The first commit is a rebase of #26284, except for files that have moved since. This is a [breaking-change], due to: * each FFI function has a distinct type, like all other functions currently do * all generic parameters on functions are recorded in their item types, e.g.: `size_of::<u8>` & `size_of::<i8>`'s types differ despite their identical signature. * function items are zero-sized, which will stop transmutes from working on them The first two cases are handled in most cases with the new coerce-unify logic, which will combine incompatible function item types into function pointers, at the outer-most level of if-else chains, match arms and array literals. The last case is specially handled during type-checking such that transmutes from a function item type to a pointer or integer type will continue to work for another release cycle, but are being linted against. To get rid of warnings and ensure your code will continue to compile, cast to a pointer before transmuting.
This commit is contained in:
commit
bcda58f491
109 changed files with 2044 additions and 2230 deletions
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 => { }
|
||||
|
|
|
|||
|
|
@ -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(..) |
|
||||
|
|
|
|||
|
|
@ -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<T>(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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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(..) |
|
||||
|
|
|
|||
|
|
@ -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<N>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<F:TypeFolder<'tcx>>(&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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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: \
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<DefId>,
|
||||
fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
|
||||
self.mk_ty(TyBareFn(opt_def_id, fty))
|
||||
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_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_ptr(&self, fty: BareFnTy<'tcx>) -> Ty<'tcx> {
|
||||
self.mk_ty(TyFnPtr(self.mk_bare_fn(fty)))
|
||||
}
|
||||
|
||||
pub fn mk_trait(&self,
|
||||
|
|
|
|||
|
|
@ -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()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(_) => {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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_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(a_opt_def_id, tcx.mk_bare_fn(fty)))
|
||||
Ok(tcx.mk_fn_ptr(fty))
|
||||
}
|
||||
|
||||
(&ty::TyProjection(ref a_data), &ty::TyProjection(ref b_data)) =>
|
||||
|
|
|
|||
|
|
@ -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::TyBareFn(opt_def_id, folder.tcx().mk_bare_fn(bfn))
|
||||
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::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),
|
||||
|
|
|
|||
|
|
@ -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<DefId>, &'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<TraitTy<'tcx>>),
|
||||
|
|
@ -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(_) |
|
||||
|
|
|
|||
|
|
@ -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<ty::Method<'tcx>>,
|
||||
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),
|
||||
|
|
|
|||
|
|
@ -98,7 +98,11 @@ fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}));
|
||||
|
||||
if let Some(def_id) = opt_def_id {
|
||||
try!(write!(f, " {{{}}}", ty::tls::with(|tcx| {
|
||||
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, ">"));
|
||||
}
|
||||
Ok(())
|
||||
write!(f, "}}")
|
||||
}
|
||||
TyFnPtr(ref bare_fn) => {
|
||||
if bare_fn.unsafety == hir::Unsafety::Unsafe {
|
||||
try!(write!(f, "unsafe "));
|
||||
}
|
||||
|
||||
if bare_fn.abi != Abi::Rust {
|
||||
try!(write!(f, "extern {} ", bare_fn.abi));
|
||||
}
|
||||
|
||||
write!(f, "{}", bare_fn.sig.0)
|
||||
}
|
||||
TyInfer(infer_ty) => write!(f, "{}", infer_ty),
|
||||
TyError => write!(f, "[type error]"),
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -171,6 +171,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||
reference: "RFC 218 <https://github.com/rust-lang/rfcs/blob/\
|
||||
master/text/0218-empty-struct-with-braces.md>",
|
||||
},
|
||||
FutureIncompatibleInfo {
|
||||
id: LintId::of(TRANSMUTE_FROM_FN_ITEM_TYPES),
|
||||
reference: "issue #19925 <https://github.com/rust-lang/rust/issues/19925>",
|
||||
},
|
||||
]);
|
||||
|
||||
// We have one lint pass defined specially
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -992,7 +992,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
|
|||
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))
|
||||
|
|
@ -1586,7 +1586,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,
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -135,12 +135,13 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -856,7 +856,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
|
||||
|
|
|
|||
|
|
@ -451,8 +451,8 @@ fn find_discr_field_candidate<'tcx>(tcx: &TyCtxt<'tcx>,
|
|||
// Regular thin pointer: &T/&mut T/Box<T>
|
||||
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() => {
|
||||
|
|
|
|||
|
|
@ -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[..]);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<ValueRef>,
|
||||
param_substs: &'tcx Substs<'tcx>)
|
||||
old_info: Option<ValueRef>)
|
||||
-> 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 {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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")));
|
||||
|_| expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot")));
|
||||
|
||||
let callee_data = TraitItem(MethodData { llfn: llreffn,
|
||||
llself: env_datum.val });
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 ");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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<Dest>,
|
||||
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<hir::Expr>],
|
||||
dest: Option<Dest>)
|
||||
-> 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 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);
|
||||
|
||||
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
|
||||
// Overloaded. Invoke the deref() method, which basically
|
||||
// converts from the `Smaht<T>` 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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<hir::Expr>]>,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
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);
|
||||
|
||||
Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
|
||||
// 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<Trait> 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<Self>) 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<Self>) 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<Trait>` from a value of type `Foo<T>`, 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<Option<ty::util::ImplMethod<'tcx>>>
|
||||
{
|
||||
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<Self>) 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 {
|
||||
|
|
|
|||
|
|
@ -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<OperandRef<'tcx>>
|
||||
{
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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<ast::NodeId>)
|
||||
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());
|
||||
|
||||
|
|
|
|||
|
|
@ -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(..) => {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
if result_ty.references_error() || bty.references_error() {
|
||||
tcx.types.err
|
||||
let origin = if is_if_let_fallback {
|
||||
TypeOrigin::IfExpressionWithNoElse(expr.span)
|
||||
} 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,
|
||||
),
|
||||
};
|
||||
TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src)
|
||||
};
|
||||
|
||||
infer::common_supertype(
|
||||
fcx.infcx(),
|
||||
origin,
|
||||
true,
|
||||
expected,
|
||||
found,
|
||||
)
|
||||
}
|
||||
});
|
||||
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 prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
|
||||
coercion::try_find_lub(fcx, origin, prev_arms, result_ty, &arm.body)
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Vec<traits::PredicateObligation<'tcx>>>,
|
||||
}
|
||||
|
||||
type CoerceResult<'tcx> = RelateResult<'tcx, Option<AutoAdjustment<'tcx>>>;
|
||||
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<T, F>(&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<Item=&'a hir::Expr> {
|
||||
|
||||
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<Item=&'a hir::Expr> {
|
||||
|
||||
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<Item=&'b hir::Expr> {
|
||||
|
||||
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<Item=&'b hir::Expr> {
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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<ty::Ty<'tcx>>,
|
||||
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 => {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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| {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 <none> 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 <none> 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<T>)
|
||||
where F: FnMut(Ty<'tcx>, usize) -> Option<T>,
|
||||
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<T>)
|
||||
// FIXME(eddyb) use copyable iterators when that becomes ergonomic.
|
||||
where E: Fn() -> I,
|
||||
I: IntoIterator<Item=&'b hir::Expr>,
|
||||
F: FnMut(Ty<'tcx>, usize) -> Option<T>,
|
||||
{
|
||||
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<MethodCall>,
|
||||
base_expr: Option<&hir::Expr>,
|
||||
base_ty: Ty<'tcx>,
|
||||
lvalue_pref: LvaluePreference)
|
||||
-> Option<ty::TypeAndMut<'tcx>>
|
||||
-> Option<MethodCallee<'tcx>>
|
||||
{
|
||||
// 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<MethodCall>,
|
||||
method: Option<MethodCallee<'tcx>>)
|
||||
-> Option<ty::TypeAndMut<'tcx>>
|
||||
/// 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();
|
||||
// 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();
|
||||
|
||||
if let Some(method_call) = method_call {
|
||||
fcx.inh.tables.borrow_mut().method_map.insert(method_call, method);
|
||||
}
|
||||
|
||||
// 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);
|
||||
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));
|
||||
});
|
||||
// 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()));
|
||||
}
|
||||
|
||||
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 {
|
||||
let origin = TypeOrigin::IfExpressionWithNoElse(sp);
|
||||
(origin, unit, then_ty,
|
||||
fcx.infcx().eq_types(true, origin, unit, then_ty).map(|_| unit))
|
||||
};
|
||||
|
||||
let cond_ty = fcx.expr_ty(cond_expr);
|
||||
let if_ty = if cond_ty.references_error() {
|
||||
fcx.tcx().types.err
|
||||
} else {
|
||||
branches_ty
|
||||
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);
|
||||
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);
|
||||
}
|
||||
uty
|
||||
}
|
||||
None => {
|
||||
let t: Ty = fcx.infcx().next_ty_var();
|
||||
for e in args {
|
||||
check_expr_has_type(fcx, &e, t);
|
||||
}
|
||||
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>,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -72,7 +72,8 @@ fn parameters_for_type_shallow<'tcx>(ty: Ty<'tcx>) -> Vec<Parameter> {
|
|||
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![]
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|| {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1663,7 +1663,8 @@ impl<'tcx> Clean<Type> 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(),
|
||||
|
|
|
|||
|
|
@ -14,26 +14,26 @@ pub mod testtypes {
|
|||
use std::any::TypeId;
|
||||
|
||||
pub fn type_ids() -> Vec<TypeId> {
|
||||
let mut ids = vec!();
|
||||
ids.push(TypeId::of::<FooNil>());
|
||||
ids.push(TypeId::of::<FooBool>());
|
||||
ids.push(TypeId::of::<FooInt>());
|
||||
ids.push(TypeId::of::<FooUint>());
|
||||
ids.push(TypeId::of::<FooFloat>());
|
||||
ids.push(TypeId::of::<FooEnum>());
|
||||
ids.push(TypeId::of::<FooUniq>());
|
||||
ids.push(TypeId::of::<FooPtr>());
|
||||
ids.push(TypeId::of::<&'static FooTrait>());
|
||||
ids.push(TypeId::of::<FooStruct>());
|
||||
ids.push(TypeId::of::<FooTuple>());
|
||||
ids
|
||||
vec![
|
||||
TypeId::of::<FooBool>(),
|
||||
TypeId::of::<FooInt>(),
|
||||
TypeId::of::<FooUint>(),
|
||||
TypeId::of::<FooFloat>(),
|
||||
TypeId::of::<FooStr>(),
|
||||
TypeId::of::<FooArray>(),
|
||||
TypeId::of::<FooSlice>(),
|
||||
TypeId::of::<FooBox>(),
|
||||
TypeId::of::<FooPtr>(),
|
||||
TypeId::of::<FooRef>(),
|
||||
TypeId::of::<FooFnPtr>(),
|
||||
TypeId::of::<FooNil>(),
|
||||
TypeId::of::<FooTuple>(),
|
||||
TypeId::of::<FooTrait>(),
|
||||
TypeId::of::<FooStruct>(),
|
||||
TypeId::of::<FooEnum>()
|
||||
]
|
||||
}
|
||||
|
||||
// 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 TySlice
|
||||
pub type FooSlice = [u8];
|
||||
|
||||
// Tests TyBox (of u8)
|
||||
pub type FooUniq = Box<u8>;
|
||||
|
||||
// As with TyStr, what type should be used for TyArray?
|
||||
pub type FooBox = Box<u8>;
|
||||
|
||||
// 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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<T>(x: isize) -> isize { x * 2 }
|
||||
fn bar<T>(x: isize) -> isize { x * 4 }
|
||||
|
||||
fn eq<T>(x: T, y: T) { }
|
||||
|
||||
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
|
||||
trait Foo { fn foo() { /* this is a default fn */ } }
|
||||
impl<T> Foo for T { /* `foo` is still default here */ }
|
||||
|
||||
eq(foo, bar);
|
||||
fn main() {
|
||||
eq(foo::<u8>, bar::<u8>);
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `fn(isize) -> isize {foo}`
|
||||
//~| found `fn(isize) -> isize {bar}`
|
||||
//~| expected `fn(isize) -> isize {foo::<u8>}`
|
||||
//~| found `fn(isize) -> isize {bar::<u8>}`
|
||||
//~| expected fn item
|
||||
//~| found a different fn item
|
||||
|
||||
eq(foo::<u8>, foo::<i8>);
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `fn(isize) -> isize {foo::<u8>}`
|
||||
//~| found `fn(isize) -> isize {foo::<i8>}`
|
||||
|
||||
eq(bar::<String>, bar::<Vec<u8>>);
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `fn(isize) -> isize {bar::<collections::string::String>}`
|
||||
//~| found `fn(isize) -> isize {bar::<collections::vec::Vec<u8>>}`
|
||||
//~| expected struct `collections::string::String`
|
||||
//~| found struct `collections::vec::Vec`
|
||||
|
||||
// Make sure we distinguish between trait methods correctly.
|
||||
eq(<u8 as Foo>::foo, <u16 as Foo>::foo);
|
||||
//~^ ERROR mismatched types
|
||||
//~| expected `fn() {Foo::foo}`
|
||||
//~| found `fn() {Foo::foo}`
|
||||
}
|
||||
|
|
|
|||
16
src/test/compile-fail/invalid-intrinsic.rs
Normal file
16
src/test/compile-fail/invalid-intrinsic.rs
Normal file
|
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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(); } }
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,5 +21,5 @@ impl<A> vec_monad<A> for Vec<A> {
|
|||
}
|
||||
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
|
||||
}
|
||||
|
|
|
|||
51
src/test/compile-fail/transmute-from-fn-item-types-lint.rs
Normal file
51
src/test/compile-fail/transmute-from-fn-item-types-lint.rs
Normal file
|
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<fn()>) {
|
||||
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::<fn(), usize>(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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue