@@ -18,6 +18,7 @@ use ich::{StableHashingContext, NodeIdHashingMode};
1818use util:: nodemap:: { FxHashMap , FxHashSet } ;
1919use ty;
2020
21+ use std:: fmt;
2122use std:: mem;
2223use std:: rc:: Rc ;
2324use syntax:: codemap;
@@ -31,6 +32,7 @@ use hir::def_id::DefId;
3132use hir:: intravisit:: { self , Visitor , NestedVisitorMap } ;
3233use hir:: { Block , Arm , Pat , PatKind , Stmt , Expr , Local } ;
3334use mir:: transform:: MirSource ;
35+ use rustc_data_structures:: indexed_vec:: Idx ;
3436use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher ,
3537 StableHasherResult } ;
3638
@@ -95,8 +97,24 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
9597/// placate the same deriving in `ty::FreeRegion`, but we may want to
9698/// actually attach a more meaningful ordering to scopes than the one
9799/// generated via deriving here.
100+ ///
101+ /// Scope is a bit-packed to save space - if `code` is SCOPE_DATA_REMAINDER_MAX
102+ /// or less, it is a `ScopeData::Remainder`, otherwise it is a type specified
103+ /// by the bitpacking.
104+ #[ derive( Clone , PartialEq , PartialOrd , Eq , Ord , Hash , Copy , RustcEncodable , RustcDecodable ) ]
105+ pub struct Scope {
106+ pub ( crate ) id : hir:: ItemLocalId ,
107+ pub ( crate ) code : u32
108+ }
109+
110+ const SCOPE_DATA_NODE : u32 = !0 ;
111+ const SCOPE_DATA_CALLSITE : u32 = !1 ;
112+ const SCOPE_DATA_ARGUMENTS : u32 = !2 ;
113+ const SCOPE_DATA_DESTRUCTION : u32 = !3 ;
114+ const SCOPE_DATA_REMAINDER_MAX : u32 = !4 ;
115+
98116#[ derive( Clone , PartialEq , PartialOrd , Eq , Ord , Hash , Debug , Copy , RustcEncodable , RustcDecodable ) ]
99- pub enum Scope {
117+ pub enum ScopeData {
100118 Node ( hir:: ItemLocalId ) ,
101119
102120 // Scope of the call-site for a function or closure
@@ -135,7 +153,90 @@ pub enum Scope {
135153 RustcDecodable , Debug , Copy ) ]
136154pub struct BlockRemainder {
137155 pub block : hir:: ItemLocalId ,
138- pub first_statement_index : u32 ,
156+ pub first_statement_index : FirstStatementIndex ,
157+ }
158+
159+ #[ derive( Clone , PartialEq , PartialOrd , Eq , Ord , Hash , RustcEncodable ,
160+ RustcDecodable , Copy ) ]
161+ pub struct FirstStatementIndex { pub idx : u32 }
162+
163+ impl Idx for FirstStatementIndex {
164+ fn new ( idx : usize ) -> Self {
165+ assert ! ( idx <= SCOPE_DATA_REMAINDER_MAX as usize ) ;
166+ FirstStatementIndex { idx : idx as u32 }
167+ }
168+
169+ fn index ( self ) -> usize {
170+ self . idx as usize
171+ }
172+ }
173+
174+ impl fmt:: Debug for FirstStatementIndex {
175+ fn fmt ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
176+ fmt:: Debug :: fmt ( & self . index ( ) , formatter)
177+ }
178+ }
179+
180+ impl From < ScopeData > for Scope {
181+ #[ inline]
182+ fn from ( scope_data : ScopeData ) -> Self {
183+ let ( id, code) = match scope_data {
184+ ScopeData :: Node ( id) => ( id, SCOPE_DATA_NODE ) ,
185+ ScopeData :: CallSite ( id) => ( id, SCOPE_DATA_CALLSITE ) ,
186+ ScopeData :: Arguments ( id) => ( id, SCOPE_DATA_ARGUMENTS ) ,
187+ ScopeData :: Destruction ( id) => ( id, SCOPE_DATA_DESTRUCTION ) ,
188+ ScopeData :: Remainder ( r) => ( r. block , r. first_statement_index . index ( ) as u32 )
189+ } ;
190+ Self { id, code }
191+ }
192+ }
193+
194+ impl fmt:: Debug for Scope {
195+ fn fmt ( & self , formatter : & mut fmt:: Formatter ) -> fmt:: Result {
196+ fmt:: Debug :: fmt ( & self . data ( ) , formatter)
197+ }
198+ }
199+
200+ #[ allow( non_snake_case) ]
201+ impl Scope {
202+ #[ inline]
203+ pub fn data ( self ) -> ScopeData {
204+ match self . code {
205+ SCOPE_DATA_NODE => ScopeData :: Node ( self . id ) ,
206+ SCOPE_DATA_CALLSITE => ScopeData :: CallSite ( self . id ) ,
207+ SCOPE_DATA_ARGUMENTS => ScopeData :: Arguments ( self . id ) ,
208+ SCOPE_DATA_DESTRUCTION => ScopeData :: Destruction ( self . id ) ,
209+ idx => ScopeData :: Remainder ( BlockRemainder {
210+ block : self . id ,
211+ first_statement_index : FirstStatementIndex { idx }
212+ } )
213+ }
214+ }
215+
216+ #[ inline]
217+ pub fn Node ( id : hir:: ItemLocalId ) -> Self {
218+ Self :: from ( ScopeData :: Node ( id) )
219+ }
220+
221+ #[ inline]
222+ pub fn CallSite ( id : hir:: ItemLocalId ) -> Self {
223+ Self :: from ( ScopeData :: CallSite ( id) )
224+ }
225+
226+ #[ inline]
227+ pub fn Arguments ( id : hir:: ItemLocalId ) -> Self {
228+ Self :: from ( ScopeData :: Arguments ( id) )
229+ }
230+
231+ #[ inline]
232+ pub fn Destruction ( id : hir:: ItemLocalId ) -> Self {
233+ Self :: from ( ScopeData :: Destruction ( id) )
234+ }
235+
236+ #[ inline]
237+ pub fn Remainder ( r : BlockRemainder ) -> Self {
238+ Self :: from ( ScopeData :: Remainder ( r) )
239+ }
139240}
140241
141242impl Scope {
@@ -144,16 +245,7 @@ impl Scope {
144245 /// NB: likely to be replaced as API is refined; e.g. pnkfelix
145246 /// anticipates `fn entry_node_id` and `fn each_exit_node_id`.
146247 pub fn item_local_id ( & self ) -> hir:: ItemLocalId {
147- match * self {
148- Scope :: Node ( id) => id,
149-
150- // These cases all return rough approximations to the
151- // precise scope denoted by `self`.
152- Scope :: Remainder ( br) => br. block ,
153- Scope :: Destruction ( id) |
154- Scope :: CallSite ( id) |
155- Scope :: Arguments ( id) => id,
156- }
248+ self . id
157249 }
158250
159251 pub fn node_id ( & self , tcx : TyCtxt , scope_tree : & ScopeTree ) -> ast:: NodeId {
@@ -177,7 +269,7 @@ impl Scope {
177269 return DUMMY_SP ;
178270 }
179271 let span = tcx. hir . span ( node_id) ;
180- if let Scope :: Remainder ( r) = * self {
272+ if let ScopeData :: Remainder ( r) = self . data ( ) {
181273 if let hir:: map:: NodeBlock ( ref blk) = tcx. hir . get ( node_id) {
182274 // Want span for scope starting after the
183275 // indexed statement and ending at end of
@@ -187,7 +279,7 @@ impl Scope {
187279 // (This is the special case aluded to in the
188280 // doc-comment for this method)
189281
190- let stmt_span = blk. stmts [ r. first_statement_index as usize ] . span ;
282+ let stmt_span = blk. stmts [ r. first_statement_index . index ( ) ] . span ;
191283
192284 // To avoid issues with macro-generated spans, the span
193285 // of the statement must be nested in that of the block.
@@ -387,7 +479,7 @@ impl<'tcx> ScopeTree {
387479 }
388480
389481 // record the destruction scopes for later so we can query them
390- if let Scope :: Destruction ( n) = child {
482+ if let ScopeData :: Destruction ( n) = child. data ( ) {
391483 self . destruction_scopes . insert ( n, child) ;
392484 }
393485 }
@@ -482,8 +574,8 @@ impl<'tcx> ScopeTree {
482574 let mut id = Scope :: Node ( expr_id) ;
483575
484576 while let Some ( & p) = self . parent_map . get ( & id) {
485- match p {
486- Scope :: Destruction ( ..) => {
577+ match p. data ( ) {
578+ ScopeData :: Destruction ( ..) => {
487579 debug ! ( "temporary_scope({:?}) = {:?} [enclosing]" ,
488580 expr_id, id) ;
489581 return Some ( id) ;
@@ -573,9 +665,9 @@ impl<'tcx> ScopeTree {
573665 // infer::region_inference for more details.
574666 let a_root_scope = a_ancestors[ a_index] ;
575667 let b_root_scope = a_ancestors[ a_index] ;
576- return match ( a_root_scope, b_root_scope) {
577- ( Scope :: Destruction ( a_root_id) ,
578- Scope :: Destruction ( b_root_id) ) => {
668+ return match ( a_root_scope. data ( ) , b_root_scope. data ( ) ) {
669+ ( ScopeData :: Destruction ( a_root_id) ,
670+ ScopeData :: Destruction ( b_root_id) ) => {
579671 if self . closure_is_enclosed_by ( a_root_id, b_root_id) {
580672 // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a`
581673 scope_b
@@ -764,7 +856,7 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk:
764856 visitor. enter_scope (
765857 Scope :: Remainder ( BlockRemainder {
766858 block : blk. hir_id . local_id ,
767- first_statement_index : i as u32
859+ first_statement_index : FirstStatementIndex :: new ( i )
768860 } )
769861 ) ;
770862 visitor. cx . var_parent = visitor. cx . parent ;
@@ -915,8 +1007,10 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
9151007 // Keep traversing up while we can.
9161008 match visitor. scope_tree . parent_map . get ( & scope) {
9171009 // Don't cross from closure bodies to their parent.
918- Some ( & Scope :: CallSite ( _) ) => break ,
919- Some ( & superscope) => scope = superscope,
1010+ Some ( & superscope) => match superscope. data ( ) {
1011+ ScopeData :: CallSite ( _) => break ,
1012+ _ => scope = superscope
1013+ } ,
9201014 None => break
9211015 }
9221016 }
0 commit comments