}
}
- /// Returns `true` if `self` is positive, including `+0.0` and
- /// `Float::infinity()`.
+ /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
+ /// positive sign bit and positive infinity.
#[inline]
fn is_sign_positive(self) -> bool {
- self > 0.0 || (1.0 / self) == INFINITY
+ !self.is_sign_negative()
}
- /// Returns `true` if `self` is negative, including `-0.0` and
- /// `Float::neg_infinity()`.
+ /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
+ /// negative sign bit and negative infinity.
#[inline]
fn is_sign_negative(self) -> bool {
- self < 0.0 || (1.0 / self) == NEG_INFINITY
+ // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus
+ // applies to zeros and NaNs as well.
+ #[repr(C)]
+ union F32Bytes {
+ f: f32,
+ b: u32
+ }
+ unsafe { F32Bytes { f: self }.b & 0x8000_0000 != 0 }
}
/// Returns the reciprocal (multiplicative inverse) of the number.
}
}
- /// Returns `true` if `self` is positive, including `+0.0` and
- /// `Float::infinity()`.
+ /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
+ /// positive sign bit and positive infinity.
#[inline]
fn is_sign_positive(self) -> bool {
- self > 0.0 || (1.0 / self) == INFINITY
+ !self.is_sign_negative()
}
- /// Returns `true` if `self` is negative, including `-0.0` and
- /// `Float::neg_infinity()`.
+ /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
+ /// negative sign bit and negative infinity.
#[inline]
fn is_sign_negative(self) -> bool {
- self < 0.0 || (1.0 / self) == NEG_INFINITY
+ #[repr(C)]
+ union F64Bytes {
+ f: f64,
+ b: u64
+ }
+ unsafe { F64Bytes { f: self }.b & 0x8000_0000_0000_0000 != 0 }
}
/// Returns the reciprocal (multiplicative inverse) of the number.
region.hash_stable(hcx, hasher);
pointee_ty.hash_stable(hcx, hasher);
}
- TyFnDef(def_id, substs, ref sig) => {
+ TyFnDef(def_id, substs) => {
def_id.hash_stable(hcx, hasher);
substs.hash_stable(hcx, hasher);
- sig.hash_stable(hcx, hasher);
}
TyFnPtr(ref sig) => {
sig.hash_stable(hcx, hasher);
Some(self.tcx.closure_kind(def_id))
}
- pub fn closure_type(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
+ /// Obtain the signature of a function or closure.
+ /// For closures, unlike `tcx.fn_sig(def_id)`, this method will
+ /// work during the type-checking of the enclosing function and
+ /// return the closure signature in its partially inferred state.
+ pub fn fn_sig(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
if let Some(tables) = self.in_progress_tables {
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
if let Some(&ty) = tables.borrow().closure_tys.get(&id) {
}
}
- self.tcx.closure_type(def_id)
+ self.tcx.fn_sig(def_id)
}
}
//! `unsafe`.
use self::RootUnsafeContext::*;
-use ty::{self, Ty, TyCtxt};
+use ty::{self, TyCtxt};
use lint;
use syntax::ast;
UnsafeBlock(ast::NodeId),
}
-fn type_is_unsafe_function(ty: Ty) -> bool {
- match ty.sty {
- ty::TyFnDef(.., f) |
- ty::TyFnPtr(f) => f.unsafety() == hir::Unsafety::Unsafe,
- _ => false,
- }
-}
-
struct EffectCheckVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
match expr.node {
hir::ExprMethodCall(..) => {
let def_id = self.tables.type_dependent_defs[&expr.id].def_id();
- let base_type = self.tcx.type_of(def_id);
- debug!("effect: method call case, base type is {:?}",
- base_type);
- if type_is_unsafe_function(base_type) {
+ let sig = self.tcx.fn_sig(def_id);
+ debug!("effect: method call case, signature is {:?}",
+ sig);
+
+ if sig.0.unsafety == hir::Unsafety::Unsafe {
self.require_unsafe(expr.span,
"invocation of unsafe method")
}
let base_type = self.tables.expr_ty_adjusted(base);
debug!("effect: call case, base type is {:?}",
base_type);
- if type_is_unsafe_function(base_type) {
- self.require_unsafe(expr.span, "call to unsafe function")
+ match base_type.sty {
+ ty::TyFnDef(..) | ty::TyFnPtr(_) => {
+ if base_type.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
+ self.require_unsafe(expr.span, "call to unsafe function")
+ }
+ }
+ _ => {}
}
}
hir::ExprUnary(hir::UnDeref, ref base) => {
impl<'a, 'tcx> ExprVisitor<'a, 'tcx> {
fn def_id_is_transmute(&self, def_id: DefId) -> bool {
- let intrinsic = match self.tcx.type_of(def_id).sty {
- ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic,
- _ => return false
- };
- intrinsic && self.tcx.item_name(def_id) == "transmute"
+ self.tcx.fn_sig(def_id).abi() == RustIntrinsic &&
+ self.tcx.item_name(def_id) == "transmute"
}
fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
} else {
Def::Err
};
- match def {
- Def::Fn(did) if self.def_id_is_transmute(did) => {
+ if let Def::Fn(did) = def {
+ if self.def_id_is_transmute(did) {
let typ = self.tables.node_id_to_type(expr.id);
- let typ = self.tcx.lift_to_global(&typ).unwrap();
- match typ.sty {
- ty::TyFnDef(.., sig) if sig.abi() == RustIntrinsic => {
- let from = sig.inputs().skip_binder()[0];
- let to = *sig.output().skip_binder();
- self.check_transmute(expr.span, from, to);
- }
- _ => {
- span_bug!(expr.span, "transmute wasn't a bare fn?!");
- }
- }
+ let sig = typ.fn_sig(self.tcx);
+ let from = sig.inputs().skip_binder()[0];
+ let to = *sig.output().skip_binder();
+ self.check_transmute(expr.span, from, to);
}
- _ => {}
}
intravisit::walk_expr(self, expr);
// The `Self` type is erased, so it should not appear in list of
// arguments or return type apart from the receiver.
- let ref sig = self.type_of(method.def_id).fn_sig();
+ let ref sig = self.fn_sig(method.def_id);
for input_ty in &sig.skip_binder().inputs()[1..] {
if self.contains_illegal_self_type_reference(trait_def_id, input_ty) {
return Some(MethodViolationCode::ReferencesSelf);
-> Progress<'tcx>
{
let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty);
- let sig = fn_type.fn_sig();
+ let sig = fn_type.fn_sig(selcx.tcx());
+ let Normalized {
+ value: sig,
+ obligations
+ } = normalize_with_depth(selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth+1,
+ &sig);
+
confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
.with_addl_obligations(fn_pointer_vtable.nested)
+ .with_addl_obligations(obligations)
}
fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
-> Progress<'tcx>
{
let closure_typer = selcx.closure_typer();
- let closure_type = closure_typer.closure_type(vtable.closure_def_id)
+ let closure_type = closure_typer.fn_sig(vtable.closure_def_id)
.subst(selcx.tcx(), vtable.substs.substs);
let Normalized {
value: closure_type,
}
// provide an impl, but only for suitable `fn` pointers
- ty::TyFnDef(.., ty::Binder(ty::FnSig {
- unsafety: hir::Unsafety::Normal,
- abi: Abi::Rust,
- variadic: false,
- ..
- })) |
- ty::TyFnPtr(ty::Binder(ty::FnSig {
- unsafety: hir::Unsafety::Normal,
- abi: Abi::Rust,
- variadic: false,
- ..
- })) => {
- candidates.vec.push(FnPointerCandidate);
+ ty::TyFnDef(..) | ty::TyFnPtr(_) => {
+ if let ty::Binder(ty::FnSig {
+ unsafety: hir::Unsafety::Normal,
+ abi: Abi::Rust,
+ variadic: false,
+ ..
+ }) = self_ty.fn_sig(self.tcx()) {
+ candidates.vec.push(FnPointerCandidate);
+ }
}
_ => { }
// ok to skip binder; it is reintroduced below
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
- let sig = self_ty.fn_sig();
+ let sig = self_ty.fn_sig(self.tcx());
let trait_ref =
self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(),
self_ty,
util::TupleArgumentsFlag::Yes)
.map_bound(|(trait_ref, _)| trait_ref);
+ let Normalized { value: trait_ref, obligations } =
+ project::normalize_with_depth(self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ &trait_ref);
+
self.confirm_poly_trait_refs(obligation.cause.clone(),
obligation.param_env,
obligation.predicate.to_poly_trait_ref(),
trait_ref)?;
- Ok(VtableFnPointerData { fn_ty: self_ty, nested: vec![] })
+ Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations })
}
fn confirm_closure_candidate(&mut self,
substs: ty::ClosureSubsts<'tcx>)
-> ty::PolyTraitRef<'tcx>
{
- let closure_type = self.infcx.closure_type(closure_def_id)
+ let closure_type = self.infcx.fn_sig(closure_def_id)
.subst(self.tcx(), substs.substs);
let ty::Binder((trait_ref, _)) =
self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(),
}
pub fn mk_fn_def(self, def_id: DefId,
- substs: &'tcx Substs<'tcx>,
- fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
- self.mk_ty(TyFnDef(def_id, substs, fty))
+ substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
+ self.mk_ty(TyFnDef(def_id, substs))
}
pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
// view of possibly unifying
simplify_type(tcx, mt.ty, can_simplify_params)
}
+ ty::TyFnDef(def_id, _) |
ty::TyClosure(def_id, _) => {
Some(ClosureSimplifiedType(def_id))
}
ty::TyTuple(ref tys, _) => {
Some(TupleSimplifiedType(tys.len()))
}
- ty::TyFnDef(.., ref f) | ty::TyFnPtr(ref f) => {
+ ty::TyFnPtr(ref f) => {
Some(FunctionSimplifiedType(f.skip_binder().inputs().len()))
}
ty::TyProjection(_) | ty::TyParam(_) => {
self.add_tys(&ts[..]);
}
- &ty::TyFnDef(_, substs, f) => {
+ &ty::TyFnDef(_, substs) => {
self.add_substs(substs);
- self.add_fn_sig(f);
}
&ty::TyFnPtr(f) => {
.filter_map(|ty| characteristic_def_id_of_type(ty))
.next(),
- ty::TyFnDef(def_id, ..) |
+ ty::TyFnDef(def_id, _) |
ty::TyClosure(def_id, _) => Some(def_id),
ty::TyBool |
/// for trans. This is also the only query that can fetch non-local MIR, at present.
[] optimized_mir: Mir(DefId) -> &'tcx mir::Mir<'tcx>,
- /// Records the type of each closure. The def ID is the ID of the
+ /// Type of each closure. The def ID is the ID of the
/// expression defining the closure.
[] closure_kind: ItemSignature(DefId) -> ty::ClosureKind,
- /// Records the type of each closure. The def ID is the ID of the
- /// expression defining the closure.
- [] closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>,
+ /// The signature of functions and closures.
+ [] fn_sig: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>,
/// Caches CoerceUnsized kinds for impls on custom types.
[] coerce_unsized_info: ItemSignature(DefId)
// late-bound regions, and we don't want method signatures to show up
// `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
// regions just fine, showing `fn(&MyType)`.
- format!("{}", tcx.type_of(self.def_id).fn_sig().skip_binder())
+ format!("{}", tcx.fn_sig(self.def_id).skip_binder())
}
ty::AssociatedKind::Type => format!("type {};", self.name.to_string()),
ty::AssociatedKind::Const => {
if a.def_id != b.def_id {
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
} else {
- let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?;
+ let substs = relate_substs(relation, None, a.substs, b.substs)?;
Ok(ty::TraitRef { def_id: a.def_id, substs: substs })
}
}
if a.def_id != b.def_id {
Err(TypeError::Traits(expected_found(relation, &a.def_id, &b.def_id)))
} else {
- let substs = relation.relate_item_substs(a.def_id, a.substs, b.substs)?;
+ let substs = relate_substs(relation, None, a.substs, b.substs)?;
Ok(ty::ExistentialTraitRef { def_id: a.def_id, substs: substs })
}
}
}
}
- (&ty::TyFnDef(a_def_id, a_substs, a_fty),
- &ty::TyFnDef(b_def_id, b_substs, b_fty))
+ (&ty::TyFnDef(a_def_id, a_substs), &ty::TyFnDef(b_def_id, b_substs))
if a_def_id == b_def_id =>
{
- let substs = relate_substs(relation, None, a_substs, b_substs)?;
- let fty = relation.relate(&a_fty, &b_fty)?;
- Ok(tcx.mk_fn_def(a_def_id, substs, fty))
+ let substs = relation.relate_item_substs(a_def_id, a_substs, b_substs)?;
+ Ok(tcx.mk_fn_def(a_def_id, substs))
}
(&ty::TyFnPtr(a_fty), &ty::TyFnPtr(b_fty)) =>
ty::TyDynamic(ref trait_ty, ref region) =>
ty::TyDynamic(trait_ty.fold_with(folder), region.fold_with(folder)),
ty::TyTuple(ts, defaulted) => ty::TyTuple(ts.fold_with(folder), defaulted),
- ty::TyFnDef(def_id, substs, f) => {
- ty::TyFnDef(def_id,
- substs.fold_with(folder),
- f.fold_with(folder))
+ ty::TyFnDef(def_id, substs) => {
+ ty::TyFnDef(def_id, substs.fold_with(folder))
}
ty::TyFnPtr(f) => ty::TyFnPtr(f.fold_with(folder)),
ty::TyRef(ref r, tm) => {
ty::TyDynamic(ref trait_ty, ref reg) =>
trait_ty.visit_with(visitor) || reg.visit_with(visitor),
ty::TyTuple(ts, _) => ts.visit_with(visitor),
- ty::TyFnDef(_, substs, ref f) => {
- substs.visit_with(visitor) || f.visit_with(visitor)
- }
+ ty::TyFnDef(_, substs) => substs.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::TyClosure(_did, ref substs) => substs.visit_with(visitor),
use hir::map::DefPathHash;
use middle::region;
-use ty::subst::Substs;
+use ty::subst::{Substs, Subst};
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
use ty::{Slice, TyS};
use ty::subst::Kind;
/// The anonymous type of a function declaration/definition. Each
/// function has a unique type.
- TyFnDef(DefId, &'tcx Substs<'tcx>, PolyFnSig<'tcx>),
+ TyFnDef(DefId, &'tcx Substs<'tcx>),
/// A pointer to a function. Written as `fn() -> i32`.
TyFnPtr(PolyFnSig<'tcx>),
}
}
- pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
+ pub fn fn_sig(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> PolyFnSig<'tcx> {
match self.sty {
- TyFnDef(.., f) | TyFnPtr(f) => f,
+ TyFnDef(def_id, substs) => {
+ tcx.fn_sig(def_id).subst(tcx, substs)
+ }
+ TyFnPtr(f) => f,
_ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self)
}
}
TyRef(_, m) => self.hash(m.mutbl),
TyClosure(def_id, _) |
TyAnon(def_id, _) |
- TyFnDef(def_id, ..) => self.def_id(def_id),
+ TyFnDef(def_id, _) => self.def_id(def_id),
TyAdt(d, _) => self.def_id(d.did),
TyFnPtr(f) => {
self.hash(f.unsafety());
ty::TyTuple(ts, _) => {
stack.extend(ts.iter().cloned().rev());
}
- ty::TyFnDef(_, substs, ft) => {
+ ty::TyFnDef(_, substs) => {
stack.extend(substs.types().rev());
- push_sig_subtypes(stack, ft);
}
ty::TyFnPtr(ft) => {
push_sig_subtypes(stack, ft);
}
write!(f, ")")
}
- TyFnDef(def_id, substs, ref bare_fn) => {
- write!(f, "{} {{", bare_fn.0)?;
+ TyFnDef(def_id, substs) => {
+ ty::tls::with(|tcx| {
+ let mut sig = tcx.fn_sig(def_id);
+ if let Some(substs) = tcx.lift(&substs) {
+ sig = sig.subst(tcx, substs);
+ }
+ write!(f, "{} {{", sig.0)
+ })?;
parameterized(f, substs, def_id, &[])?;
write!(f, "}}")
}
terminator: &'a Option<mir::Terminator<'tcx>>)
-> Option<(&'a [mir::Operand<'tcx>], Span)> {
if let Some(mir::Terminator { ref kind, source_info, .. }) = *terminator {
- if let mir::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind
- {
- if let mir::Operand::Constant(ref func) = *oper
- {
- if let ty::TyFnDef(def_id, _, sig) = func.ty.sty
- {
- let abi = sig.abi();
+ if let mir::TerminatorKind::Call { func: ref oper, ref args, .. } = *kind {
+ if let mir::Operand::Constant(ref func) = *oper {
+ if let ty::TyFnDef(def_id, _) = func.ty.sty {
+ let abi = tcx.fn_sig(def_id).abi();
let name = tcx.item_name(def_id);
- if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
- if name == "rustc_peek" {
- return Some((args, source_info.span));
- }
+ if abi == Abi::RustIntrinsic && name == "rustc_peek" {
+ return Some((args, source_info.span));
}
}
}
use rustc::middle::const_val::{ConstEvalErr, ConstVal};
use rustc::mir::{Field, BorrowKind, Mutability};
-use rustc::ty::{self, TyCtxt, AdtDef, Ty, TypeVariants, Region};
+use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
use rustc::ty::subst::{Substs, Kind};
use rustc::hir::{self, PatKind, RangeEnd};
use rustc::hir::def::{Def, CtorKind};
let adt_def = self.tcx.adt_def(enum_id);
if adt_def.variants.len() > 1 {
let substs = match ty.sty {
- TypeVariants::TyAdt(_, substs) => substs,
- TypeVariants::TyFnDef(_, substs, _) => substs,
+ ty::TyAdt(_, substs) |
+ ty::TyFnDef(_, substs) => substs,
_ => bug!("inappropriate type for def: {:?}", ty.sty),
};
PatternKind::Variant {
if !def_id_is_transmute(cx, did) {
return None;
}
- let typ = cx.tables.node_id_to_type(expr.id);
- match typ.sty {
- ty::TyFnDef(.., bare_fn) if bare_fn.abi() == RustIntrinsic => {
- let from = bare_fn.inputs().skip_binder()[0];
- let to = *bare_fn.output().skip_binder();
- return Some((&from.sty, &to.sty));
- }
- _ => (),
- }
+ let sig = cx.tables.node_id_to_type(expr.id).fn_sig(cx.tcx);
+ let from = sig.inputs().skip_binder()[0];
+ let to = *sig.output().skip_binder();
+ return Some((&from.sty, &to.sty));
}
None
}
fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
- match cx.tcx.type_of(def_id).sty {
- ty::TyFnDef(.., bfty) if bfty.abi() == RustIntrinsic => (),
- _ => return false,
- }
+ cx.tcx.fn_sig(def_id).abi() == RustIntrinsic &&
cx.tcx.item_name(def_id) == "transmute"
}
}
fn check_foreign_fn(&mut self, id: ast::NodeId, decl: &hir::FnDecl) {
let def_id = self.cx.tcx.hir.local_def_id(id);
- let sig = self.cx.tcx.type_of(def_id).fn_sig();
+ let sig = self.cx.tcx.fn_sig(def_id);
let sig = self.cx.tcx.erase_late_bound_regions(&sig);
for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) {
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
typeck_tables_of => { cdata.item_body_tables(def_id.index, tcx) }
closure_kind => { cdata.closure_kind(def_id.index) }
- closure_type => { cdata.closure_ty(def_id.index, tcx) }
+ fn_sig => { cdata.fn_sig(def_id.index, tcx) }
inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
is_const_fn => { cdata.is_const_fn(def_id.index) }
is_foreign_item => { cdata.is_foreign_item(def_id.index) }
}
}
- pub fn closure_ty(&self,
- closure_id: DefIndex,
- tcx: TyCtxt<'a, 'tcx, 'tcx>)
- -> ty::PolyFnSig<'tcx> {
- match self.entry(closure_id).kind {
- EntryKind::Closure(data) => data.decode(self).ty.decode((self, tcx)),
+ pub fn fn_sig(&self,
+ id: DefIndex,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>)
+ -> ty::PolyFnSig<'tcx> {
+ let sig = match self.entry(id).kind {
+ EntryKind::Fn(data) |
+ EntryKind::ForeignFn(data) => data.decode(self).sig,
+ EntryKind::Method(data) => data.decode(self).fn_data.sig,
+ EntryKind::Variant(data) |
+ EntryKind::Struct(data, _) => data.decode(self).ctor_sig.unwrap(),
+ EntryKind::Closure(data) => data.decode(self).sig,
_ => bug!(),
- }
+ };
+ sig.decode((self, tcx))
}
#[inline]
use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary,
EncodedMetadata, EncodedMetadataHashes,
EncodedMetadataHash};
+use rustc::hir::def::CtorKind;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LOCAL_CRATE};
use rustc::hir::map::definitions::{DefPathTable, GlobalMetaDataKind};
use rustc::ich::Fingerprint;
ctor_kind: variant.ctor_kind,
discr: variant.discr,
struct_ctor: None,
+ ctor_sig: if variant.ctor_kind == CtorKind::Fn {
+ Some(self.lazy(&tcx.fn_sig(def_id)))
+ } else {
+ None
+ }
};
let enum_id = tcx.hir.as_local_node_id(enum_did).unwrap();
ty: Some(self.encode_item_type(def_id)),
inherent_impls: LazySeq::empty(),
- variances: LazySeq::empty(),
+ variances: if variant.ctor_kind == CtorKind::Fn {
+ self.encode_variances_of(def_id)
+ } else {
+ LazySeq::empty()
+ },
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
ctor_kind: variant.ctor_kind,
discr: variant.discr,
struct_ctor: Some(def_id.index),
+ ctor_sig: if variant.ctor_kind == CtorKind::Fn {
+ Some(self.lazy(&tcx.fn_sig(def_id)))
+ } else {
+ None
+ }
};
let struct_id = tcx.hir.as_local_node_id(adt_def_id).unwrap();
ty: Some(self.encode_item_type(def_id)),
inherent_impls: LazySeq::empty(),
- variances: LazySeq::empty(),
+ variances: if variant.ctor_kind == CtorKind::Fn {
+ self.encode_variances_of(def_id)
+ } else {
+ LazySeq::empty()
+ },
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
};
FnData {
constness: hir::Constness::NotConst,
- arg_names: arg_names
+ arg_names: arg_names,
+ sig: self.lazy(&tcx.fn_sig(def_id)),
}
} else {
bug!()
}
},
inherent_impls: LazySeq::empty(),
- variances: LazySeq::empty(),
+ variances: if trait_item.kind == ty::AssociatedKind::Method {
+ self.encode_variances_of(def_id)
+ } else {
+ LazySeq::empty()
+ },
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
debug!("IsolatedEncoder::encode_info_for_impl_item({:?})", def_id);
+ let tcx = self.tcx;
+
let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
let ast_item = self.tcx.hir.expect_impl_item(node_id);
let impl_item = self.tcx.associated_item(def_id);
FnData {
constness: sig.constness,
arg_names: self.encode_fn_arg_names_for_body(body),
+ sig: self.lazy(&tcx.fn_sig(def_id)),
}
} else {
bug!()
ty: Some(self.encode_item_type(def_id)),
inherent_impls: LazySeq::empty(),
- variances: LazySeq::empty(),
+ variances: if impl_item.kind == ty::AssociatedKind::Method {
+ self.encode_variances_of(def_id)
+ } else {
+ LazySeq::empty()
+ },
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
let data = FnData {
constness: constness,
arg_names: self.encode_fn_arg_names_for_body(body),
+ sig: self.lazy(&tcx.fn_sig(def_id)),
};
EntryKind::Fn(self.lazy(&data))
ctor_kind: variant.ctor_kind,
discr: variant.discr,
struct_ctor: struct_ctor,
+ ctor_sig: None,
}), repr_options)
}
hir::ItemUnion(..) => {
ctor_kind: variant.ctor_kind,
discr: variant.discr,
struct_ctor: None,
+ ctor_sig: None,
}), repr_options)
}
hir::ItemDefaultImpl(..) => {
hir::ItemEnum(..) |
hir::ItemStruct(..) |
hir::ItemUnion(..) |
- hir::ItemTrait(..) => self.encode_variances_of(def_id),
+ hir::ItemFn(..) => self.encode_variances_of(def_id),
_ => LazySeq::empty(),
},
generics: match item.node {
let data = ClosureData {
kind: tcx.closure_kind(def_id),
- ty: self.lazy(&tcx.closure_type(def_id)),
+ sig: self.lazy(&tcx.fn_sig(def_id)),
};
Entry {
let data = FnData {
constness: hir::Constness::NotConst,
arg_names: self.encode_fn_arg_names(names),
+ sig: self.lazy(&tcx.fn_sig(def_id)),
};
EntryKind::ForeignFn(self.lazy(&data))
}
ty: Some(self.encode_item_type(def_id)),
inherent_impls: LazySeq::empty(),
- variances: LazySeq::empty(),
+ variances: match nitem.node {
+ hir::ForeignItemFn(..) => self.encode_variances_of(def_id),
+ _ => LazySeq::empty(),
+ },
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
Type,
Enum(ReprOptions),
Field,
- Variant(Lazy<VariantData>),
- Struct(Lazy<VariantData>, ReprOptions),
- Union(Lazy<VariantData>, ReprOptions),
- Fn(Lazy<FnData>),
- ForeignFn(Lazy<FnData>),
+ Variant(Lazy<VariantData<'tcx>>),
+ Struct(Lazy<VariantData<'tcx>>, ReprOptions),
+ Union(Lazy<VariantData<'tcx>>, ReprOptions),
+ Fn(Lazy<FnData<'tcx>>),
+ ForeignFn(Lazy<FnData<'tcx>>),
Mod(Lazy<ModData>),
MacroDef(Lazy<MacroDef>),
Closure(Lazy<ClosureData<'tcx>>),
Trait(Lazy<TraitData<'tcx>>),
Impl(Lazy<ImplData<'tcx>>),
DefaultImpl(Lazy<ImplData<'tcx>>),
- Method(Lazy<MethodData>),
+ Method(Lazy<MethodData<'tcx>>),
AssociatedType(AssociatedContainer),
AssociatedConst(AssociatedContainer, u8),
}
impl_stable_hash_for!(struct MacroDef { body, legacy });
#[derive(RustcEncodable, RustcDecodable)]
-pub struct FnData {
+pub struct FnData<'tcx> {
pub constness: hir::Constness,
pub arg_names: LazySeq<ast::Name>,
+ pub sig: Lazy<ty::PolyFnSig<'tcx>>,
}
-impl_stable_hash_for!(struct FnData { constness, arg_names });
+impl_stable_hash_for!(struct FnData<'tcx> { constness, arg_names, sig });
#[derive(RustcEncodable, RustcDecodable)]
-pub struct VariantData {
+pub struct VariantData<'tcx> {
pub ctor_kind: CtorKind,
pub discr: ty::VariantDiscr,
/// If this is a struct's only variant, this
/// is the index of the "struct ctor" item.
pub struct_ctor: Option<DefIndex>,
+
+ /// If this is a tuple struct or variant
+ /// ctor, this is its "function" signature.
+ pub ctor_sig: Option<Lazy<ty::PolyFnSig<'tcx>>>,
}
-impl_stable_hash_for!(struct VariantData {
+impl_stable_hash_for!(struct VariantData<'tcx> {
ctor_kind,
discr,
- struct_ctor
+ struct_ctor,
+ ctor_sig
});
#[derive(RustcEncodable, RustcDecodable)]
}
#[derive(RustcEncodable, RustcDecodable)]
-pub struct MethodData {
- pub fn_data: FnData,
+pub struct MethodData<'tcx> {
+ pub fn_data: FnData<'tcx>,
pub container: AssociatedContainer,
pub has_self: bool,
}
-impl_stable_hash_for!(struct MethodData { fn_data, container, has_self });
+impl_stable_hash_for!(struct MethodData<'tcx> { fn_data, container, has_self });
#[derive(RustcEncodable, RustcDecodable)]
pub struct ClosureData<'tcx> {
pub kind: ty::ClosureKind,
- pub ty: Lazy<ty::PolyFnSig<'tcx>>,
+ pub sig: Lazy<ty::PolyFnSig<'tcx>>,
}
-impl_stable_hash_for!(struct ClosureData<'tcx> { kind, ty });
+impl_stable_hash_for!(struct ClosureData<'tcx> { kind, sig });
// FIXME(canndrew): This is_never should probably be an is_uninhabited
let diverges = expr.ty.is_never();
let intrinsic = match ty.sty {
- ty::TyFnDef(def_id, _, ref f) if
- f.abi() == Abi::RustIntrinsic ||
- f.abi() == Abi::PlatformIntrinsic =>
- {
- Some(this.hir.tcx().item_name(def_id).as_str())
+ ty::TyFnDef(def_id, _) => {
+ let f = ty.fn_sig(this.hir.tcx());
+ if f.abi() == Abi::RustIntrinsic ||
+ f.abi() == Abi::PlatformIntrinsic {
+ Some(this.hir.tcx().item_name(def_id).as_str())
+ } else {
+ None
+ }
}
_ => None
};
use rustc::ty::{self, AdtKind, VariantDef, Ty};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
use rustc::ty::cast::CastKind as TyCastKind;
-use rustc::ty::subst::Subst;
use rustc::hir;
impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
});
Expr {
temp_lifetime: temp_lifetime,
- ty: cx.tcx.type_of(def_id).subst(cx.tcx, substs),
+ ty: cx.tcx().mk_fn_def(def_id, substs),
span: expr.span,
kind: ExprKind::Literal {
literal: Literal::Value {
// types in the MIR. They will be substituted again with
// the param-substs, but because they are concrete, this
// will not do any harm.
- let sig = tcx.erase_late_bound_regions(&ty.fn_sig());
+ let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx));
let arg_tys = sig.inputs();
build_call_shim(
} else {
Substs::identity_for_item(tcx, def_id)
};
- let fn_ty = tcx.type_of(def_id).subst(tcx, substs);
- let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig());
+ let sig = tcx.fn_sig(def_id).subst(tcx, substs);
+ let sig = tcx.erase_late_bound_regions(&sig);
let span = tcx.def_span(def_id);
let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
call_kind={:?}, untuple_args={:?})",
def_id, rcvr_adjustment, call_kind, untuple_args);
- let fn_ty = tcx.type_of(def_id);
- let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig());
+ let sig = tcx.fn_sig(def_id);
+ let sig = tcx.erase_late_bound_regions(&sig);
let span = tcx.def_span(def_id);
debug!("build_call_shim: sig={:?}", sig);
{
let tcx = infcx.tcx;
let def_id = tcx.hir.local_def_id(ctor_id);
- let sig = match tcx.type_of(def_id).sty {
- ty::TyFnDef(_, _, fty) => tcx.no_late_bound_regions(&fty)
- .expect("LBR in ADT constructor signature"),
- _ => bug!("unexpected type for ctor {:?}", def_id)
- };
+ let sig = tcx.no_late_bound_regions(&tcx.fn_sig(def_id))
+ .expect("LBR in ADT constructor signature");
let sig = tcx.erase_regions(&sig);
let (adt_def, substs) = match sig.output().sty {
let terminator = bb_data.terminator();
if let TerminatorKind::Call {
func: Operand::Constant(ref f), .. } = terminator.kind {
- if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty {
+ if let ty::TyFnDef(callee_def_id, substs) = f.ty.sty {
callsites.push_back(CallSite {
callee: callee_def_id,
substs: substs,
let terminator = bb_data.terminator();
if let TerminatorKind::Call {
func: Operand::Constant(ref f), .. } = terminator.kind {
- if let ty::TyFnDef(callee_def_id, substs, _) = f.ty.sty {
+ if let ty::TyFnDef(callee_def_id, substs) = f.ty.sty {
// Don't inline the same function multiple times.
if callsite.callee != callee_def_id {
callsites.push_back(CallSite {
}
TerminatorKind::Call {func: Operand::Constant(ref f), .. } => {
- if let ty::TyFnDef(.., f) = f.ty.sty {
+ if let ty::TyFnDef(def_id, _) = f.ty.sty {
// Don't give intrinsics the extra penalty for calls
+ let f = tcx.fn_sig(def_id);
if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
cost += INSTR_COST;
} else {
let fn_ty = func.ty(self.mir, self.tcx);
let (is_shuffle, is_const_fn) = match fn_ty.sty {
- ty::TyFnDef(def_id, _, f) => {
- (f.abi() == Abi::PlatformIntrinsic &&
+ ty::TyFnDef(def_id, _) => {
+ (self.tcx.fn_sig(def_id).abi() == Abi::PlatformIntrinsic &&
self.tcx.item_name(def_id).as_str().starts_with("simd_shuffle"),
self.tcx.is_const_fn(def_id))
}
let func_ty = func.ty(mir, tcx);
debug!("check_terminator: call, func_ty={:?}", func_ty);
let sig = match func_ty.sty {
- ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => sig,
+ ty::TyFnDef(..) | ty::TyFnPtr(_) => func_ty.fn_sig(tcx),
_ => {
span_mirbug!(self, term, "call to non-function {:?}", func_ty);
return;
}
fn ty(&mut self) -> &mut Self {
- self.ev.tcx.type_of(self.item_def_id).visit_with(self);
+ let ty = self.ev.tcx.type_of(self.item_def_id);
+ ty.visit_with(self);
+ if let ty::TyFnDef(def_id, _) = ty.sty {
+ if def_id == self.item_def_id {
+ self.ev.tcx.fn_sig(def_id).visit_with(self);
+ }
+ }
self
}
}
fn ty(&mut self) -> &mut Self {
- self.tcx.type_of(self.item_def_id).visit_with(self);
+ let ty = self.tcx.type_of(self.item_def_id);
+ ty.visit_with(self);
+ if let ty::TyFnDef(def_id, _) = ty.sty {
+ if def_id == self.item_def_id {
+ self.tcx.fn_sig(def_id).visit_with(self);
+ }
+ }
self
}
assert!(!item_type.has_erasable_regions());
hasher.visit_ty(item_type);
+ // If this is a function, we hash the signature as well.
+ // This is not *strictly* needed, but it may help in some
+ // situations, see the `run-make/a-b-a-linker-guard` test.
+ if let ty::TyFnDef(..) = item_type.sty {
+ item_type.fn_sig(tcx).visit_with(&mut hasher);
+ }
+
// also include any type parameters (for generic items)
if let Some(substs) = substs {
assert!(!substs.has_erasable_regions());
is_direct_call: bool,
output: &mut Vec<TransItem<'tcx>>)
{
- if let ty::TyFnDef(def_id, substs, _) = ty.sty {
+ if let ty::TyFnDef(def_id, substs) = ty.sty {
let instance = monomorphize::resolve(scx, def_id, substs);
visit_instance_use(scx, instance, is_direct_call, output);
}
-> ty::PolyFnSig<'tcx>
{
match ty.sty {
- ty::TyFnDef(_, _, sig) => sig,
+ ty::TyFnDef(..) |
// Shims currently have type TyFnPtr. Not sure this should remain.
- ty::TyFnPtr(sig) => sig,
+ ty::TyFnPtr(_) => ty.fn_sig(ccx.tcx()),
ty::TyClosure(def_id, substs) => {
let tcx = ccx.tcx();
- let sig = tcx.closure_type(def_id).subst(tcx, substs.substs);
+ let sig = tcx.fn_sig(def_id).subst(tcx, substs.substs);
let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv);
let env_ty = match tcx.closure_kind(def_id) {
debug!("type_metadata: {:?}", t);
- let sty = &t.sty;
let ptr_metadata = |ty: Ty<'tcx>| {
match ty.sty {
ty::TySlice(typ) => {
}
};
- let MetadataCreationResult { metadata, already_stored_in_typemap } = match *sty {
+ let MetadataCreationResult { metadata, already_stored_in_typemap } = match t.sty {
ty::TyNever |
ty::TyBool |
ty::TyChar |
Err(metadata) => return metadata,
}
}
- ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => {
+ ty::TyFnDef(..) | ty::TyFnPtr(_) => {
let fn_metadata = subroutine_type_metadata(cx,
unique_type_id,
- sig,
+ t.fn_sig(cx.tcx()),
usage_site_span).metadata;
match debug_context(cx).type_map
.borrow()
usage_site_span).finalize(cx)
}
_ => {
- bug!("debuginfo: unexpected type in type_metadata: {:?}", sty)
+ bug!("debuginfo: unexpected type in type_metadata: {:?}", t)
}
};
push_type_params(cx, principal.substs, output);
}
},
- ty::TyFnDef(.., sig) |
- ty::TyFnPtr(sig) => {
+ ty::TyFnDef(..) | ty::TyFnPtr(_) => {
+ let sig = t.fn_sig(cx.tcx());
if sig.unsafety() == hir::Unsafety::Unsafe {
output.push_str("unsafe ");
}
let ccx = bcx.ccx;
let tcx = ccx.tcx();
- let (def_id, substs, sig) = match callee_ty.sty {
- ty::TyFnDef(def_id, substs, sig) => (def_id, substs, sig),
+ let (def_id, substs) = match callee_ty.sty {
+ ty::TyFnDef(def_id, substs) => (def_id, substs),
_ => bug!("expected fn item type, found {}", callee_ty)
};
+ let sig = callee_ty.fn_sig(tcx);
let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
let arg_tys = sig.inputs();
let ret_ty = sig.output();
let tcx = bcx.tcx();
- let sig = tcx.erase_late_bound_regions_and_normalize(&callee_ty.fn_sig());
+ let sig = tcx.erase_late_bound_regions_and_normalize(&callee_ty.fn_sig(tcx));
let arg_tys = sig.inputs();
// every intrinsic takes a SIMD vector as its first argument
// 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 (instance, mut llfn, sig) = match callee.ty.sty {
- ty::TyFnDef(def_id, substs, sig) => {
+ let (instance, mut llfn) = match callee.ty.sty {
+ ty::TyFnDef(def_id, substs) => {
(Some(monomorphize::resolve(bcx.ccx.shared(), def_id, substs)),
- None,
- sig)
+ None)
}
- ty::TyFnPtr(sig) => {
- (None,
- Some(callee.immediate()),
- sig)
+ ty::TyFnPtr(_) => {
+ (None, Some(callee.immediate()))
}
_ => bug!("{} is not callable", callee.ty)
};
let def = instance.map(|i| i.def);
+ let sig = callee.ty.fn_sig(bcx.tcx());
let sig = bcx.tcx().erase_late_bound_regions_and_normalize(&sig);
let abi = sig.abi;
let fn_ty = func.ty(self.mir, tcx);
let fn_ty = self.monomorphize(&fn_ty);
let (def_id, substs) = match fn_ty.sty {
- ty::TyFnDef(def_id, substs, _) => (def_id, substs),
+ ty::TyFnDef(def_id, substs) => (def_id, substs),
_ => span_bug!(span, "calling {:?} (of type {}) in constant",
func, fn_ty)
};
let val = match *kind {
mir::CastKind::ReifyFnPointer => {
match operand.ty.sty {
- ty::TyFnDef(def_id, substs, _) => {
+ ty::TyFnDef(def_id, substs) => {
callee::resolve_and_get_fn(self.ccx, def_id, substs)
}
_ => {
.find(|it| it.kind == ty::AssociatedKind::Method)
.unwrap().def_id;
// Now create its substs [Closure, Tuple]
- let input = tcx.closure_type(def_id)
+ let input = tcx.fn_sig(def_id)
.subst(tcx, substs.substs).input(0);
let input = tcx.erase_late_bound_regions_and_normalize(&input);
let substs = tcx.mk_substs([operand.ty, input]
let val = match *kind {
mir::CastKind::ReifyFnPointer => {
match operand.ty.sty {
- ty::TyFnDef(def_id, substs, _) => {
+ ty::TyFnDef(def_id, substs) => {
OperandValue::Immediate(
callee::resolve_and_get_fn(bcx.ccx, def_id, substs))
}
let self_ty = tcx.mk_closure_from_closure_substs(
closure_did, substs);
- let sig = tcx.closure_type(closure_did).subst(tcx, substs.substs);
+ let sig = tcx.fn_sig(closure_did).subst(tcx, substs.substs);
let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
assert_eq!(sig.inputs().len(), 1);
let substs = tcx.mk_substs([
} else {
let item_type = def_ty(scx, def_id, substs);
let def = match item_type.sty {
- ty::TyFnDef(_, _, f) if
- f.abi() == Abi::RustIntrinsic ||
- f.abi() == Abi::PlatformIntrinsic =>
+ ty::TyFnDef(..) if {
+ let f = item_type.fn_sig(scx.tcx());
+ f.abi() == Abi::RustIntrinsic ||
+ f.abi() == Abi::PlatformIntrinsic
+ } =>
{
debug!(" => intrinsic");
ty::InstanceDef::Intrinsic(def_id)
output);
}
},
- ty::TyFnDef(.., sig) |
- ty::TyFnPtr(sig) => {
+ ty::TyFnDef(..) |
+ ty::TyFnPtr(_) => {
+ let sig = t.fn_sig(self.tcx);
if sig.unsafety() == hir::Unsafety::Unsafe {
output.push_str("unsafe ");
}
// Type check the path.
let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
// Replace constructor type with constructed type for tuple struct patterns.
- let pat_ty = pat_ty.fn_sig().output();
+ let pat_ty = pat_ty.fn_sig(tcx).output();
let pat_ty = tcx.no_late_bound_regions(&pat_ty).expect("expected fn type");
self.demand_eqtype(pat.span, expected, pat_ty);
// haven't yet decided on whether the closure is fn vs
// fnmut vs fnonce. If so, we have to defer further processing.
if self.closure_kind(def_id).is_none() {
- let closure_ty = self.closure_type(def_id).subst(self.tcx, substs.substs);
+ let closure_ty = self.fn_sig(def_id).subst(self.tcx, substs.substs);
let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span,
infer::FnCall,
&closure_ty)
expected: Expectation<'tcx>)
-> Ty<'tcx> {
let (fn_sig, def_span) = match callee_ty.sty {
- ty::TyFnDef(def_id, .., sig) => {
- (sig, self.tcx.hir.span_if_local(def_id))
+ ty::TyFnDef(def_id, _) => {
+ (callee_ty.fn_sig(self.tcx), self.tcx.hir.span_if_local(def_id))
}
ty::TyFnPtr(sig) => (sig, None),
ref t => {
(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 {
+ if let ty::TyFnDef(..) = self.expr_ty.sty {
// Attempt a coercion to a fn pointer type.
+ let f = self.expr_ty.fn_sig(fcx.tcx);
let res = fcx.try_coerce(self.expr,
self.expr_ty,
self.expr_diverges,
}
match a.sty {
- ty::TyFnDef(.., a_f) => {
+ ty::TyFnDef(..) => {
// Function items are coercible to any closure
// type; function pointers are not (that would
// require double indirection).
// Additionally, we permit coercion of function
// items to drop the unsafe qualifier.
- self.coerce_from_fn_item(a, a_f, b)
+ self.coerce_from_fn_item(a, b)
}
ty::TyFnPtr(a_f) => {
// We permit coercion of fn pointers to drop the
fn coerce_from_fn_item(&self,
a: Ty<'tcx>,
- fn_ty_a: ty::PolyFnSig<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx> {
//! Attempts to coerce from the type of a Rust function item
match b.sty {
ty::TyFnPtr(_) => {
- let a_fn_pointer = self.tcx.mk_fn_ptr(fn_ty_a);
- self.coerce_from_safe_fn(a_fn_pointer, fn_ty_a, b,
- simple(Adjust::ReifyFnPointer), simple(Adjust::ReifyFnPointer))
+ let a_sig = a.fn_sig(self.tcx);
+ let InferOk { value: a_sig, mut obligations } =
+ self.normalize_associated_types_in_as_infer_ok(self.cause.span, &a_sig);
+
+ let a_fn_pointer = self.tcx.mk_fn_ptr(a_sig);
+ let InferOk { value, obligations: o2 } =
+ self.coerce_from_safe_fn(a_fn_pointer, a_sig, b,
+ simple(Adjust::ReifyFnPointer), simple(Adjust::ReifyFnPointer))?;
+
+ obligations.extend(o2);
+ Ok(InferOk { value, obligations })
}
_ => self.unify_and(a, b, identity),
}
// `extern "rust-call" fn((arg0,arg1,...)) -> _`
// to
// `fn(arg0,arg1,...) -> _`
- let sig = self.closure_type(def_id_a).subst(self.tcx, substs_a.substs);
+ let sig = self.fn_sig(def_id_a).subst(self.tcx, substs_a.substs);
let converted_sig = sig.map_bound(|s| {
let params_iter = match s.inputs()[0].sty {
ty::TyTuple(params, _) => {
// 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 = self.at(cause, self.param_env)
- .trace(prev_ty, new_ty)
- .lub(&a_fty, &b_fty)
- .map(|ok| self.register_infer_ok_obligations(ok))?;
-
- if a_def_id == b_def_id {
- // Same function, maybe the parameters match.
- let substs = self.commit_if_ok(|_| {
- self.at(cause, self.param_env)
- .trace(prev_ty, new_ty)
- .lub(&a_substs, &b_substs)
- .map(|ok| self.register_infer_ok_obligations(ok))
- });
-
- if let Ok(substs) = substs {
- // We have a LUB of prev_ty and new_ty, just return it.
- return Ok(self.tcx.mk_fn_def(a_def_id, substs, fty));
- }
- }
+ if let (&ty::TyFnDef(..), &ty::TyFnDef(..)) = (&prev_ty.sty, &new_ty.sty) {
+ // Don't reify if the function types have a LUB, i.e. they
+ // are the same function and their parameters have a LUB.
+ let lub_ty = self.commit_if_ok(|_| {
+ self.at(cause, self.param_env)
+ .lub(prev_ty, new_ty)
+ .map(|ok| self.register_infer_ok_obligations(ok))
+ });
+
+ if lub_ty.is_ok() {
+ // We have a LUB of prev_ty and new_ty, just return it.
+ return lub_ty;
+ }
- // Reify both sides and return the reified fn pointer type.
- let fn_ptr = self.tcx.mk_fn_ptr(fty);
- for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) {
- // The only adjustment that can produce an fn item is
- // `NeverToAny`, so this should always be valid.
- self.apply_adjustments(expr, vec![Adjustment {
- kind: Adjust::ReifyFnPointer,
- target: fn_ptr
- }]);
- }
- return Ok(fn_ptr);
+ // The signature must match.
+ let a_sig = prev_ty.fn_sig(self.tcx);
+ let a_sig = self.normalize_associated_types_in(new.span, &a_sig);
+ let b_sig = new_ty.fn_sig(self.tcx);
+ let b_sig = self.normalize_associated_types_in(new.span, &b_sig);
+ let sig = self.at(cause, self.param_env)
+ .trace(prev_ty, new_ty)
+ .lub(&a_sig, &b_sig)
+ .map(|ok| self.register_infer_ok_obligations(ok))?;
+
+ // Reify both sides and return the reified fn pointer type.
+ let fn_ptr = self.tcx.mk_fn_ptr(sig);
+ for expr in exprs.iter().map(|e| e.as_coercion_site()).chain(Some(new)) {
+ // The only adjustment that can produce an fn item is
+ // `NeverToAny`, so this should always be valid.
+ self.apply_adjustments(expr, vec![Adjustment {
+ kind: Adjust::ReifyFnPointer,
+ target: fn_ptr
+ }]);
}
- _ => {}
+ return Ok(fn_ptr);
}
let mut coerce = Coerce::new(self, cause.clone());
// Compute skolemized form of impl and trait method tys.
let tcx = infcx.tcx;
- let m_sig = |method: &ty::AssociatedItem| {
- match tcx.type_of(method.def_id).sty {
- ty::TyFnDef(_, _, f) => f,
- _ => bug!()
- }
- };
-
let (impl_sig, _) =
infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
infer::HigherRankedType,
- &m_sig(impl_m));
+ &tcx.fn_sig(impl_m.def_id));
let impl_sig =
inh.normalize_associated_types_in(impl_m_span,
impl_m_node_id,
let trait_sig = inh.liberate_late_bound_regions(
impl_m.def_id,
- &m_sig(trait_m));
+ &tcx.fn_sig(trait_m.def_id));
let trait_sig =
trait_sig.subst(tcx, trait_to_skol_substs);
let trait_sig =
ty::ImplContainer(_) => impl_trait_ref.self_ty(),
ty::TraitContainer(_) => tcx.mk_self_type()
};
- let method_ty = tcx.type_of(method.def_id);
- let self_arg_ty = *method_ty.fn_sig().input(0).skip_binder();
+ let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder();
match ExplicitSelf::determine(untransformed_self_ty, self_arg_ty) {
ExplicitSelf::ByValue => "self".to_string(),
ExplicitSelf::ByReference(_, hir::MutImmutable) => "&self".to_string(),
trait_m: &ty::AssociatedItem,
trait_item_span: Option<Span>)
-> Result<(), ErrorReported> {
- let m_fty = |method: &ty::AssociatedItem| {
- match tcx.type_of(method.def_id).sty {
- ty::TyFnDef(_, _, f) => f,
- _ => bug!()
- }
- };
- let impl_m_fty = m_fty(impl_m);
- let trait_m_fty = m_fty(trait_m);
+ let impl_m_fty = tcx.fn_sig(impl_m.def_id);
+ let trait_m_fty = tcx.fn_sig(trait_m.def_id);
let trait_number_args = trait_m_fty.inputs().skip_binder().len();
let impl_number_args = impl_m_fty.inputs().skip_binder().len();
if trait_number_args != impl_number_args {
fn has_no_input_arg(&self, method: &AssociatedItem) -> bool {
match method.def() {
Def::Method(def_id) => {
- match self.tcx.type_of(def_id).sty {
- ty::TypeVariants::TyFnDef(_, _, sig) => {
- sig.inputs().skip_binder().len() == 1
- }
- _ => false,
- }
+ self.tcx.fn_sig(def_id).inputs().skip_binder().len() == 1
}
_ => false,
}
use intrinsics;
use rustc::traits::{ObligationCause, ObligationCauseCode};
-use rustc::ty::subst::Substs;
use rustc::ty::{self, TyCtxt, Ty};
use rustc::util::nodemap::FxHashMap;
use require_same_types;
output: Ty<'tcx>) {
let def_id = tcx.hir.local_def_id(it.id);
- let substs = Substs::for_item(tcx, def_id,
- |_, _| tcx.types.re_erased,
- |def, _| tcx.mk_param_from_def(def));
+ match it.node {
+ hir::ForeignItemFn(..) => {}
+ _ => {
+ struct_span_err!(tcx.sess, it.span, E0619,
+ "intrinsic must be a function")
+ .span_label(it.span, "expected a function")
+ .emit();
+ return;
+ }
+ }
- let fty = tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
- inputs.into_iter(),
- output,
- false,
- hir::Unsafety::Unsafe,
- abi
- )));
let i_n_tps = tcx.generics_of(def_id).types.len();
if i_n_tps != n_tps {
let span = match it.node {
hir::ForeignItemFn(_, _, ref generics) => generics.span,
- hir::ForeignItemStatic(..) => it.span
+ _ => bug!()
};
struct_span_err!(tcx.sess, span, E0094,
i_n_tps, n_tps)
.span_label(span, format!("expected {} type parameter", n_tps))
.emit();
- } else {
- require_same_types(tcx,
- &ObligationCause::new(it.span,
- it.id,
- ObligationCauseCode::IntrinsicType),
- tcx.type_of(def_id),
- fty);
+ return;
}
+
+ let fty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig(
+ inputs.into_iter(),
+ output,
+ false,
+ hir::Unsafety::Unsafe,
+ abi
+ )));
+ let cause = ObligationCause::new(it.span, it.id, ObligationCauseCode::IntrinsicType);
+ require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(def_id)), fty);
}
/// Remember to add all intrinsics here, in librustc_trans/trans/intrinsic.rs,
let mut structural_to_nomimal = FxHashMap();
- let sig = tcx.type_of(def_id).fn_sig();
+ let sig = tcx.fn_sig(def_id);
let sig = tcx.no_late_bound_regions(&sig).unwrap();
if intr.inputs.len() != sig.inputs().len() {
span_err!(tcx.sess, it.span, E0444,
debug!("method_predicates after subst = {:?}", method_predicates);
- let sig = self.tcx.type_of(def_id).fn_sig();
+ let sig = self.tcx.fn_sig(def_id);
// Instantiate late-bound regions and substitute the trait
// parameters into the method type to get the actual method type.
// NB: Instantiate late-bound regions first so that
// `instantiate_type_scheme` can normalize associated types that
// may reference those regions.
- let fn_sig = tcx.type_of(def_id).fn_sig();
+ let fn_sig = tcx.fn_sig(def_id);
let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
infer::FnCall,
&fn_sig).0;
expected: ty::Ty<'tcx>) -> bool {
match method.def() {
Def::Method(def_id) => {
- let fty = self.tcx.type_of(def_id).fn_sig();
+ let fty = self.tcx.fn_sig(def_id);
self.probe(|_| {
let substs = self.fresh_substs_for_item(self.span, method.def_id);
let output = fty.output().subst(self.tcx, substs);
impl_ty: Ty<'tcx>,
substs: &Substs<'tcx>)
-> Ty<'tcx> {
- let self_ty = self.tcx.type_of(method).fn_sig().input(0);
+ let self_ty = self.tcx.fn_sig(method).input(0);
debug!("xform_self_ty(impl_ty={:?}, self_ty={:?}, substs={:?})",
impl_ty,
self_ty,
typeck_item_bodies,
typeck_tables_of,
has_typeck_tables,
- closure_type,
closure_kind,
adt_destructor,
..*providers
};
}
-fn closure_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- def_id: DefId)
- -> ty::PolyFnSig<'tcx> {
- let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
- tcx.typeck_tables_of(def_id).closure_tys[&node_id]
-}
-
fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ty::ClosureKind {
Inherited::build(tcx, def_id).enter(|inh| {
let param_env = tcx.param_env(def_id);
let fcx = if let Some(decl) = fn_decl {
- let fn_sig = tcx.type_of(def_id).fn_sig();
+ let fn_sig = tcx.fn_sig(def_id);
check_abi(tcx, span, fn_sig.abi());
-> ty::TypeAndMut<'tcx>
{
// extract method return type, which will be &T;
- // all LB regions should have been instantiated during method lookup
let ret_ty = method.sig.output();
// method returns &T, but the type as visible to user is T, so deref
ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => {
variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
}
- ty::TyFnDef(.., f) => {
- let ptr_ty = self.tcx.mk_fn_ptr(f);
+ ty::TyFnDef(..) => {
+ let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx));
let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty);
variadic_error(tcx.sess, arg.span, arg_ty, &format!("{}", ptr_ty));
}
}
ty::AssociatedKind::Method => {
reject_shadowing_type_parameters(fcx.tcx, item.def_id);
- let method_ty = fcx.tcx.type_of(item.def_id);
- let method_ty = fcx.normalize_associated_types_in(span, &method_ty);
+ let sig = fcx.tcx.fn_sig(item.def_id);
+ let sig = fcx.normalize_associated_types_in(span, &sig);
let predicates = fcx.tcx.predicates_of(item.def_id)
.instantiate_identity(fcx.tcx);
let predicates = fcx.normalize_associated_types_in(span, &predicates);
- let sig = method_ty.fn_sig();
this.check_fn_or_method(fcx, span, sig, &predicates,
item.def_id, &mut implied_bounds);
let sig_if_method = sig_if_method.expect("bad signature for method");
fn check_item_fn(&mut self, item: &hir::Item) {
self.for_item(item).with_fcx(|fcx, this| {
let def_id = fcx.tcx.hir.local_def_id(item.id);
- let ty = fcx.tcx.type_of(def_id);
- let item_ty = fcx.normalize_associated_types_in(item.span, &ty);
- let sig = item_ty.fn_sig();
+ let sig = fcx.tcx.fn_sig(def_id);
+ let sig = fcx.normalize_associated_types_in(item.span, &sig);
let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
let span = method_sig.decl.inputs[0].span;
- let method_ty = fcx.tcx.type_of(method.def_id);
- let fty = fcx.normalize_associated_types_in(span, &method_ty);
- let sig = fcx.liberate_late_bound_regions(method.def_id, &fty.fn_sig());
+ let sig = fcx.tcx.fn_sig(method.def_id);
+ let sig = fcx.normalize_associated_types_in(span, &sig);
+ let sig = fcx.liberate_late_bound_regions(method.def_id, &sig);
debug!("check_method_receiver: sig={:?}", sig);
type_param_predicates,
trait_def,
adt_def,
+ fn_sig,
impl_trait_ref,
impl_polarity,
is_foreign_item,
tcx.generics_of(def_id);
tcx.type_of(def_id);
tcx.predicates_of(def_id);
+ if let hir::ForeignItemFn(..) = item.node {
+ tcx.fn_sig(def_id);
+ }
}
}
hir::ItemEnum(ref enum_definition, _) => {
tcx.generics_of(def_id);
tcx.type_of(def_id);
tcx.predicates_of(def_id);
+ if let hir::ItemFn(..) = it.node {
+ tcx.fn_sig(def_id);
+ }
}
}
}
hir::TraitItemKind::Type(_, Some(_)) |
hir::TraitItemKind::Method(..) => {
tcx.type_of(def_id);
+ if let hir::TraitItemKind::Method(..) = trait_item.node {
+ tcx.fn_sig(def_id);
+ }
}
hir::TraitItemKind::Type(_, None) => {}
tcx.generics_of(def_id);
tcx.type_of(def_id);
tcx.predicates_of(def_id);
+ if let hir::ImplItemKind::Method(..) = tcx.hir.expect_impl_item(impl_item_id).node {
+ tcx.fn_sig(def_id);
+ }
}
fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
match tcx.hir.get(node_id) {
NodeTraitItem(item) => {
match item.node {
- TraitItemKind::Method(ref sig, _) => {
- let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl);
+ TraitItemKind::Method(..) => {
let substs = Substs::identity_for_item(tcx, def_id);
- tcx.mk_fn_def(def_id, substs, fty)
+ tcx.mk_fn_def(def_id, substs)
}
TraitItemKind::Const(ref ty, _) |
TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
NodeImplItem(item) => {
match item.node {
- ImplItemKind::Method(ref sig, _) => {
- let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl);
+ ImplItemKind::Method(..) => {
let substs = Substs::identity_for_item(tcx, def_id);
- tcx.mk_fn_def(def_id, substs, fty)
+ tcx.mk_fn_def(def_id, substs)
}
ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
ImplItemKind::Type(ref ty) => {
ItemTy(ref t, _) | ItemImpl(.., ref t, _) => {
icx.to_ty(t)
}
- ItemFn(ref decl, unsafety, _, abi, _, _) => {
- let tofd = AstConv::ty_of_fn(&icx, unsafety, abi, &decl);
+ ItemFn(..) => {
let substs = Substs::identity_for_item(tcx, def_id);
- tcx.mk_fn_def(def_id, substs, tofd)
+ tcx.mk_fn_def(def_id, substs)
}
ItemEnum(..) |
ItemStruct(..) |
}
NodeForeignItem(foreign_item) => {
- let abi = tcx.hir.get_foreign_abi(node_id);
-
match foreign_item.node {
- ForeignItemFn(ref fn_decl, _, _) => {
- compute_type_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
+ ForeignItemFn(..) => {
+ let substs = Substs::identity_for_item(tcx, def_id);
+ tcx.mk_fn_def(def_id, substs)
}
ForeignItemStatic(ref t, _) => icx.to_ty(t)
}
NodeStructCtor(&ref def) |
NodeVariant(&Spanned { node: hir::Variant_ { data: ref def, .. }, .. }) => {
- let ty = tcx.type_of(tcx.hir.get_parent_did(node_id));
match *def {
- VariantData::Unit(..) | VariantData::Struct(..) => ty,
- VariantData::Tuple(ref fields, _) => {
- let inputs = fields.iter().map(|f| {
- tcx.type_of(tcx.hir.local_def_id(f.id))
- });
+ VariantData::Unit(..) | VariantData::Struct(..) => {
+ tcx.type_of(tcx.hir.get_parent_did(node_id))
+ }
+ VariantData::Tuple(..) => {
let substs = Substs::identity_for_item(tcx, def_id);
- tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
- inputs,
- ty,
- false,
- hir::Unsafety::Normal,
- abi::Abi::Rust
- )))
+ tcx.mk_fn_def(def_id, substs)
}
}
}
}
}
+fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> ty::PolyFnSig<'tcx> {
+ use rustc::hir::map::*;
+ use rustc::hir::*;
+
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+
+ let icx = ItemCtxt::new(tcx, def_id);
+
+ match tcx.hir.get(node_id) {
+ NodeTraitItem(&hir::TraitItem { node: TraitItemKind::Method(ref sig, _), .. }) |
+ NodeImplItem(&hir::ImplItem { node: ImplItemKind::Method(ref sig, _), .. }) => {
+ AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl)
+ }
+
+ NodeItem(&hir::Item { node: ItemFn(ref decl, unsafety, _, abi, _, _), .. }) => {
+ AstConv::ty_of_fn(&icx, unsafety, abi, decl)
+ }
+
+ NodeForeignItem(&hir::ForeignItem { node: ForeignItemFn(ref fn_decl, _, _), .. }) => {
+ let abi = tcx.hir.get_foreign_abi(node_id);
+ compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
+ }
+
+ NodeStructCtor(&VariantData::Tuple(ref fields, _)) |
+ NodeVariant(&Spanned { node: hir::Variant_ {
+ data: VariantData::Tuple(ref fields, _), ..
+ }, .. }) => {
+ let ty = tcx.type_of(tcx.hir.get_parent_did(node_id));
+ let inputs = fields.iter().map(|f| {
+ tcx.type_of(tcx.hir.local_def_id(f.id))
+ });
+ ty::Binder(tcx.mk_fn_sig(
+ inputs,
+ ty,
+ false,
+ hir::Unsafety::Normal,
+ abi::Abi::Rust
+ ))
+ }
+
+ NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
+ tcx.typeck_tables_of(def_id).closure_tys[&node_id]
+ }
+
+ x => {
+ bug!("unexpected sort of node in fn_sig(): {:?}", x);
+ }
+ }
+}
+
fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> Option<ty::TraitRef<'tcx>> {
}
}
-fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
+fn compute_sig_of_foreign_fn_decl<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
decl: &hir::FnDecl,
abi: abi::Abi)
- -> Ty<'tcx>
+ -> ty::PolyFnSig<'tcx>
{
let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), hir::Unsafety::Unsafe, abi, decl);
}
}
- let substs = Substs::identity_for_item(tcx, def_id);
- tcx.mk_fn_def(def_id, substs, fty)
+ fty
}
fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
E0568, // auto-traits can not have predicates,
E0588, // packed struct cannot transitively contain a `[repr(align)]` struct
E0592, // duplicate definitions with name `{}`
+ E0619, // intrinsic must be a function
}
}
_ => ()
}
- let substs = tcx.intern_substs(&[]);
- let se_ty = tcx.mk_fn_def(main_def_id, substs,
- ty::Binder(tcx.mk_fn_sig(
+ let se_ty = tcx.mk_fn_ptr(ty::Binder(
+ tcx.mk_fn_sig(
iter::empty(),
tcx.mk_nil(),
false,
hir::Unsafety::Normal,
Abi::Rust
- ))
- );
+ )
+ ));
require_same_types(
tcx,
&ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
se_ty,
- main_t);
+ tcx.mk_fn_ptr(tcx.fn_sig(main_def_id)));
}
_ => {
span_bug!(main_span,
_ => ()
}
- let substs = tcx.intern_substs(&[]);
- let se_ty = tcx.mk_fn_def(start_def_id, substs,
- ty::Binder(tcx.mk_fn_sig(
+ let se_ty = tcx.mk_fn_ptr(ty::Binder(
+ tcx.mk_fn_sig(
[
tcx.types.isize,
tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
false,
hir::Unsafety::Normal,
Abi::Rust
- ))
- );
+ )
+ ));
require_same_types(
tcx,
&ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
se_ty,
- start_t);
+ tcx.mk_fn_ptr(tcx.fn_sig(start_def_id)));
}
_ => {
span_bug!(start_span,
//! We walk the set of items and, for each member, generate new constraints.
use hir::def_id::DefId;
-use middle::resolve_lifetime as rl;
use rustc::dep_graph::{AssertDepGraphSafe, DepKind};
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
-use rustc::hir::map as hir_map;
use syntax::ast;
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
/// }
///
/// then while we are visiting `Bar<T>`, the `CurrentItem` would have
-/// the def-id and generics of `Foo`.
-pub struct CurrentItem<'a> {
+/// the def-id and the start of `Foo`'s inferreds.
+pub struct CurrentItem {
def_id: DefId,
- generics: &'a ty::Generics,
+ inferred_start: InferredIndex,
}
pub fn add_constraints_from_crate<'a, 'tcx>(terms_cx: TermsContext<'a, 'tcx>)
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
+ match item.node {
+ hir::ItemStruct(ref struct_def, _) |
+ hir::ItemUnion(ref struct_def, _) => {
+ self.visit_node_helper(item.id);
+
+ if let hir::VariantData::Tuple(..) = *struct_def {
+ self.visit_node_helper(struct_def.id());
+ }
+ }
+
+ hir::ItemEnum(ref enum_def, _) => {
+ self.visit_node_helper(item.id);
+
+ for variant in &enum_def.variants {
+ if let hir::VariantData::Tuple(..) = variant.node.data {
+ self.visit_node_helper(variant.node.data.id());
+ }
+ }
+ }
+
+ hir::ItemFn(..) => {
+ self.visit_node_helper(item.id);
+ }
+
+ hir::ItemForeignMod(ref foreign_mod) => {
+ for foreign_item in &foreign_mod.items {
+ if let hir::ForeignItemFn(..) = foreign_item.node {
+ self.visit_node_helper(foreign_item.id);
+ }
+ }
+ }
+
+ _ => {}
+ }
+ }
+
+ fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
+ if let hir::TraitItemKind::Method(..) = trait_item.node {
+ self.visit_node_helper(trait_item.id);
+ }
+ }
+
+ fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
+ if let hir::ImplItemKind::Method(..) = impl_item.node {
+ self.visit_node_helper(impl_item.id);
+ }
+ }
+}
+
+impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
+ fn visit_node_helper(&mut self, id: ast::NodeId) {
let tcx = self.terms_cx.tcx;
- let def_id = tcx.hir.local_def_id(item.id);
+ let def_id = tcx.hir.local_def_id(id);
// Encapsulate constructing the constraints into a task we can
// reference later. This can go away once the red-green
//
// See README.md for a detailed discussion
// on dep-graph management.
- match item.node {
- hir::ItemEnum(..) |
- hir::ItemStruct(..) |
- hir::ItemUnion(..) => {
- let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
- tcx.dep_graph.with_task(dep_node,
- AssertDepGraphSafe(self),
- def_id,
- visit_item_task);
- }
- _ => {
- // Nothing to do here, skip the task.
- }
- }
+ let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
+ tcx.dep_graph.with_task(dep_node,
+ AssertDepGraphSafe(self),
+ def_id,
+ visit_item_task);
fn visit_item_task<'a, 'tcx>(ccx: AssertDepGraphSafe<&mut ConstraintContext<'a, 'tcx>>,
def_id: DefId)
}
}
- fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
- }
-
- fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
- }
-}
-
-/// Is `param_id` a lifetime according to `map`?
-fn is_lifetime(map: &hir_map::Map, param_id: ast::NodeId) -> bool {
- match map.find(param_id) {
- Some(hir_map::NodeLifetime(..)) => true,
- _ => false,
- }
-}
-
-impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
self.terms_cx.tcx
}
fn build_constraints_for_item(&mut self, def_id: DefId) {
let tcx = self.tcx();
- let id = self.tcx().hir.as_local_node_id(def_id).unwrap();
- let item = tcx.hir.expect_item(id);
- debug!("visit_item item={}", tcx.hir.node_to_string(item.id));
+ debug!("build_constraints_for_item({})", tcx.item_path_str(def_id));
- match item.node {
- hir::ItemEnum(..) |
- hir::ItemStruct(..) |
- hir::ItemUnion(..) => {
- let generics = tcx.generics_of(def_id);
- let current_item = &CurrentItem { def_id, generics };
+ // Skip items with no generics - there's nothing to infer in them.
+ if tcx.generics_of(def_id).count() == 0 {
+ return;
+ }
+ let id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let inferred_start = self.terms_cx.inferred_starts[&id];
+ let current_item = &CurrentItem { def_id, inferred_start };
+ match tcx.type_of(def_id).sty {
+ ty::TyAdt(def, _) => {
// Not entirely obvious: constraints on structs/enums do not
// affect the variance of their type parameters. See discussion
// in comment at top of module.
//
// self.add_constraints_from_generics(generics);
- for field in tcx.adt_def(def_id).all_fields() {
+ for field in def.all_fields() {
self.add_constraints_from_ty(current_item,
tcx.type_of(field.did),
self.covariant);
}
}
- hir::ItemTrait(..) |
- hir::ItemExternCrate(_) |
- hir::ItemUse(..) |
- hir::ItemStatic(..) |
- hir::ItemConst(..) |
- hir::ItemFn(..) |
- hir::ItemMod(..) |
- hir::ItemForeignMod(..) |
- hir::ItemGlobalAsm(..) |
- hir::ItemTy(..) |
- hir::ItemImpl(..) |
- hir::ItemDefaultImpl(..) => {
- span_bug!(item.span, "`build_constraints_for_item` invoked for non-type-def");
+ ty::TyFnDef(..) => {
+ self.add_constraints_from_sig(current_item,
+ tcx.fn_sig(def_id),
+ self.covariant);
}
- }
- }
-
- /// Load the generics for another item, adding a corresponding
- /// relation into the dependencies to indicate that the variance
- /// for `current` relies on `def_id`.
- fn read_generics(&mut self, current: &CurrentItem, def_id: DefId) -> &'tcx ty::Generics {
- let generics = self.tcx().generics_of(def_id);
- if self.tcx().dep_graph.is_fully_enabled() {
- self.dependencies.add(current.def_id, def_id);
- }
- generics
- }
- fn opt_inferred_index(&self, param_id: ast::NodeId) -> Option<&InferredIndex> {
- self.terms_cx.inferred_map.get(¶m_id)
- }
-
- fn find_binding_for_lifetime(&self, param_id: ast::NodeId) -> ast::NodeId {
- let tcx = self.terms_cx.tcx;
- assert!(is_lifetime(&tcx.hir, param_id));
- match tcx.named_region_map.defs.get(¶m_id) {
- Some(&rl::Region::EarlyBound(_, lifetime_decl_id)) => lifetime_decl_id,
- Some(_) => bug!("should not encounter non early-bound cases"),
-
- // The lookup should only fail when `param_id` is
- // itself a lifetime binding: use it as the decl_id.
- None => param_id,
- }
-
- }
-
- /// Is `param_id` a type parameter for which we infer variance?
- fn is_to_be_inferred(&self, param_id: ast::NodeId) -> bool {
- let result = self.terms_cx.inferred_map.contains_key(¶m_id);
-
- // To safe-guard against invalid inferred_map constructions,
- // double-check if variance is inferred at some use of a type
- // parameter (by inspecting parent of its binding declaration
- // to see if it is introduced by a type or by a fn/impl).
-
- let check_result = |this: &ConstraintContext| -> bool {
- let tcx = this.terms_cx.tcx;
- let decl_id = this.find_binding_for_lifetime(param_id);
- // Currently only called on lifetimes; double-checking that.
- assert!(is_lifetime(&tcx.hir, param_id));
- let parent_id = tcx.hir.get_parent(decl_id);
- let parent = tcx.hir
- .find(parent_id)
- .unwrap_or_else(|| bug!("tcx.hir missing entry for id: {}", parent_id));
-
- let is_inferred;
- macro_rules! cannot_happen { () => { {
- bug!("invalid parent: {} for {}",
- tcx.hir.node_to_string(parent_id),
- tcx.hir.node_to_string(param_id));
- } } }
-
- match parent {
- hir_map::NodeItem(p) => {
- match p.node {
- hir::ItemTy(..) |
- hir::ItemEnum(..) |
- hir::ItemStruct(..) |
- hir::ItemUnion(..) |
- hir::ItemTrait(..) => is_inferred = true,
- hir::ItemFn(..) => is_inferred = false,
- _ => cannot_happen!(),
- }
- }
- hir_map::NodeTraitItem(..) => is_inferred = false,
- hir_map::NodeImplItem(..) => is_inferred = false,
- _ => cannot_happen!(),
- }
-
- return is_inferred;
- };
-
- assert_eq!(result, check_result(self));
-
- return result;
- }
-
- /// Returns a variance term representing the declared variance of the type/region parameter
- /// with the given id.
- fn declared_variance(&self,
- param_def_id: DefId,
- item_def_id: DefId,
- index: usize)
- -> VarianceTermPtr<'a> {
- assert_eq!(param_def_id.krate, item_def_id.krate);
-
- if let Some(param_node_id) = self.tcx().hir.as_local_node_id(param_def_id) {
- // Parameter on an item defined within current crate:
- // variance not yet inferred, so return a symbolic
- // variance.
- if let Some(&InferredIndex(index)) = self.opt_inferred_index(param_node_id) {
- self.terms_cx.inferred_infos[index].term
- } else {
- // If there is no inferred entry for a type parameter,
- // it must be declared on a (locally defiend) trait -- they don't
- // get inferreds because they are always invariant.
- if cfg!(debug_assertions) {
- let item_node_id = self.tcx().hir.as_local_node_id(item_def_id).unwrap();
- let item = self.tcx().hir.expect_item(item_node_id);
- let success = match item.node {
- hir::ItemTrait(..) => true,
- _ => false,
- };
- if !success {
- bug!("parameter {:?} has no inferred, but declared on non-trait: {:?}",
- item_def_id,
- item);
- }
- }
- self.invariant
+ _ => {
+ span_bug!(tcx.def_span(def_id),
+ "`build_constraints_for_item` unsupported for this item");
}
- } else {
- // Parameter on an item defined within another crate:
- // variance already inferred, just look it up.
- let variances = self.tcx().variances_of(item_def_id);
- self.constant_term(variances[index])
}
}
fn add_constraint(&mut self,
- InferredIndex(index): InferredIndex,
+ current: &CurrentItem,
+ index: u32,
variance: VarianceTermPtr<'a>) {
debug!("add_constraint(index={}, variance={:?})", index, variance);
self.constraints.push(Constraint {
- inferred: InferredIndex(index),
+ inferred: InferredIndex(current.inferred_start.0 + index as usize),
variance: variance,
});
}
debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}",
trait_ref,
variance);
+ self.add_constraints_from_invariant_substs(current, trait_ref.substs, variance);
+ }
- let trait_generics = self.tcx().generics_of(trait_ref.def_id);
+ fn add_constraints_from_invariant_substs(&mut self,
+ current: &CurrentItem,
+ substs: &Substs<'tcx>,
+ variance: VarianceTermPtr<'a>) {
+ debug!("add_constraints_from_invariant_substs: substs={:?} variance={:?}",
+ substs,
+ variance);
- self.add_constraints_from_substs(current,
- trait_ref.def_id,
- &trait_generics.types,
- &trait_generics.regions,
- trait_ref.substs,
- variance);
+ // Trait are always invariant so we can take advantage of that.
+ let variance_i = self.invariant(variance);
+ for ty in substs.types() {
+ self.add_constraints_from_ty(current, ty, variance_i);
+ }
+
+ for region in substs.regions() {
+ self.add_constraints_from_region(current, region, variance_i);
+ }
}
/// Adds constraints appropriate for an instance of `ty` appearing
// leaf type -- noop
}
- ty::TyClosure(..) |
- ty::TyAnon(..) => {
+ ty::TyFnDef(..) |
+ ty::TyClosure(..) => {
bug!("Unexpected closure type in variance computation");
}
}
ty::TyAdt(def, substs) => {
- let adt_generics = self.read_generics(current, def.did);
-
- self.add_constraints_from_substs(current,
- def.did,
- &adt_generics.types,
- &adt_generics.regions,
- substs,
- variance);
+ self.add_constraints_from_substs(current, def.did, substs, variance);
}
ty::TyProjection(ref data) => {
- let trait_ref = &data.trait_ref;
- let trait_generics = self.tcx().generics_of(trait_ref.def_id);
-
- self.add_constraints_from_substs(current,
- trait_ref.def_id,
- &trait_generics.types,
- &trait_generics.regions,
- trait_ref.substs,
- variance);
+ self.add_constraints_from_trait_ref(current, data.trait_ref, variance);
+ }
+
+ ty::TyAnon(_, substs) => {
+ self.add_constraints_from_invariant_substs(current, substs, variance);
}
ty::TyDynamic(ref data, r) => {
}
ty::TyParam(ref data) => {
- assert_eq!(current.generics.parent, None);
- let mut i = data.idx as usize;
- if !current.generics.has_self || i > 0 {
- i -= current.generics.regions.len();
- }
- let def_id = current.generics.types[i].def_id;
- let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
- match self.terms_cx.inferred_map.get(&node_id) {
- Some(&index) => {
- self.add_constraint(index, variance);
- }
- None => {
- // We do not infer variance for type parameters
- // declared on methods. They will not be present
- // in the inferred_map.
- }
- }
+ self.add_constraint(current, data.idx, variance);
}
- ty::TyFnDef(.., sig) |
ty::TyFnPtr(sig) => {
self.add_constraints_from_sig(current, sig, variance);
}
fn add_constraints_from_substs(&mut self,
current: &CurrentItem,
def_id: DefId,
- type_param_defs: &[ty::TypeParameterDef],
- region_param_defs: &[ty::RegionParameterDef],
substs: &Substs<'tcx>,
variance: VarianceTermPtr<'a>) {
debug!("add_constraints_from_substs(def_id={:?}, substs={:?}, variance={:?})",
substs,
variance);
- for p in type_param_defs {
- let variance_decl = self.declared_variance(p.def_id, def_id, p.index as usize);
+ // We don't record `inferred_starts` entries for empty generics.
+ if substs.is_empty() {
+ return;
+ }
+
+ // Add a corresponding relation into the dependencies to
+ // indicate that the variance for `current` relies on `def_id`.
+ if self.tcx().dep_graph.is_fully_enabled() {
+ self.dependencies.add(current.def_id, def_id);
+ }
+
+ let (local, remote) = if let Some(id) = self.tcx().hir.as_local_node_id(def_id) {
+ (Some(self.terms_cx.inferred_starts[&id]), None)
+ } else {
+ (None, Some(self.tcx().variances_of(def_id)))
+ };
+
+ for (i, k) in substs.iter().enumerate() {
+ let variance_decl = if let Some(InferredIndex(start)) = local {
+ // Parameter on an item defined within current crate:
+ // variance not yet inferred, so return a symbolic
+ // variance.
+ self.terms_cx.inferred_terms[start + i]
+ } else {
+ // Parameter on an item defined within another crate:
+ // variance already inferred, just look it up.
+ self.constant_term(remote.as_ref().unwrap()[i])
+ };
let variance_i = self.xform(variance, variance_decl);
- let substs_ty = substs.type_for_def(p);
debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
variance_decl,
variance_i);
- self.add_constraints_from_ty(current, substs_ty, variance_i);
- }
-
- for p in region_param_defs {
- let variance_decl = self.declared_variance(p.def_id, def_id, p.index as usize);
- let variance_i = self.xform(variance, variance_decl);
- let substs_r = substs.region_for_def(p);
- self.add_constraints_from_region(current, substs_r, variance_i);
+ if let Some(ty) = k.as_type() {
+ self.add_constraints_from_ty(current, ty, variance_i);
+ } else if let Some(r) = k.as_region() {
+ self.add_constraints_from_region(current, r, variance_i);
+ } else {
+ bug!();
+ }
}
}
variance: VarianceTermPtr<'a>) {
match *region {
ty::ReEarlyBound(ref data) => {
- assert_eq!(current.generics.parent, None);
- let i = data.index as usize - current.generics.has_self as usize;
- let def_id = current.generics.regions[i].def_id;
- let node_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
- if self.is_to_be_inferred(node_id) {
- let &index = self.opt_inferred_index(node_id).unwrap();
- self.add_constraint(index, variance);
- }
+ self.add_constraint(current, data.index, variance);
}
ty::ReStatic => {}
ty::ReLateBound(..) => {
- // We do not infer variance for region parameters on
- // methods or in fn types.
+ // Late-bound regions do not get substituted the same
+ // way early-bound regions do, so we skip them here.
}
ty::ReFree(..) |
fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
-> Rc<Vec<ty::Variance>> {
- let item_id = tcx.hir.as_local_node_id(item_def_id).expect("expected local def-id");
- let item = tcx.hir.expect_item(item_id);
- match item.node {
- hir::ItemTrait(..) => {
- // Traits are always invariant.
- let generics = tcx.generics_of(item_def_id);
- assert!(generics.parent.is_none());
- Rc::new(vec![ty::Variance::Invariant; generics.count()])
- }
+ let id = tcx.hir.as_local_node_id(item_def_id).expect("expected local def-id");
+ let unsupported = || {
+ // Variance not relevant.
+ span_bug!(tcx.hir.span(id), "asked to compute variance for wrong kind of item")
+ };
+ match tcx.hir.get(id) {
+ hir::map::NodeItem(item) => match item.node {
+ hir::ItemEnum(..) |
+ hir::ItemStruct(..) |
+ hir::ItemUnion(..) |
+ hir::ItemFn(..) => {}
- hir::ItemEnum(..) |
- hir::ItemStruct(..) |
- hir::ItemUnion(..) => {
- // Everything else must be inferred.
+ _ => unsupported()
+ },
- // Lacking red/green, we read the variances for all items here
- // but ignore the dependencies, then re-synthesize the ones we need.
- let crate_map = tcx.dep_graph.with_ignore(|| tcx.crate_variances(LOCAL_CRATE));
- let dep_node = item_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
- tcx.dep_graph.read(dep_node);
- for &dep_def_id in crate_map.dependencies.less_than(&item_def_id) {
- if dep_def_id.is_local() {
- let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
- tcx.dep_graph.read(dep_node);
- } else {
- let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVariances);
- tcx.dep_graph.read(dep_node);
- }
- }
-
- crate_map.variances.get(&item_def_id)
- .unwrap_or(&crate_map.empty_variance)
- .clone()
- }
+ hir::map::NodeTraitItem(item) => match item.node {
+ hir::TraitItemKind::Method(..) => {}
+
+ _ => unsupported()
+ },
+
+ hir::map::NodeImplItem(item) => match item.node {
+ hir::ImplItemKind::Method(..) => {}
+
+ _ => unsupported()
+ },
+
+ hir::map::NodeForeignItem(item) => match item.node {
+ hir::ForeignItemFn(..) => {}
- _ => {
- // Variance not relevant.
- span_bug!(item.span, "asked to compute variance for wrong kind of item")
+ _ => unsupported()
+ },
+
+ hir::map::NodeVariant(_) | hir::map::NodeStructCtor(_) => {}
+
+ _ => unsupported()
+ }
+
+ // Everything else must be inferred.
+
+ // Lacking red/green, we read the variances for all items here
+ // but ignore the dependencies, then re-synthesize the ones we need.
+ let crate_map = tcx.dep_graph.with_ignore(|| tcx.crate_variances(LOCAL_CRATE));
+ let dep_node = item_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
+ tcx.dep_graph.read(dep_node);
+ for &dep_def_id in crate_map.dependencies.less_than(&item_def_id) {
+ if dep_def_id.is_local() {
+ let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints);
+ tcx.dep_graph.read(dep_node);
+ } else {
+ let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVariances);
+ tcx.dep_graph.read(dep_node);
}
}
+
+ crate_map.variances.get(&item_def_id)
+ .unwrap_or(&crate_map.empty_variance)
+ .clone()
}
pub fn solve_constraints(constraints_cx: ConstraintContext) -> ty::CrateVariancesMap {
let ConstraintContext { terms_cx, dependencies, constraints, .. } = constraints_cx;
- let solutions = terms_cx.inferred_infos
- .iter()
- .map(|ii| ii.initial_variance)
- .collect();
+ let mut solutions = vec![ty::Bivariant; terms_cx.inferred_terms.len()];
+ for &(id, ref variances) in &terms_cx.lang_items {
+ let InferredIndex(start) = terms_cx.inferred_starts[&id];
+ for (i, &variance) in variances.iter().enumerate() {
+ solutions[start + i] = variance;
+ }
+ }
let mut solutions_cx = SolveContext {
- terms_cx: terms_cx,
- constraints: constraints,
- solutions: solutions,
+ terms_cx,
+ constraints,
+ solutions,
};
solutions_cx.solve();
let variances = solutions_cx.create_map();
let old_value = self.solutions[inferred];
let new_value = glb(variance, old_value);
if old_value != new_value {
- debug!("Updating inferred {} (node {}) \
+ debug!("Updating inferred {} \
from {:?} to {:?} due to {:?}",
inferred,
- self.terms_cx
- .inferred_infos[inferred]
- .param_id,
old_value,
new_value,
term);
}
fn create_map(&self) -> FxHashMap<DefId, Rc<Vec<ty::Variance>>> {
- // Collect all the variances for a particular item and stick
- // them into the variance map. We rely on the fact that we
- // generate all the inferreds for a particular item
- // consecutively (that is, we collect solutions for an item
- // until we see a new item id, and we assume (1) the solutions
- // are in the same order as the type parameters were declared
- // and (2) all solutions or a given item appear before a new
- // item id).
-
let tcx = self.terms_cx.tcx;
- let mut map = FxHashMap();
-
let solutions = &self.solutions;
- let inferred_infos = &self.terms_cx.inferred_infos;
- let mut index = 0;
- let num_inferred = self.terms_cx.num_inferred();
- while index < num_inferred {
- let item_id = inferred_infos[index].item_id;
-
- let mut item_variances = vec![];
-
- while index < num_inferred && inferred_infos[index].item_id == item_id {
- let info = &inferred_infos[index];
- let variance = solutions[index];
- debug!("Index {} Info {} Variance {:?}",
- index,
- info.index,
- variance);
-
- assert_eq!(item_variances.len(), info.index);
- item_variances.push(variance);
- index += 1;
- }
+ self.terms_cx.inferred_starts.iter().map(|(&id, &InferredIndex(start))| {
+ let def_id = tcx.hir.local_def_id(id);
+ let generics = tcx.generics_of(def_id);
- debug!("item_id={} item_variances={:?}", item_id, item_variances);
+ let mut variances = solutions[start..start+generics.count()].to_vec();
- let item_def_id = tcx.hir.local_def_id(item_id);
+ debug!("id={} variances={:?}", id, variances);
- map.insert(item_def_id, Rc::new(item_variances));
- }
+ // Functions can have unused type parameters: make those invariant.
+ if let ty::TyFnDef(..) = tcx.type_of(def_id).sty {
+ for variance in &mut variances {
+ if *variance == ty::Bivariant {
+ *variance = ty::Invariant;
+ }
+ }
+ }
- map
+ (def_id, Rc::new(variances))
+ }).collect()
}
fn evaluate(&self, term: VarianceTermPtr<'a>) -> ty::Variance {
use arena::TypedArena;
use rustc::ty::{self, TyCtxt};
use std::fmt;
-use std::rc::Rc;
use syntax::ast;
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub arena: &'a TypedArena<VarianceTerm<'a>>,
- pub empty_variances: Rc<Vec<ty::Variance>>,
-
// For marker types, UnsafeCell, and other lang items where
// variance is hardcoded, records the item-id and the hardcoded
// variance.
pub lang_items: Vec<(ast::NodeId, Vec<ty::Variance>)>,
- // Maps from the node id of a type/generic parameter to the
- // corresponding inferred index.
- pub inferred_map: NodeMap<InferredIndex>,
-
- // Maps from an InferredIndex to the info for that variable.
- pub inferred_infos: Vec<InferredInfo<'a>>,
-}
-
-pub struct InferredInfo<'a> {
- pub item_id: ast::NodeId,
- pub index: usize,
- pub param_id: ast::NodeId,
- pub term: VarianceTermPtr<'a>,
+ // Maps from the node id of an item to the first inferred index
+ // used for its type & region parameters.
+ pub inferred_starts: NodeMap<InferredIndex>,
- // Initial value to use for this parameter when inferring
- // variance. For most parameters, this is Bivariant. But for lang
- // items and input type parameters on traits, it is different.
- pub initial_variance: ty::Variance,
+ // Maps from an InferredIndex to the term for that variable.
+ pub inferred_terms: Vec<VarianceTermPtr<'a>>,
}
pub fn determine_parameters_to_be_inferred<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let mut terms_cx = TermsContext {
tcx: tcx,
arena: arena,
- inferred_map: NodeMap(),
- inferred_infos: Vec::new(),
+ inferred_starts: NodeMap(),
+ inferred_terms: vec![],
lang_items: lang_items(tcx),
-
- // cache and share the variance struct used for items with
- // no type/region parameters
- empty_variances: Rc::new(vec![]),
};
// See README.md for a discussion on dep-graph management.
}
impl<'a, 'tcx> TermsContext<'a, 'tcx> {
- fn add_inferreds_for_item(&mut self,
- item_id: ast::NodeId,
- generics: &hir::Generics) {
- //! Add "inferreds" for the generic parameters declared on this
- //! item. This has a lot of annoying parameters because we are
- //! trying to drive this from the AST, rather than the
- //! ty::Generics, so that we can get span info -- but this
- //! means we must accommodate syntactic distinctions.
- //!
+ fn add_inferreds_for_item(&mut self, id: ast::NodeId) {
+ let tcx = self.tcx;
+ let def_id = tcx.hir.local_def_id(id);
+ let count = tcx.generics_of(def_id).count();
- // NB: In the code below for writing the results back into the
- // `CrateVariancesMap`, we rely on the fact that all inferreds
- // for a particular item are assigned continuous indices.
-
- for (p, i) in generics.lifetimes.iter().zip(0..) {
- let id = p.lifetime.id;
- self.add_inferred(item_id, i, id);
- }
-
- for (p, i) in generics.ty_params.iter().zip(generics.lifetimes.len()..) {
- self.add_inferred(item_id, i, p.id);
+ if count == 0 {
+ return;
}
- }
- fn add_inferred(&mut self, item_id: ast::NodeId, index: usize, param_id: ast::NodeId) {
- let inf_index = InferredIndex(self.inferred_infos.len());
- let term = self.arena.alloc(InferredTerm(inf_index));
- let initial_variance = self.pick_initial_variance(item_id, index);
- self.inferred_infos.push(InferredInfo {
- item_id: item_id,
- index: index,
- param_id: param_id,
- term: term,
- initial_variance: initial_variance,
- });
- let newly_added = self.inferred_map.insert(param_id, inf_index).is_none();
+ // Record the start of this item's inferreds.
+ let start = self.inferred_terms.len();
+ let newly_added = self.inferred_starts.insert(id, InferredIndex(start)).is_none();
assert!(newly_added);
- debug!("add_inferred(item_path={}, \
- item_id={}, \
- index={}, \
- param_id={}, \
- inf_index={:?}, \
- initial_variance={:?})",
- self.tcx.item_path_str(self.tcx.hir.local_def_id(item_id)),
- item_id,
- index,
- param_id,
- inf_index,
- initial_variance);
- }
-
- fn pick_initial_variance(&self, item_id: ast::NodeId, index: usize) -> ty::Variance {
- match self.lang_items.iter().find(|&&(n, _)| n == item_id) {
- Some(&(_, ref variances)) => variances[index],
- None => ty::Bivariant,
- }
- }
+ // NB: In the code below for writing the results back into the
+ // `CrateVariancesMap`, we rely on the fact that all inferreds
+ // for a particular item are assigned continuous indices.
- pub fn num_inferred(&self) -> usize {
- self.inferred_infos.len()
+ let arena = self.arena;
+ self.inferred_terms.extend((start..start+count).map(|i| {
+ &*arena.alloc(InferredTerm(InferredIndex(i)))
+ }));
}
}
self.tcx.hir.node_to_string(item.id));
match item.node {
- hir::ItemEnum(_, ref generics) |
- hir::ItemStruct(_, ref generics) |
- hir::ItemUnion(_, ref generics) => {
- self.add_inferreds_for_item(item.id, generics);
+ hir::ItemStruct(ref struct_def, _) |
+ hir::ItemUnion(ref struct_def, _) => {
+ self.add_inferreds_for_item(item.id);
+
+ if let hir::VariantData::Tuple(..) = *struct_def {
+ self.add_inferreds_for_item(struct_def.id());
+ }
+ }
+
+ hir::ItemEnum(ref enum_def, _) => {
+ self.add_inferreds_for_item(item.id);
+
+ for variant in &enum_def.variants {
+ if let hir::VariantData::Tuple(..) = variant.node.data {
+ self.add_inferreds_for_item(variant.node.data.id());
+ }
+ }
+ }
+
+ hir::ItemFn(..) => {
+ self.add_inferreds_for_item(item.id);
}
- hir::ItemTrait(..) |
- hir::ItemExternCrate(_) |
- hir::ItemUse(..) |
- hir::ItemDefaultImpl(..) |
- hir::ItemImpl(..) |
- hir::ItemStatic(..) |
- hir::ItemConst(..) |
- hir::ItemFn(..) |
- hir::ItemMod(..) |
- hir::ItemForeignMod(..) |
- hir::ItemGlobalAsm(..) |
- hir::ItemTy(..) => {}
+ hir::ItemForeignMod(ref foreign_mod) => {
+ for foreign_item in &foreign_mod.items {
+ if let hir::ForeignItemFn(..) = foreign_item.node {
+ self.add_inferreds_for_item(foreign_item.id);
+ }
+ }
+ }
+
+ _ => {}
}
}
- fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
+ if let hir::TraitItemKind::Method(..) = trait_item.node {
+ self.add_inferreds_for_item(trait_item.id);
+ }
}
- fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+ fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
+ if let hir::ImplItemKind::Method(..) = impl_item.node {
+ self.add_inferreds_for_item(impl_item.id);
+ }
}
}
}
fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function {
- let sig = cx.tcx.type_of(did).fn_sig();
+ let sig = cx.tcx.fn_sig(did);
let constness = if cx.tcx.is_const_fn(did) {
hir::Constness::Const
ty::AssociatedKind::Method => {
let generics = (cx.tcx.generics_of(self.def_id),
&cx.tcx.predicates_of(self.def_id)).clean(cx);
- let sig = cx.tcx.type_of(self.def_id).fn_sig();
+ let sig = cx.tcx.fn_sig(self.def_id);
let mut decl = (self.def_id, sig).clean(cx);
if self.method_has_self_argument {
mutability: mt.mutbl.clean(cx),
type_: box mt.ty.clean(cx),
},
- ty::TyFnDef(.., sig) |
- ty::TyFnPtr(sig) => BareFunction(box BareFunctionDecl {
- unsafety: sig.unsafety(),
- generics: Generics {
- lifetimes: Vec::new(),
- type_params: Vec::new(),
- where_predicates: Vec::new()
- },
- decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx),
- abi: sig.abi(),
- }),
+ ty::TyFnDef(..) |
+ ty::TyFnPtr(_) => {
+ let ty = cx.tcx.lift(self).unwrap();
+ let sig = ty.fn_sig(cx.tcx);
+ BareFunction(box BareFunctionDecl {
+ unsafety: sig.unsafety(),
+ generics: Generics {
+ lifetimes: Vec::new(),
+ type_params: Vec::new(),
+ where_predicates: Vec::new()
+ },
+ decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx),
+ abi: sig.abi(),
+ })
+ }
ty::TyAdt(def, substs) => {
let did = def.did;
let kind = match def.adt_kind() {
#[inline]
pub fn signum(self) -> f32 { num::Float::signum(self) }
- /// Returns `true` if `self`'s sign bit is positive, including
- /// `+0.0` and `INFINITY`.
+ /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
+ /// positive sign bit and positive infinity.
///
/// ```
- /// use std::f32;
- ///
- /// let nan = f32::NAN;
/// let f = 7.0_f32;
/// let g = -7.0_f32;
///
/// assert!(f.is_sign_positive());
/// assert!(!g.is_sign_positive());
- /// // Requires both tests to determine if is `NaN`
- /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) }
- /// Returns `true` if `self`'s sign is negative, including `-0.0`
- /// and `NEG_INFINITY`.
+ /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
+ /// negative sign bit and negative infinity.
///
/// ```
- /// use std::f32;
- ///
- /// let nan = f32::NAN;
/// let f = 7.0f32;
/// let g = -7.0f32;
///
/// assert!(!f.is_sign_negative());
/// assert!(g.is_sign_negative());
- /// // Requires both tests to determine if is `NaN`.
- /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
assert!(!nan.is_infinite());
assert!(!nan.is_finite());
assert!(!nan.is_normal());
- assert!(!nan.is_sign_positive());
+ assert!(nan.is_sign_positive());
assert!(!nan.is_sign_negative());
assert_eq!(Fp::Nan, nan.classify());
}
assert!(!(-1f32).is_sign_positive());
assert!(!NEG_INFINITY.is_sign_positive());
assert!(!(1f32/NEG_INFINITY).is_sign_positive());
- assert!(!NAN.is_sign_positive());
+ assert!(NAN.is_sign_positive());
+ assert!(!(-NAN).is_sign_positive());
}
#[test]
assert!(NEG_INFINITY.is_sign_negative());
assert!((1f32/NEG_INFINITY).is_sign_negative());
assert!(!NAN.is_sign_negative());
+ assert!((-NAN).is_sign_negative());
}
#[test]
#[inline]
pub fn signum(self) -> f64 { num::Float::signum(self) }
- /// Returns `true` if `self`'s sign bit is positive, including
- /// `+0.0` and `INFINITY`.
+ /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
+ /// positive sign bit and positive infinity.
///
/// ```
- /// use std::f64;
- ///
- /// let nan: f64 = f64::NAN;
- ///
/// let f = 7.0_f64;
/// let g = -7.0_f64;
///
/// assert!(f.is_sign_positive());
/// assert!(!g.is_sign_positive());
- /// // Requires both tests to determine if is `NaN`
- /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[inline]
pub fn is_positive(self) -> bool { num::Float::is_sign_positive(self) }
- /// Returns `true` if `self`'s sign is negative, including `-0.0`
- /// and `NEG_INFINITY`.
+ /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
+ /// negative sign bit and negative infinity.
///
/// ```
- /// use std::f64;
- ///
- /// let nan = f64::NAN;
- ///
/// let f = 7.0_f64;
/// let g = -7.0_f64;
///
/// assert!(!f.is_sign_negative());
/// assert!(g.is_sign_negative());
- /// // Requires both tests to determine if is `NaN`.
- /// assert!(!nan.is_sign_positive() && !nan.is_sign_negative());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
assert!(!nan.is_infinite());
assert!(!nan.is_finite());
assert!(!nan.is_normal());
- assert!(!nan.is_sign_positive());
+ assert!(nan.is_sign_positive());
assert!(!nan.is_sign_negative());
assert_eq!(Fp::Nan, nan.classify());
}
assert!(!(-1f64).is_sign_positive());
assert!(!NEG_INFINITY.is_sign_positive());
assert!(!(1f64/NEG_INFINITY).is_sign_positive());
- assert!(!NAN.is_sign_positive());
+ assert!(NAN.is_sign_positive());
+ assert!(!(-NAN).is_sign_positive());
}
#[test]
assert!(NEG_INFINITY.is_sign_negative());
assert!((1f64/NEG_INFINITY).is_sign_negative());
assert!(!NAN.is_sign_negative());
+ assert!((-NAN).is_sign_negative());
}
#[test]
all_fields = af;
vdata = vdata_;
}
- EnumMatching(_, variant, ref af) => {
+ EnumMatching(.., variant, ref af) => {
ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.node.name]);
all_fields = af;
vdata = &variant.node.data;
// based on the "shape".
let (ident, is_struct) = match *substr.fields {
Struct(vdata, _) => (substr.type_ident, vdata.is_struct()),
- EnumMatching(_, v, _) => (v.node.name, v.node.data.is_struct()),
+ EnumMatching(_, _, v, _) => (v.node.name, v.node.data.is_struct()),
EnumNonMatchingCollapsed(..) |
StaticStruct(..) |
StaticEnum(..) => cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"),
blk])
}
- EnumMatching(idx, variant, ref fields) => {
+ EnumMatching(idx, _, variant, ref fields) => {
// We're not generating an AST that the borrow checker is expecting,
// so we need to generate a unique local variable to take the
// mutable loan out on, otherwise we get conflicts which don't
/// A summary of the possible sets of fields.
pub enum SubstructureFields<'a> {
Struct(&'a ast::VariantData, Vec<FieldInfo<'a>>),
- /// Matching variants of the enum: variant index, ast::Variant,
+ /// Matching variants of the enum: variant index, variant count, ast::Variant,
/// fields: the field name is only non-`None` in the case of a struct
/// variant.
- EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo<'a>>),
+ EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo<'a>>),
/// Non-matching variants of the enum, but with all state hidden from
/// the consequent code. The first component holds `Ident`s for all of
// expressions for referencing every field of every
// Self arg, assuming all are instances of VariantK.
// Build up code associated with such a case.
- let substructure = EnumMatching(index, variant, field_tuples);
+ let substructure = EnumMatching(index, variants.len(), variant, field_tuples);
let arm_expr = self.call_substructure_method(cx,
trait_,
type_ident,
// We need a default case that handles the fieldless variants.
// The index and actual variant aren't meaningful in this case,
// so just use whatever
+ let substructure = EnumMatching(0, variants.len(), v, Vec::new());
Some(self.call_substructure_method(cx,
trait_,
type_ident,
&self_args[..],
nonself_args,
- &EnumMatching(0, v, Vec::new())))
+ &substructure))
}
_ if variants.len() > 1 && self_args.len() > 1 => {
// Since we know that all the arguments will match if we reach
let mut stmts = Vec::new();
let fields = match *substr.fields {
- Struct(_, ref fs) => fs,
+ Struct(_, ref fs) | EnumMatching(_, 1, .., ref fs) => fs,
EnumMatching(.., ref fs) => {
let variant_value = deriving::call_intrinsic(cx,
trait_span,
pub fn f1_uint_uint() {
f1(2u32, 4u32);
//~^ ERROR `u32: Foo` is not satisfied
+ //~| ERROR `u32: Foo` is not satisfied
}
pub fn f1_uint_int() {
f1(2u32, 4i32);
//~^ ERROR `u32: Foo` is not satisfied
+ //~| ERROR `u32: Foo` is not satisfied
}
pub fn f2_int() {
#![feature(intrinsics)]
extern "rust-intrinsic" {
pub static breakpoint : unsafe extern "rust-intrinsic" fn();
- //~^ ERROR intrinsic has wrong type
+ //~^ ERROR intrinsic must be a function
}
-fn main() { unsafe { breakpoint(); } }
\ No newline at end of file
+fn main() { unsafe { breakpoint(); } }
//~^ ERROR E0277
//~| NOTE trait message
//~| NOTE required by
+ //~| ERROR E0277
+ //~| NOTE trait message
Index::index(&[] as &[i32], Foo(2u32));
//~^ ERROR E0277
//~| NOTE on impl for Foo
//~| NOTE required by
+ //~| ERROR E0277
+ //~| NOTE on impl for Foo
Index::index(&[] as &[i32], Bar(2u32));
//~^ ERROR E0277
//~| NOTE on impl for Bar
//~| NOTE required by
+ //~| ERROR E0277
+ //~| NOTE on impl for Bar
}
//~^ ERROR E0277
//~| NOTE a usize is required
//~| NOTE required by
+ //~| ERROR E0277
+ //~| NOTE a usize is required
}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <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.
-
-// Check that `T:'a` is contravariant in T.
-
-#![feature(rustc_attrs)]
-
-#[rustc_variance]
-trait Foo: 'static { //~ ERROR [o]
-}
-
-#[rustc_variance]
-trait Bar<T> { //~ ERROR [o, o]
- fn do_it(&self)
- where T: 'static;
-}
-
-fn main() { }
// Check that bounds on type parameters (other than `Self`) do not
// influence variance.
-#[rustc_variance]
-trait Getter<T> { //~ ERROR [o, o]
+trait Getter<T> {
fn get(&self) -> T;
}
-#[rustc_variance]
-trait Setter<T> { //~ ERROR [o, o]
+trait Setter<T> {
fn get(&self, T);
}
Foo(T)
}
-#[rustc_variance]
-trait TestTrait<U,T:Setter<U>> { //~ ERROR [o, o, o]
- fn getter(&self, u: U) -> T;
-}
-
-#[rustc_variance]
-trait TestTrait2<U> : Getter<U> { //~ ERROR [o, o]
-}
-
-#[rustc_variance]
-trait TestTrait3<U> { //~ ERROR [o, o]
- fn getter<T:Getter<U>>(&self);
-}
-
#[rustc_variance]
struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [*, +]
t: T
m: TestMut<B, A>
}
-#[rustc_variance]
-trait Getter<A> { //~ ERROR [o, o]
+trait Getter<A> {
fn get(&self) -> A;
}
-#[rustc_variance]
-trait Setter<A> { //~ ERROR [o, o]
- fn set(&mut self, a: A);
-}
-
-#[rustc_variance]
-trait GetterSetter<A> { //~ ERROR [o, o]
- fn get(&self) -> A;
+trait Setter<A> {
fn set(&mut self, a: A);
}
-#[rustc_variance]
-trait GetterInTypeBound<A> { //~ ERROR [o, o]
- // Here, the use of `A` in the method bound *does* affect
- // variance. Think of it as if the method requested a dictionary
- // for `T:Getter<A>`. Since this dictionary is an input, it is
- // contravariant, and the Getter is covariant w/r/t A, yielding an
- // overall contravariant result.
- fn do_it<T:Getter<A>>(&self);
-}
-
-#[rustc_variance]
-trait SetterInTypeBound<A> { //~ ERROR [o, o]
- fn do_it<T:Setter<A>>(&self);
-}
-
#[rustc_variance]
struct TestObject<A, R> { //~ ERROR [o, o]
n: Box<Setter<A>+Send>,
}
}
-fn fake_hash(v: &mut Vec<u8>, e: E) {
- e.hash(&mut FakeHasher(v));
+fn fake_hash<A: Hash>(v: &mut Vec<u8>, a: A) {
+ a.hash(&mut FakeHasher(v));
}
fn main() {
fake_hash(&mut va, E::A);
fake_hash(&mut vb, E::B);
assert!(va != vb);
+
+ // issue #39137: single variant enum hash should not hash discriminant
+ #[derive(Hash)]
+ enum SingleVariantEnum {
+ A(u8),
+ }
+ let mut v = vec![];
+ fake_hash(&mut v, SingleVariantEnum::A(17));
+ assert_eq!(vec![17], v);
}