Rewrite TypeId computation to not miss anything and work cross-crate.
This commit is contained in:
parent
b30eff7ba7
commit
d42da7b8f3
7 changed files with 248 additions and 191 deletions
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
//! misc. type-system utilities too small to deserve their own file
|
//! misc. type-system utilities too small to deserve their own file
|
||||||
|
|
||||||
use hir::svh::Svh;
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::DefId;
|
||||||
use ty::subst;
|
use ty::subst;
|
||||||
use infer::InferCtxt;
|
use infer::InferCtxt;
|
||||||
|
@ -18,6 +17,7 @@ use hir::pat_util;
|
||||||
use traits::{self, ProjectionMode};
|
use traits::{self, ProjectionMode};
|
||||||
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
|
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
|
||||||
use ty::{Disr, ParameterEnvironment};
|
use ty::{Disr, ParameterEnvironment};
|
||||||
|
use ty::fold::TypeVisitor;
|
||||||
use ty::layout::{Layout, LayoutError};
|
use ty::layout::{Layout, LayoutError};
|
||||||
use ty::TypeVariants::*;
|
use ty::TypeVariants::*;
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::hash::{Hash, SipHasher, Hasher};
|
use std::hash::{Hash, SipHasher, Hasher};
|
||||||
|
use std::intrinsics;
|
||||||
use syntax::ast::{self, Name};
|
use syntax::ast::{self, Name};
|
||||||
use syntax::attr::{self, SignedInt, UnsignedInt};
|
use syntax::attr::{self, SignedInt, UnsignedInt};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
@ -350,148 +351,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
|
|
||||||
/// Creates a hash of the type `Ty` which will be the same no matter what crate
|
/// Creates a hash of the type `Ty` which will be the same no matter what crate
|
||||||
/// context it's calculated within. This is used by the `type_id` intrinsic.
|
/// context it's calculated within. This is used by the `type_id` intrinsic.
|
||||||
pub fn hash_crate_independent(self, ty: Ty<'tcx>, svh: &Svh) -> u64 {
|
pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
|
||||||
let mut state = SipHasher::new();
|
let mut hasher = TypeIdHasher {
|
||||||
helper(self, ty, svh, &mut state);
|
tcx: self,
|
||||||
return state.finish();
|
state: SipHasher::new()
|
||||||
|
};
|
||||||
fn helper<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
hasher.visit_ty(ty);
|
||||||
ty: Ty<'tcx>, svh: &Svh,
|
hasher.state.finish()
|
||||||
state: &mut SipHasher) {
|
|
||||||
macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } }
|
|
||||||
macro_rules! hash { ($e:expr) => { $e.hash(state) } }
|
|
||||||
|
|
||||||
let region = |state: &mut SipHasher, r: ty::Region| {
|
|
||||||
match r {
|
|
||||||
ty::ReStatic | ty::ReErased => {}
|
|
||||||
ty::ReLateBound(db, ty::BrAnon(i)) => {
|
|
||||||
db.hash(state);
|
|
||||||
i.hash(state);
|
|
||||||
}
|
|
||||||
ty::ReEmpty |
|
|
||||||
ty::ReEarlyBound(..) |
|
|
||||||
ty::ReLateBound(..) |
|
|
||||||
ty::ReFree(..) |
|
|
||||||
ty::ReScope(..) |
|
|
||||||
ty::ReVar(..) |
|
|
||||||
ty::ReSkolemized(..) => {
|
|
||||||
bug!("unexpected region found when hashing a type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let did = |state: &mut SipHasher, did: DefId| {
|
|
||||||
let h = if did.is_local() {
|
|
||||||
svh.clone()
|
|
||||||
} else {
|
|
||||||
tcx.sess.cstore.crate_hash(did.krate)
|
|
||||||
};
|
|
||||||
h.hash(state);
|
|
||||||
did.index.hash(state);
|
|
||||||
};
|
|
||||||
let mt = |state: &mut SipHasher, mt: TypeAndMut| {
|
|
||||||
mt.mutbl.hash(state);
|
|
||||||
};
|
|
||||||
let fn_sig = |state: &mut SipHasher, sig: &ty::Binder<ty::FnSig<'tcx>>| {
|
|
||||||
let sig = tcx.anonymize_late_bound_regions(sig).0;
|
|
||||||
for a in &sig.inputs { helper(tcx, *a, svh, state); }
|
|
||||||
if let ty::FnConverging(output) = sig.output {
|
|
||||||
helper(tcx, output, svh, state);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ty.maybe_walk(|ty| {
|
|
||||||
match ty.sty {
|
|
||||||
TyBool => byte!(2),
|
|
||||||
TyChar => byte!(3),
|
|
||||||
TyInt(i) => {
|
|
||||||
byte!(4);
|
|
||||||
hash!(i);
|
|
||||||
}
|
|
||||||
TyUint(u) => {
|
|
||||||
byte!(5);
|
|
||||||
hash!(u);
|
|
||||||
}
|
|
||||||
TyFloat(f) => {
|
|
||||||
byte!(6);
|
|
||||||
hash!(f);
|
|
||||||
}
|
|
||||||
TyStr => {
|
|
||||||
byte!(7);
|
|
||||||
}
|
|
||||||
TyEnum(d, _) => {
|
|
||||||
byte!(8);
|
|
||||||
did(state, d.did);
|
|
||||||
}
|
|
||||||
TyBox(_) => {
|
|
||||||
byte!(9);
|
|
||||||
}
|
|
||||||
TyArray(_, n) => {
|
|
||||||
byte!(10);
|
|
||||||
n.hash(state);
|
|
||||||
}
|
|
||||||
TySlice(_) => {
|
|
||||||
byte!(11);
|
|
||||||
}
|
|
||||||
TyRawPtr(m) => {
|
|
||||||
byte!(12);
|
|
||||||
mt(state, m);
|
|
||||||
}
|
|
||||||
TyRef(r, m) => {
|
|
||||||
byte!(13);
|
|
||||||
region(state, *r);
|
|
||||||
mt(state, m);
|
|
||||||
}
|
|
||||||
TyFnDef(def_id, _, _) => {
|
|
||||||
byte!(14);
|
|
||||||
hash!(def_id);
|
|
||||||
}
|
|
||||||
TyFnPtr(ref b) => {
|
|
||||||
byte!(15);
|
|
||||||
hash!(b.unsafety);
|
|
||||||
hash!(b.abi);
|
|
||||||
fn_sig(state, &b.sig);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
TyTrait(ref data) => {
|
|
||||||
byte!(17);
|
|
||||||
did(state, data.principal_def_id());
|
|
||||||
hash!(data.bounds);
|
|
||||||
|
|
||||||
let principal = tcx.anonymize_late_bound_regions(&data.principal).0;
|
|
||||||
for subty in &principal.substs.types {
|
|
||||||
helper(tcx, subty, svh, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
TyStruct(d, _) => {
|
|
||||||
byte!(18);
|
|
||||||
did(state, d.did);
|
|
||||||
}
|
|
||||||
TyTuple(ref inner) => {
|
|
||||||
byte!(19);
|
|
||||||
hash!(inner.len());
|
|
||||||
}
|
|
||||||
TyParam(p) => {
|
|
||||||
byte!(20);
|
|
||||||
hash!(p.space);
|
|
||||||
hash!(p.idx);
|
|
||||||
hash!(p.name.as_str());
|
|
||||||
}
|
|
||||||
TyInfer(_) => bug!(),
|
|
||||||
TyError => byte!(21),
|
|
||||||
TyClosure(d, _) => {
|
|
||||||
byte!(22);
|
|
||||||
did(state, d);
|
|
||||||
}
|
|
||||||
TyProjection(ref data) => {
|
|
||||||
byte!(23);
|
|
||||||
did(state, data.trait_ref.def_id);
|
|
||||||
hash!(data.item_name.as_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this ADT is a dtorck type.
|
/// Returns true if this ADT is a dtorck type.
|
||||||
|
@ -525,6 +391,143 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||||
|
tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
||||||
|
state: SipHasher
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'gcx, 'tcx> TypeIdHasher<'a, 'gcx, 'tcx> {
|
||||||
|
fn hash<T: Hash>(&mut self, x: T) {
|
||||||
|
x.hash(&mut self.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hash_discriminant_u8<T>(&mut self, x: &T) {
|
||||||
|
let v = unsafe {
|
||||||
|
intrinsics::discriminant_value(x)
|
||||||
|
};
|
||||||
|
let b = v as u8;
|
||||||
|
assert_eq!(v, b as u64);
|
||||||
|
self.hash(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn def_id(&mut self, did: DefId) {
|
||||||
|
// Hash the crate identification information.
|
||||||
|
let name = self.tcx.crate_name(did.krate);
|
||||||
|
let disambiguator = self.tcx.crate_disambiguator(did.krate);
|
||||||
|
self.hash((name, disambiguator));
|
||||||
|
|
||||||
|
// Hash the item path within that crate.
|
||||||
|
// FIXME(#35379) This should use a deterministic
|
||||||
|
// DefPath hashing mechanism, not the DefIndex.
|
||||||
|
self.hash(did.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
|
||||||
|
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
|
||||||
|
// Distinguish between the Ty variants uniformly.
|
||||||
|
self.hash_discriminant_u8(&ty.sty);
|
||||||
|
|
||||||
|
match ty.sty {
|
||||||
|
TyInt(i) => self.hash(i),
|
||||||
|
TyUint(u) => self.hash(u),
|
||||||
|
TyFloat(f) => self.hash(f),
|
||||||
|
TyStruct(d, _) |
|
||||||
|
TyEnum(d, _) => self.def_id(d.did),
|
||||||
|
TyArray(_, n) => self.hash(n),
|
||||||
|
TyRawPtr(m) |
|
||||||
|
TyRef(_, m) => self.hash(m.mutbl),
|
||||||
|
TyClosure(def_id, _) |
|
||||||
|
TyFnDef(def_id, _, _) => self.def_id(def_id),
|
||||||
|
TyFnPtr(f) => {
|
||||||
|
self.hash(f.unsafety);
|
||||||
|
self.hash(f.abi);
|
||||||
|
self.hash(f.sig.variadic());
|
||||||
|
}
|
||||||
|
TyTrait(ref data) => {
|
||||||
|
// Trait objects have a list of projection bounds
|
||||||
|
// that are not guaranteed to be sorted in an order
|
||||||
|
// that gets preserved across crates, so we need
|
||||||
|
// to sort them again by the name, in string form.
|
||||||
|
|
||||||
|
// Hash the whole principal trait ref.
|
||||||
|
self.def_id(data.principal_def_id());
|
||||||
|
data.principal.visit_with(self);
|
||||||
|
|
||||||
|
// Hash region and builtin bounds.
|
||||||
|
data.bounds.region_bound.visit_with(self);
|
||||||
|
self.hash(data.bounds.builtin_bounds);
|
||||||
|
|
||||||
|
// Only projection bounds are left, sort and hash them.
|
||||||
|
let mut projection_bounds: Vec<_> = data.bounds.projection_bounds
|
||||||
|
.iter()
|
||||||
|
.map(|b| (b.item_name().as_str(), b))
|
||||||
|
.collect();
|
||||||
|
projection_bounds.sort_by_key(|&(ref name, _)| name.clone());
|
||||||
|
for (name, bound) in projection_bounds {
|
||||||
|
self.def_id(bound.0.projection_ty.trait_ref.def_id);
|
||||||
|
self.hash(name);
|
||||||
|
bound.visit_with(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bypass super_visit_with, we've visited everything.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TyTuple(tys) => {
|
||||||
|
self.hash(tys.len());
|
||||||
|
}
|
||||||
|
TyParam(p) => {
|
||||||
|
self.hash(p.space);
|
||||||
|
self.hash(p.idx);
|
||||||
|
self.hash(p.name.as_str());
|
||||||
|
}
|
||||||
|
TyProjection(ref data) => {
|
||||||
|
self.def_id(data.trait_ref.def_id);
|
||||||
|
self.hash(data.item_name.as_str());
|
||||||
|
}
|
||||||
|
TyBool |
|
||||||
|
TyChar |
|
||||||
|
TyStr |
|
||||||
|
TyBox(_) |
|
||||||
|
TySlice(_) |
|
||||||
|
TyError => {}
|
||||||
|
TyInfer(_) => bug!()
|
||||||
|
}
|
||||||
|
|
||||||
|
ty.super_visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_region(&mut self, r: ty::Region) -> bool {
|
||||||
|
match r {
|
||||||
|
ty::ReStatic | ty::ReErased => {
|
||||||
|
self.hash::<u32>(0);
|
||||||
|
}
|
||||||
|
ty::ReLateBound(db, ty::BrAnon(i)) => {
|
||||||
|
assert!(db.depth > 0);
|
||||||
|
self.hash::<u32>(db.depth);
|
||||||
|
self.hash(i);
|
||||||
|
}
|
||||||
|
ty::ReEmpty |
|
||||||
|
ty::ReEarlyBound(..) |
|
||||||
|
ty::ReLateBound(..) |
|
||||||
|
ty::ReFree(..) |
|
||||||
|
ty::ReScope(..) |
|
||||||
|
ty::ReVar(..) |
|
||||||
|
ty::ReSkolemized(..) => {
|
||||||
|
bug!("unexpected region found when hashing a type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, x: &ty::Binder<T>) -> bool {
|
||||||
|
// Anonymize late-bound regions so that, for example:
|
||||||
|
// `for<'a, b> fn(&'a &'b T)` and `for<'a, b> fn(&'b &'a T)`
|
||||||
|
// result in the same TypeId (the two types are equivalent).
|
||||||
|
self.tcx.anonymize_late_bound_regions(x).super_visit_with(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> ty::TyS<'tcx> {
|
impl<'a, 'tcx> ty::TyS<'tcx> {
|
||||||
fn impls_bound(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
fn impls_bound(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
param_env: &ParameterEnvironment<'tcx>,
|
param_env: &ParameterEnvironment<'tcx>,
|
||||||
|
|
|
@ -406,9 +406,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||||
C_str_slice(ccx, ty_name)
|
C_str_slice(ccx, ty_name)
|
||||||
}
|
}
|
||||||
(_, "type_id") => {
|
(_, "type_id") => {
|
||||||
let hash = ccx.tcx().hash_crate_independent(*substs.types.get(FnSpace, 0),
|
C_u64(ccx, ccx.tcx().type_id_hash(*substs.types.get(FnSpace, 0)))
|
||||||
&ccx.link_meta().crate_hash);
|
|
||||||
C_u64(ccx, hash)
|
|
||||||
}
|
}
|
||||||
(_, "init_dropped") => {
|
(_, "init_dropped") => {
|
||||||
let tp_ty = *substs.types.get(FnSpace, 0);
|
let tp_ty = *substs.types.get(FnSpace, 0);
|
||||||
|
|
|
@ -21,14 +21,16 @@ pub struct E(Result<&'static str, isize>);
|
||||||
pub type F = Option<isize>;
|
pub type F = Option<isize>;
|
||||||
pub type G = usize;
|
pub type G = usize;
|
||||||
pub type H = &'static str;
|
pub type H = &'static str;
|
||||||
|
pub type I = Box<Fn()>;
|
||||||
|
|
||||||
pub unsafe fn id_A() -> TypeId { TypeId::of::<A>() }
|
pub fn id_A() -> TypeId { TypeId::of::<A>() }
|
||||||
pub unsafe fn id_B() -> TypeId { TypeId::of::<B>() }
|
pub fn id_B() -> TypeId { TypeId::of::<B>() }
|
||||||
pub unsafe fn id_C() -> TypeId { TypeId::of::<C>() }
|
pub fn id_C() -> TypeId { TypeId::of::<C>() }
|
||||||
pub unsafe fn id_D() -> TypeId { TypeId::of::<D>() }
|
pub fn id_D() -> TypeId { TypeId::of::<D>() }
|
||||||
pub unsafe fn id_E() -> TypeId { TypeId::of::<E>() }
|
pub fn id_E() -> TypeId { TypeId::of::<E>() }
|
||||||
pub unsafe fn id_F() -> TypeId { TypeId::of::<F>() }
|
pub fn id_F() -> TypeId { TypeId::of::<F>() }
|
||||||
pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
|
pub fn id_G() -> TypeId { TypeId::of::<G>() }
|
||||||
pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }
|
pub fn id_H() -> TypeId { TypeId::of::<H>() }
|
||||||
|
pub fn id_I() -> TypeId { TypeId::of::<I>() }
|
||||||
|
|
||||||
pub unsafe fn foo<T: Any>() -> TypeId { TypeId::of::<T>() }
|
pub fn foo<T: Any>() -> TypeId { TypeId::of::<T>() }
|
||||||
|
|
|
@ -21,14 +21,16 @@ pub struct E(Result<&'static str, isize>);
|
||||||
pub type F = Option<isize>;
|
pub type F = Option<isize>;
|
||||||
pub type G = usize;
|
pub type G = usize;
|
||||||
pub type H = &'static str;
|
pub type H = &'static str;
|
||||||
|
pub type I = Box<Fn()>;
|
||||||
|
|
||||||
pub unsafe fn id_A() -> TypeId { TypeId::of::<A>() }
|
pub fn id_A() -> TypeId { TypeId::of::<A>() }
|
||||||
pub unsafe fn id_B() -> TypeId { TypeId::of::<B>() }
|
pub fn id_B() -> TypeId { TypeId::of::<B>() }
|
||||||
pub unsafe fn id_C() -> TypeId { TypeId::of::<C>() }
|
pub fn id_C() -> TypeId { TypeId::of::<C>() }
|
||||||
pub unsafe fn id_D() -> TypeId { TypeId::of::<D>() }
|
pub fn id_D() -> TypeId { TypeId::of::<D>() }
|
||||||
pub unsafe fn id_E() -> TypeId { TypeId::of::<E>() }
|
pub fn id_E() -> TypeId { TypeId::of::<E>() }
|
||||||
pub unsafe fn id_F() -> TypeId { TypeId::of::<F>() }
|
pub fn id_F() -> TypeId { TypeId::of::<F>() }
|
||||||
pub unsafe fn id_G() -> TypeId { TypeId::of::<G>() }
|
pub fn id_G() -> TypeId { TypeId::of::<G>() }
|
||||||
pub unsafe fn id_H() -> TypeId { TypeId::of::<H>() }
|
pub fn id_H() -> TypeId { TypeId::of::<H>() }
|
||||||
|
pub fn id_I() -> TypeId { TypeId::of::<I>() }
|
||||||
|
|
||||||
pub unsafe fn foo<T:Any>() -> TypeId { TypeId::of::<T>() }
|
pub fn foo<T: Any>() -> TypeId { TypeId::of::<T>() }
|
||||||
|
|
40
src/test/run-pass/type-id-higher-rank-2.rs
Normal file
40
src/test/run-pass/type-id-higher-rank-2.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Test that we can't ignore lifetimes by going through Any.
|
||||||
|
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
struct Foo<'a>(&'a str);
|
||||||
|
|
||||||
|
fn good(s: &String) -> Foo { Foo(s) }
|
||||||
|
|
||||||
|
fn bad1(s: String) -> Option<&'static str> {
|
||||||
|
let a: Box<Any> = Box::new(good as fn(&String) -> Foo);
|
||||||
|
a.downcast_ref::<fn(&String) -> Foo<'static>>().map(|f| f(&s).0)
|
||||||
|
}
|
||||||
|
|
||||||
|
trait AsStr<'a, 'b> {
|
||||||
|
fn get(&'a self) -> &'b str;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AsStr<'a, 'a> for String {
|
||||||
|
fn get(&'a self) -> &'a str { self }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bad2(s: String) -> Option<&'static str> {
|
||||||
|
let a: Box<Any> = Box::new(Box::new(s) as Box<for<'a> AsStr<'a, 'a>>);
|
||||||
|
a.downcast_ref::<Box<for<'a> AsStr<'a, 'static>>>().map(|x| x.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
assert_eq!(bad1(String::from("foo")), None);
|
||||||
|
assert_eq!(bad2(String::from("bar")), None);
|
||||||
|
}
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
use std::any::{Any, TypeId};
|
use std::any::{Any, TypeId};
|
||||||
|
|
||||||
|
struct Struct<'a>(&'a ());
|
||||||
|
trait Trait<'a> {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Bare fns
|
// Bare fns
|
||||||
{
|
{
|
||||||
|
@ -34,6 +37,14 @@ fn main() {
|
||||||
let e = TypeId::of::<for<'a> fn(fn(&'a isize) -> &'a isize)>();
|
let e = TypeId::of::<for<'a> fn(fn(&'a isize) -> &'a isize)>();
|
||||||
let f = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a isize)>();
|
let f = TypeId::of::<fn(for<'a> fn(&'a isize) -> &'a isize)>();
|
||||||
assert!(e != f);
|
assert!(e != f);
|
||||||
|
|
||||||
|
// Make sure lifetime parameters of items are not ignored.
|
||||||
|
let g = TypeId::of::<for<'a> fn(&'a Trait<'a>) -> Struct<'a>>();
|
||||||
|
let h = TypeId::of::<for<'a> fn(&'a Trait<'a>) -> Struct<'static>>();
|
||||||
|
let i = TypeId::of::<for<'a, 'b> fn(&'a Trait<'b>) -> Struct<'b>>();
|
||||||
|
assert!(g != h);
|
||||||
|
assert!(g != i);
|
||||||
|
assert!(h != i);
|
||||||
}
|
}
|
||||||
// Boxed unboxed closures
|
// Boxed unboxed closures
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,36 +23,37 @@ struct A;
|
||||||
struct Test;
|
struct Test;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
unsafe {
|
assert_eq!(TypeId::of::<other1::A>(), other1::id_A());
|
||||||
assert_eq!(TypeId::of::<other1::A>(), other1::id_A());
|
assert_eq!(TypeId::of::<other1::B>(), other1::id_B());
|
||||||
assert_eq!(TypeId::of::<other1::B>(), other1::id_B());
|
assert_eq!(TypeId::of::<other1::C>(), other1::id_C());
|
||||||
assert_eq!(TypeId::of::<other1::C>(), other1::id_C());
|
assert_eq!(TypeId::of::<other1::D>(), other1::id_D());
|
||||||
assert_eq!(TypeId::of::<other1::D>(), other1::id_D());
|
assert_eq!(TypeId::of::<other1::E>(), other1::id_E());
|
||||||
assert_eq!(TypeId::of::<other1::E>(), other1::id_E());
|
assert_eq!(TypeId::of::<other1::F>(), other1::id_F());
|
||||||
assert_eq!(TypeId::of::<other1::F>(), other1::id_F());
|
assert_eq!(TypeId::of::<other1::G>(), other1::id_G());
|
||||||
assert_eq!(TypeId::of::<other1::G>(), other1::id_G());
|
assert_eq!(TypeId::of::<other1::H>(), other1::id_H());
|
||||||
assert_eq!(TypeId::of::<other1::H>(), other1::id_H());
|
assert_eq!(TypeId::of::<other1::I>(), other1::id_I());
|
||||||
|
|
||||||
assert_eq!(TypeId::of::<other2::A>(), other2::id_A());
|
assert_eq!(TypeId::of::<other2::A>(), other2::id_A());
|
||||||
assert_eq!(TypeId::of::<other2::B>(), other2::id_B());
|
assert_eq!(TypeId::of::<other2::B>(), other2::id_B());
|
||||||
assert_eq!(TypeId::of::<other2::C>(), other2::id_C());
|
assert_eq!(TypeId::of::<other2::C>(), other2::id_C());
|
||||||
assert_eq!(TypeId::of::<other2::D>(), other2::id_D());
|
assert_eq!(TypeId::of::<other2::D>(), other2::id_D());
|
||||||
assert_eq!(TypeId::of::<other2::E>(), other2::id_E());
|
assert_eq!(TypeId::of::<other2::E>(), other2::id_E());
|
||||||
assert_eq!(TypeId::of::<other2::F>(), other2::id_F());
|
assert_eq!(TypeId::of::<other2::F>(), other2::id_F());
|
||||||
assert_eq!(TypeId::of::<other2::G>(), other2::id_G());
|
assert_eq!(TypeId::of::<other2::G>(), other2::id_G());
|
||||||
assert_eq!(TypeId::of::<other2::H>(), other2::id_H());
|
assert_eq!(TypeId::of::<other2::H>(), other2::id_H());
|
||||||
|
assert_eq!(TypeId::of::<other1::I>(), other2::id_I());
|
||||||
|
|
||||||
assert_eq!(other1::id_F(), other2::id_F());
|
assert_eq!(other1::id_F(), other2::id_F());
|
||||||
assert_eq!(other1::id_G(), other2::id_G());
|
assert_eq!(other1::id_G(), other2::id_G());
|
||||||
assert_eq!(other1::id_H(), other2::id_H());
|
assert_eq!(other1::id_H(), other2::id_H());
|
||||||
|
assert_eq!(other1::id_I(), other2::id_I());
|
||||||
|
|
||||||
assert_eq!(TypeId::of::<isize>(), other2::foo::<isize>());
|
assert_eq!(TypeId::of::<isize>(), other2::foo::<isize>());
|
||||||
assert_eq!(TypeId::of::<isize>(), other1::foo::<isize>());
|
assert_eq!(TypeId::of::<isize>(), other1::foo::<isize>());
|
||||||
assert_eq!(other2::foo::<isize>(), other1::foo::<isize>());
|
assert_eq!(other2::foo::<isize>(), other1::foo::<isize>());
|
||||||
assert_eq!(TypeId::of::<A>(), other2::foo::<A>());
|
assert_eq!(TypeId::of::<A>(), other2::foo::<A>());
|
||||||
assert_eq!(TypeId::of::<A>(), other1::foo::<A>());
|
assert_eq!(TypeId::of::<A>(), other1::foo::<A>());
|
||||||
assert_eq!(other2::foo::<A>(), other1::foo::<A>());
|
assert_eq!(other2::foo::<A>(), other1::foo::<A>());
|
||||||
}
|
|
||||||
|
|
||||||
// sanity test of TypeId
|
// sanity test of TypeId
|
||||||
let (a, b, c) = (TypeId::of::<usize>(), TypeId::of::<&'static str>(),
|
let (a, b, c) = (TypeId::of::<usize>(), TypeId::of::<&'static str>(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue