Skip to content

Commit 813d828

Browse files
committed
rollup merge of #19821: bkoropoff/issue-19791
Normalize late-bound regions in bare functions, stack closures, and traits and include them in the generated hash. Closes #19791 r? @nikomatsakis (does my normalization make sense?) cc @alexcrichton
2 parents b2ff8bb + 0a1798d commit 813d828

File tree

3 files changed

+248
-114
lines changed

3 files changed

+248
-114
lines changed

src/librustc/middle/ty.rs

+158-114
Original file line numberDiff line numberDiff line change
@@ -5825,126 +5825,153 @@ pub fn trait_item_of_item(tcx: &ctxt, def_id: ast::DefId)
58255825
/// context it's calculated within. This is used by the `type_id` intrinsic.
58265826
pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 {
58275827
let mut state = sip::SipState::new();
5828-
macro_rules! byte( ($b:expr) => { ($b as u8).hash(&mut state) } );
5829-
macro_rules! hash( ($e:expr) => { $e.hash(&mut state) } );
5830-
5831-
let region = |_state: &mut sip::SipState, r: Region| {
5832-
match r {
5833-
ReStatic => {}
5834-
5835-
ReEmpty |
5836-
ReEarlyBound(..) |
5837-
ReLateBound(..) |
5838-
ReFree(..) |
5839-
ReScope(..) |
5840-
ReInfer(..) => {
5841-
tcx.sess.bug("non-static region found when hashing a type")
5828+
helper(tcx, ty, svh, &mut state);
5829+
return state.result();
5830+
5831+
fn helper(tcx: &ctxt, ty: Ty, svh: &Svh, state: &mut sip::SipState) {
5832+
macro_rules! byte( ($b:expr) => { ($b as u8).hash(state) } );
5833+
macro_rules! hash( ($e:expr) => { $e.hash(state) } );
5834+
5835+
let region = |state: &mut sip::SipState, r: Region| {
5836+
match r {
5837+
ReStatic => {}
5838+
ReLateBound(db, BrAnon(i)) => {
5839+
db.hash(state);
5840+
i.hash(state);
5841+
}
5842+
ReEmpty |
5843+
ReEarlyBound(..) |
5844+
ReLateBound(..) |
5845+
ReFree(..) |
5846+
ReScope(..) |
5847+
ReInfer(..) => {
5848+
tcx.sess.bug("unexpected region found when hashing a type")
5849+
}
58425850
}
5843-
}
5844-
};
5845-
let did = |state: &mut sip::SipState, did: DefId| {
5846-
let h = if ast_util::is_local(did) {
5847-
svh.clone()
5848-
} else {
5849-
tcx.sess.cstore.get_crate_hash(did.krate)
58505851
};
5851-
h.as_str().hash(state);
5852-
did.node.hash(state);
5853-
};
5854-
let mt = |state: &mut sip::SipState, mt: mt| {
5855-
mt.mutbl.hash(state);
5856-
};
5857-
ty::walk_ty(ty, |ty| {
5858-
match ty.sty {
5859-
ty_bool => byte!(2),
5860-
ty_char => byte!(3),
5861-
ty_int(i) => {
5862-
byte!(4);
5863-
hash!(i);
5864-
}
5865-
ty_uint(u) => {
5866-
byte!(5);
5867-
hash!(u);
5868-
}
5869-
ty_float(f) => {
5870-
byte!(6);
5871-
hash!(f);
5872-
}
5873-
ty_str => {
5874-
byte!(7);
5875-
}
5876-
ty_enum(d, _) => {
5877-
byte!(8);
5878-
did(&mut state, d);
5879-
}
5880-
ty_uniq(_) => {
5881-
byte!(9);
5882-
}
5883-
ty_vec(_, Some(n)) => {
5884-
byte!(10);
5885-
n.hash(&mut state);
5886-
}
5887-
ty_vec(_, None) => {
5888-
byte!(11);
5889-
}
5890-
ty_ptr(m) => {
5891-
byte!(12);
5892-
mt(&mut state, m);
5893-
}
5894-
ty_rptr(r, m) => {
5895-
byte!(13);
5896-
region(&mut state, r);
5897-
mt(&mut state, m);
5898-
}
5899-
ty_bare_fn(ref b) => {
5900-
byte!(14);
5901-
hash!(b.unsafety);
5902-
hash!(b.abi);
5852+
let did = |state: &mut sip::SipState, did: DefId| {
5853+
let h = if ast_util::is_local(did) {
5854+
svh.clone()
5855+
} else {
5856+
tcx.sess.cstore.get_crate_hash(did.krate)
5857+
};
5858+
h.as_str().hash(state);
5859+
did.node.hash(state);
5860+
};
5861+
let mt = |state: &mut sip::SipState, mt: mt| {
5862+
mt.mutbl.hash(state);
5863+
};
5864+
let fn_sig = |state: &mut sip::SipState, sig: &FnSig| {
5865+
let sig = anonymize_late_bound_regions(tcx, sig);
5866+
for a in sig.inputs.iter() { helper(tcx, *a, svh, state); }
5867+
if let ty::FnConverging(output) = sig.output {
5868+
helper(tcx, output, svh, state);
59035869
}
5904-
ty_closure(ref c) => {
5905-
byte!(15);
5906-
hash!(c.unsafety);
5907-
hash!(c.onceness);
5908-
hash!(c.bounds);
5909-
match c.store {
5910-
UniqTraitStore => byte!(0),
5911-
RegionTraitStore(r, m) => {
5912-
byte!(1)
5913-
region(&mut state, r);
5914-
assert_eq!(m, ast::MutMutable);
5870+
};
5871+
maybe_walk_ty(ty, |ty| {
5872+
match ty.sty {
5873+
ty_bool => byte!(2),
5874+
ty_char => byte!(3),
5875+
ty_int(i) => {
5876+
byte!(4);
5877+
hash!(i);
5878+
}
5879+
ty_uint(u) => {
5880+
byte!(5);
5881+
hash!(u);
5882+
}
5883+
ty_float(f) => {
5884+
byte!(6);
5885+
hash!(f);
5886+
}
5887+
ty_str => {
5888+
byte!(7);
5889+
}
5890+
ty_enum(d, _) => {
5891+
byte!(8);
5892+
did(state, d);
5893+
}
5894+
ty_uniq(_) => {
5895+
byte!(9);
5896+
}
5897+
ty_vec(_, Some(n)) => {
5898+
byte!(10);
5899+
n.hash(state);
5900+
}
5901+
ty_vec(_, None) => {
5902+
byte!(11);
5903+
}
5904+
ty_ptr(m) => {
5905+
byte!(12);
5906+
mt(state, m);
5907+
}
5908+
ty_rptr(r, m) => {
5909+
byte!(13);
5910+
region(state, r);
5911+
mt(state, m);
5912+
}
5913+
ty_bare_fn(ref b) => {
5914+
byte!(14);
5915+
hash!(b.unsafety);
5916+
hash!(b.abi);
5917+
fn_sig(state, &b.sig);
5918+
return false;
5919+
}
5920+
ty_closure(ref c) => {
5921+
byte!(15);
5922+
hash!(c.unsafety);
5923+
hash!(c.onceness);
5924+
hash!(c.bounds);
5925+
match c.store {
5926+
UniqTraitStore => byte!(0),
5927+
RegionTraitStore(r, m) => {
5928+
byte!(1);
5929+
region(state, r);
5930+
assert_eq!(m, ast::MutMutable);
5931+
}
59155932
}
5933+
5934+
fn_sig(state, &c.sig);
5935+
5936+
return false;
59165937
}
5917-
}
5918-
ty_trait(box TyTrait { ref principal, bounds }) => {
5919-
byte!(17);
5920-
did(&mut state, principal.def_id);
5921-
hash!(bounds);
5922-
}
5923-
ty_struct(d, _) => {
5924-
byte!(18);
5925-
did(&mut state, d);
5926-
}
5927-
ty_tup(ref inner) => {
5928-
byte!(19);
5929-
hash!(inner.len());
5930-
}
5931-
ty_param(p) => {
5932-
byte!(20);
5933-
hash!(p.idx);
5934-
did(&mut state, p.def_id);
5935-
}
5936-
ty_open(_) => byte!(22),
5937-
ty_infer(_) => unreachable!(),
5938-
ty_err => byte!(23),
5939-
ty_unboxed_closure(d, r, _) => {
5940-
byte!(24);
5941-
did(&mut state, d);
5942-
region(&mut state, r);
5943-
}
5944-
}
5945-
});
5938+
ty_trait(box TyTrait { ref principal, bounds }) => {
5939+
byte!(17);
5940+
did(state, principal.def_id);
5941+
hash!(bounds);
5942+
5943+
let principal = anonymize_late_bound_regions(tcx, principal);
5944+
for subty in principal.substs.types.iter() {
5945+
helper(tcx, *subty, svh, state);
5946+
}
59465947

5947-
state.result()
5948+
return false;
5949+
}
5950+
ty_struct(d, _) => {
5951+
byte!(18);
5952+
did(state, d);
5953+
}
5954+
ty_tup(ref inner) => {
5955+
byte!(19);
5956+
hash!(inner.len());
5957+
}
5958+
ty_param(p) => {
5959+
byte!(20);
5960+
hash!(p.idx);
5961+
did(state, p.def_id);
5962+
}
5963+
ty_open(_) => byte!(22),
5964+
ty_infer(_) => unreachable!(),
5965+
ty_err => byte!(23),
5966+
ty_unboxed_closure(d, r, _) => {
5967+
byte!(24);
5968+
did(state, d);
5969+
region(state, r);
5970+
}
5971+
}
5972+
true
5973+
});
5974+
}
59485975
}
59495976

59505977
impl Variance {
@@ -6284,6 +6311,23 @@ pub fn erase_late_bound_regions<'tcx, HR>(
62846311
replace_late_bound_regions(tcx, value, |_, _| ty::ReStatic).0
62856312
}
62866313

6314+
/// Rewrite any late-bound regions so that they are anonymous. Region numbers are
6315+
/// assigned starting at 1 and increasing monotonically in the order traversed
6316+
/// by the fold operation.
6317+
///
6318+
/// The chief purpose of this function is to canonicalize regions so that two
6319+
/// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become
6320+
/// structurally identical. For example, `for<'a, 'b> fn(&'a int, &'b int)` and
6321+
/// `for<'a, 'b> fn(&'b int, &'a int)` will become identical after anonymization.
6322+
pub fn anonymize_late_bound_regions<'tcx, HR>(tcx: &ctxt<'tcx>, sig: &HR) -> HR
6323+
where HR: HigherRankedFoldable<'tcx> {
6324+
let mut counter = 0;
6325+
replace_late_bound_regions(tcx, sig, |_, db| {
6326+
counter += 1;
6327+
ReLateBound(db, BrAnon(counter))
6328+
}).0
6329+
}
6330+
62876331
/// Replaces the late-bound-regions in `value` that are bound by `value`.
62886332
pub fn replace_late_bound_regions<'tcx, HR, F>(
62896333
tcx: &ty::ctxt<'tcx>,

src/libsyntax/print/pprust.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1005,8 +1005,13 @@ impl<'a> State<'a> {
10051005
fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) -> IoResult<()> {
10061006
if !t.bound_lifetimes.is_empty() {
10071007
try!(word(&mut self.s, "for<"));
1008+
let mut comma = false;
10081009
for lifetime_def in t.bound_lifetimes.iter() {
1010+
if comma {
1011+
try!(self.word_space(","))
1012+
}
10091013
try!(self.print_lifetime_def(lifetime_def));
1014+
comma = true;
10101015
}
10111016
try!(word(&mut self.s, ">"));
10121017
}
+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that type IDs correctly account for higher-rank lifetimes
12+
// Also acts as a regression test for an ICE (issue #19791)
13+
14+
#![feature(unboxed_closures)]
15+
16+
use std::intrinsics::TypeId;
17+
18+
fn main() {
19+
// Bare fns
20+
{
21+
let a = TypeId::of::<fn(&'static int, &'static int)>();
22+
let b = TypeId::of::<for<'a> fn(&'static int, &'a int)>();
23+
let c = TypeId::of::<for<'a, 'b> fn(&'a int, &'b int)>();
24+
let d = TypeId::of::<for<'a, 'b> fn(&'b int, &'a int)>();
25+
assert!(a != b);
26+
assert!(a != c);
27+
assert!(a != d);
28+
assert!(b != c);
29+
assert!(b != d);
30+
assert_eq!(c, d);
31+
32+
// Make sure De Bruijn indices are handled correctly
33+
let e = TypeId::of::<for<'a> fn(fn(&'a int) -> &'a int)>();
34+
let f = TypeId::of::<fn(for<'a> fn(&'a int) -> &'a int)>();
35+
assert!(e != f);
36+
}
37+
// Stack closures
38+
{
39+
let a = TypeId::of::<|&'static int, &'static int|>();
40+
let b = TypeId::of::<for<'a> |&'static int, &'a int|>();
41+
let c = TypeId::of::<for<'a, 'b> |&'a int, &'b int|>();
42+
let d = TypeId::of::<for<'a, 'b> |&'b int, &'a int|>();
43+
assert!(a != b);
44+
assert!(a != c);
45+
assert!(a != d);
46+
assert!(b != c);
47+
assert!(b != d);
48+
assert_eq!(c, d);
49+
50+
// Make sure De Bruijn indices are handled correctly
51+
let e = TypeId::of::<for<'a> |(|&'a int| -> &'a int)|>();
52+
let f = TypeId::of::<|for<'a> |&'a int| -> &'a int|>();
53+
assert!(e != f);
54+
}
55+
// Boxed unboxed closures
56+
{
57+
let a = TypeId::of::<Box<Fn(&'static int, &'static int)>>();
58+
let b = TypeId::of::<Box<for<'a> Fn(&'static int, &'a int)>>();
59+
let c = TypeId::of::<Box<for<'a, 'b> Fn(&'a int, &'b int)>>();
60+
let d = TypeId::of::<Box<for<'a, 'b> Fn(&'b int, &'a int)>>();
61+
assert!(a != b);
62+
assert!(a != c);
63+
assert!(a != d);
64+
assert!(b != c);
65+
assert!(b != d);
66+
assert_eq!(c, d);
67+
68+
// Make sure De Bruijn indices are handled correctly
69+
let e = TypeId::of::<Box<for<'a> Fn(Box<Fn(&'a int) -> &'a int>)>>();
70+
let f = TypeId::of::<Box<Fn(Box<for<'a> Fn(&'a int) -> &'a int>)>>();
71+
assert!(e != f);
72+
}
73+
// Raw unboxed closures
74+
// Note that every unboxed closure has its own anonymous type,
75+
// so no two IDs should equal each other, even when compatible
76+
{
77+
let a = id(|&: _: &int, _: &int| {});
78+
let b = id(|&: _: &int, _: &int| {});
79+
assert!(a != b);
80+
}
81+
82+
fn id<T:'static>(_: T) -> TypeId {
83+
TypeId::of::<T>()
84+
}
85+
}

0 commit comments

Comments
 (0)