|
10 | 10 |
|
11 | 11 | //! misc. type-system utilities too small to deserve their own file |
12 | 12 |
|
13 | | -use hir::svh::Svh; |
14 | 13 | use hir::def_id::DefId; |
15 | 14 | use ty::subst; |
16 | 15 | use infer::InferCtxt; |
17 | 16 | use hir::pat_util; |
18 | 17 | use traits::{self, ProjectionMode}; |
19 | 18 | use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; |
20 | 19 | use ty::{Disr, ParameterEnvironment}; |
| 20 | +use ty::fold::TypeVisitor; |
21 | 21 | use ty::layout::{Layout, LayoutError}; |
22 | 22 | use ty::TypeVariants::*; |
23 | 23 |
|
24 | 24 | use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; |
25 | 25 |
|
26 | 26 | use std::cmp; |
27 | 27 | use std::hash::{Hash, SipHasher, Hasher}; |
| 28 | +use std::intrinsics; |
28 | 29 | use syntax::ast::{self, Name}; |
29 | 30 | use syntax::attr::{self, SignedInt, UnsignedInt}; |
30 | 31 | use syntax_pos::Span; |
@@ -350,148 +351,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { |
350 | 351 |
|
351 | 352 | /// Creates a hash of the type `Ty` which will be the same no matter what crate |
352 | 353 | /// context it's calculated within. This is used by the `type_id` intrinsic. |
353 | | - pub fn hash_crate_independent(self, ty: Ty<'tcx>, svh: &Svh) -> u64 { |
354 | | - let mut state = SipHasher::new(); |
355 | | - helper(self, ty, svh, &mut state); |
356 | | - return state.finish(); |
357 | | - |
358 | | - fn helper<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, |
359 | | - ty: Ty<'tcx>, svh: &Svh, |
360 | | - state: &mut SipHasher) { |
361 | | - macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } } |
362 | | - macro_rules! hash { ($e:expr) => { $e.hash(state) } } |
363 | | - |
364 | | - let region = |state: &mut SipHasher, r: ty::Region| { |
365 | | - match r { |
366 | | - ty::ReStatic | ty::ReErased => {} |
367 | | - ty::ReLateBound(db, ty::BrAnon(i)) => { |
368 | | - db.hash(state); |
369 | | - i.hash(state); |
370 | | - } |
371 | | - ty::ReEmpty | |
372 | | - ty::ReEarlyBound(..) | |
373 | | - ty::ReLateBound(..) | |
374 | | - ty::ReFree(..) | |
375 | | - ty::ReScope(..) | |
376 | | - ty::ReVar(..) | |
377 | | - ty::ReSkolemized(..) => { |
378 | | - bug!("unexpected region found when hashing a type") |
379 | | - } |
380 | | - } |
381 | | - }; |
382 | | - let did = |state: &mut SipHasher, did: DefId| { |
383 | | - let h = if did.is_local() { |
384 | | - svh.clone() |
385 | | - } else { |
386 | | - tcx.sess.cstore.crate_hash(did.krate) |
387 | | - }; |
388 | | - h.hash(state); |
389 | | - did.index.hash(state); |
390 | | - }; |
391 | | - let mt = |state: &mut SipHasher, mt: TypeAndMut| { |
392 | | - mt.mutbl.hash(state); |
393 | | - }; |
394 | | - let fn_sig = |state: &mut SipHasher, sig: &ty::Binder<ty::FnSig<'tcx>>| { |
395 | | - let sig = tcx.anonymize_late_bound_regions(sig).0; |
396 | | - for a in &sig.inputs { helper(tcx, *a, svh, state); } |
397 | | - if let ty::FnConverging(output) = sig.output { |
398 | | - helper(tcx, output, svh, state); |
399 | | - } |
400 | | - }; |
401 | | - ty.maybe_walk(|ty| { |
402 | | - match ty.sty { |
403 | | - TyBool => byte!(2), |
404 | | - TyChar => byte!(3), |
405 | | - TyInt(i) => { |
406 | | - byte!(4); |
407 | | - hash!(i); |
408 | | - } |
409 | | - TyUint(u) => { |
410 | | - byte!(5); |
411 | | - hash!(u); |
412 | | - } |
413 | | - TyFloat(f) => { |
414 | | - byte!(6); |
415 | | - hash!(f); |
416 | | - } |
417 | | - TyStr => { |
418 | | - byte!(7); |
419 | | - } |
420 | | - TyEnum(d, _) => { |
421 | | - byte!(8); |
422 | | - did(state, d.did); |
423 | | - } |
424 | | - TyBox(_) => { |
425 | | - byte!(9); |
426 | | - } |
427 | | - TyArray(_, n) => { |
428 | | - byte!(10); |
429 | | - n.hash(state); |
430 | | - } |
431 | | - TySlice(_) => { |
432 | | - byte!(11); |
433 | | - } |
434 | | - TyRawPtr(m) => { |
435 | | - byte!(12); |
436 | | - mt(state, m); |
437 | | - } |
438 | | - TyRef(r, m) => { |
439 | | - byte!(13); |
440 | | - region(state, *r); |
441 | | - mt(state, m); |
442 | | - } |
443 | | - TyFnDef(def_id, _, _) => { |
444 | | - byte!(14); |
445 | | - hash!(def_id); |
446 | | - } |
447 | | - TyFnPtr(ref b) => { |
448 | | - byte!(15); |
449 | | - hash!(b.unsafety); |
450 | | - hash!(b.abi); |
451 | | - fn_sig(state, &b.sig); |
452 | | - return false; |
453 | | - } |
454 | | - TyTrait(ref data) => { |
455 | | - byte!(17); |
456 | | - did(state, data.principal_def_id()); |
457 | | - hash!(data.bounds); |
458 | | - |
459 | | - let principal = tcx.anonymize_late_bound_regions(&data.principal).0; |
460 | | - for subty in &principal.substs.types { |
461 | | - helper(tcx, subty, svh, state); |
462 | | - } |
463 | | - |
464 | | - return false; |
465 | | - } |
466 | | - TyStruct(d, _) => { |
467 | | - byte!(18); |
468 | | - did(state, d.did); |
469 | | - } |
470 | | - TyTuple(ref inner) => { |
471 | | - byte!(19); |
472 | | - hash!(inner.len()); |
473 | | - } |
474 | | - TyParam(p) => { |
475 | | - byte!(20); |
476 | | - hash!(p.space); |
477 | | - hash!(p.idx); |
478 | | - hash!(p.name.as_str()); |
479 | | - } |
480 | | - TyInfer(_) => bug!(), |
481 | | - TyError => byte!(21), |
482 | | - TyClosure(d, _) => { |
483 | | - byte!(22); |
484 | | - did(state, d); |
485 | | - } |
486 | | - TyProjection(ref data) => { |
487 | | - byte!(23); |
488 | | - did(state, data.trait_ref.def_id); |
489 | | - hash!(data.item_name.as_str()); |
490 | | - } |
491 | | - } |
492 | | - true |
493 | | - }); |
494 | | - } |
| 354 | + pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { |
| 355 | + let mut hasher = TypeIdHasher { |
| 356 | + tcx: self, |
| 357 | + state: SipHasher::new() |
| 358 | + }; |
| 359 | + hasher.visit_ty(ty); |
| 360 | + hasher.state.finish() |
495 | 361 | } |
496 | 362 |
|
497 | 363 | /// Returns true if this ADT is a dtorck type. |
@@ -525,6 +391,143 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { |
525 | 391 | } |
526 | 392 | } |
527 | 393 |
|
| 394 | +struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { |
| 395 | + tcx: TyCtxt<'a, 'gcx, 'tcx>, |
| 396 | + state: SipHasher |
| 397 | +} |
| 398 | + |
| 399 | +impl<'a, 'gcx, 'tcx> TypeIdHasher<'a, 'gcx, 'tcx> { |
| 400 | + fn hash<T: Hash>(&mut self, x: T) { |
| 401 | + x.hash(&mut self.state); |
| 402 | + } |
| 403 | + |
| 404 | + fn hash_discriminant_u8<T>(&mut self, x: &T) { |
| 405 | + let v = unsafe { |
| 406 | + intrinsics::discriminant_value(x) |
| 407 | + }; |
| 408 | + let b = v as u8; |
| 409 | + assert_eq!(v, b as u64); |
| 410 | + self.hash(b) |
| 411 | + } |
| 412 | + |
| 413 | + fn def_id(&mut self, did: DefId) { |
| 414 | + // Hash the crate identification information. |
| 415 | + let name = self.tcx.crate_name(did.krate); |
| 416 | + let disambiguator = self.tcx.crate_disambiguator(did.krate); |
| 417 | + self.hash((name, disambiguator)); |
| 418 | + |
| 419 | + // Hash the item path within that crate. |
| 420 | + // FIXME(#35379) This should use a deterministic |
| 421 | + // DefPath hashing mechanism, not the DefIndex. |
| 422 | + self.hash(did.index); |
| 423 | + } |
| 424 | +} |
| 425 | + |
| 426 | +impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { |
| 427 | + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { |
| 428 | + // Distinguish between the Ty variants uniformly. |
| 429 | + self.hash_discriminant_u8(&ty.sty); |
| 430 | + |
| 431 | + match ty.sty { |
| 432 | + TyInt(i) => self.hash(i), |
| 433 | + TyUint(u) => self.hash(u), |
| 434 | + TyFloat(f) => self.hash(f), |
| 435 | + TyStruct(d, _) | |
| 436 | + TyEnum(d, _) => self.def_id(d.did), |
| 437 | + TyArray(_, n) => self.hash(n), |
| 438 | + TyRawPtr(m) | |
| 439 | + TyRef(_, m) => self.hash(m.mutbl), |
| 440 | + TyClosure(def_id, _) | |
| 441 | + TyFnDef(def_id, _, _) => self.def_id(def_id), |
| 442 | + TyFnPtr(f) => { |
| 443 | + self.hash(f.unsafety); |
| 444 | + self.hash(f.abi); |
| 445 | + self.hash(f.sig.variadic()); |
| 446 | + } |
| 447 | + TyTrait(ref data) => { |
| 448 | + // Trait objects have a list of projection bounds |
| 449 | + // that are not guaranteed to be sorted in an order |
| 450 | + // that gets preserved across crates, so we need |
| 451 | + // to sort them again by the name, in string form. |
| 452 | + |
| 453 | + // Hash the whole principal trait ref. |
| 454 | + self.def_id(data.principal_def_id()); |
| 455 | + data.principal.visit_with(self); |
| 456 | + |
| 457 | + // Hash region and builtin bounds. |
| 458 | + data.bounds.region_bound.visit_with(self); |
| 459 | + self.hash(data.bounds.builtin_bounds); |
| 460 | + |
| 461 | + // Only projection bounds are left, sort and hash them. |
| 462 | + let mut projection_bounds: Vec<_> = data.bounds.projection_bounds |
| 463 | + .iter() |
| 464 | + .map(|b| (b.item_name().as_str(), b)) |
| 465 | + .collect(); |
| 466 | + projection_bounds.sort_by_key(|&(ref name, _)| name.clone()); |
| 467 | + for (name, bound) in projection_bounds { |
| 468 | + self.def_id(bound.0.projection_ty.trait_ref.def_id); |
| 469 | + self.hash(name); |
| 470 | + bound.visit_with(self); |
| 471 | + } |
| 472 | + |
| 473 | + // Bypass super_visit_with, we've visited everything. |
| 474 | + return false; |
| 475 | + } |
| 476 | + TyTuple(tys) => { |
| 477 | + self.hash(tys.len()); |
| 478 | + } |
| 479 | + TyParam(p) => { |
| 480 | + self.hash(p.space); |
| 481 | + self.hash(p.idx); |
| 482 | + self.hash(p.name.as_str()); |
| 483 | + } |
| 484 | + TyProjection(ref data) => { |
| 485 | + self.def_id(data.trait_ref.def_id); |
| 486 | + self.hash(data.item_name.as_str()); |
| 487 | + } |
| 488 | + TyBool | |
| 489 | + TyChar | |
| 490 | + TyStr | |
| 491 | + TyBox(_) | |
| 492 | + TySlice(_) | |
| 493 | + TyError => {} |
| 494 | + TyInfer(_) => bug!() |
| 495 | + } |
| 496 | + |
| 497 | + ty.super_visit_with(self) |
| 498 | + } |
| 499 | + |
| 500 | + fn visit_region(&mut self, r: ty::Region) -> bool { |
| 501 | + match r { |
| 502 | + ty::ReStatic | ty::ReErased => { |
| 503 | + self.hash::<u32>(0); |
| 504 | + } |
| 505 | + ty::ReLateBound(db, ty::BrAnon(i)) => { |
| 506 | + assert!(db.depth > 0); |
| 507 | + self.hash::<u32>(db.depth); |
| 508 | + self.hash(i); |
| 509 | + } |
| 510 | + ty::ReEmpty | |
| 511 | + ty::ReEarlyBound(..) | |
| 512 | + ty::ReLateBound(..) | |
| 513 | + ty::ReFree(..) | |
| 514 | + ty::ReScope(..) | |
| 515 | + ty::ReVar(..) | |
| 516 | + ty::ReSkolemized(..) => { |
| 517 | + bug!("unexpected region found when hashing a type") |
| 518 | + } |
| 519 | + } |
| 520 | + false |
| 521 | + } |
| 522 | + |
| 523 | + fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, x: &ty::Binder<T>) -> bool { |
| 524 | + // Anonymize late-bound regions so that, for example: |
| 525 | + // `for<'a, b> fn(&'a &'b T)` and `for<'a, b> fn(&'b &'a T)` |
| 526 | + // result in the same TypeId (the two types are equivalent). |
| 527 | + self.tcx.anonymize_late_bound_regions(x).super_visit_with(self) |
| 528 | + } |
| 529 | +} |
| 530 | + |
528 | 531 | impl<'a, 'tcx> ty::TyS<'tcx> { |
529 | 532 | fn impls_bound(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, |
530 | 533 | param_env: &ParameterEnvironment<'tcx>, |
|
0 commit comments