22//!
33//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
44
5+ use std:: assert_matches:: assert_matches;
56use std:: borrow:: Cow ;
67use std:: fmt:: { self , Debug , Formatter } ;
78use std:: ops:: { Index , IndexMut } ;
@@ -37,7 +38,7 @@ use crate::ty::codec::{TyDecoder, TyEncoder};
3738use crate :: ty:: print:: { FmtPrinter , Printer , pretty_print_const, with_no_trimmed_paths} ;
3839use crate :: ty:: visit:: TypeVisitableExt ;
3940use crate :: ty:: {
40- self , AdtDef , GenericArg , GenericArgsRef , Instance , InstanceKind , List , Ty , TyCtxt , TypingEnv ,
41+ self , GenericArg , GenericArgsRef , Instance , InstanceKind , List , Ty , TyCtxt , TypingEnv ,
4142 UserTypeAnnotationIndex ,
4243} ;
4344
@@ -64,6 +65,7 @@ use pretty::pretty_print_const_value;
6465pub use statement:: * ;
6566pub use syntax:: * ;
6667pub use terminator:: * ;
68+ use thin_vec:: ThinVec ;
6769
6870pub use self :: generic_graph:: graphviz_safe_def_name;
6971pub use self :: graphviz:: write_mir_graphviz;
@@ -985,7 +987,7 @@ pub struct LocalDecl<'tcx> {
985987 /// borrow checker needs this information since it can affect
986988 /// region inference.
987989 // FIXME(matthewjasper) Don't store in this in `Body`
988- pub user_ty : Option < Box < UserTypeProjections > > ,
990+ pub user_ty : Option < UserTypeProjections > ,
989991
990992 /// The *syntactic* (i.e., not visibility) source scope the local is defined
991993 /// in. If the local was defined in a let-statement, this
@@ -1560,55 +1562,73 @@ pub struct SourceScopeLocalData {
15601562/// &'static str`.
15611563#[ derive( Clone , Debug , TyEncodable , TyDecodable , HashStable , TypeFoldable , TypeVisitable ) ]
15621564pub struct UserTypeProjections {
1563- pub contents : Vec < UserTypeProjection > ,
1565+ /// Instead of storing the projected user types directly, we store a flat list
1566+ /// of "operations" that can be used to build the projections as needed.
1567+ ///
1568+ /// The list happens to be stored in reverse order, because that's slightly
1569+ /// more convenient for the code that builds the list of ops.
1570+ ops_reversed : ThinVec < ProjectedUserTypesOp > ,
1571+ // If this struct ever ceases to be pointer-sized, its field in `LocalDecl`
1572+ // should probably be boxed again.
15641573}
15651574
1566- impl < ' tcx > UserTypeProjections {
1567- pub fn none ( ) -> Self {
1568- UserTypeProjections { contents : vec ! [ ] }
1569- }
1570-
1571- pub fn is_empty ( & self ) -> bool {
1572- self . contents . is_empty ( )
1573- }
1574-
1575- pub fn projections ( & self ) -> impl Iterator < Item = & UserTypeProjection > + ExactSizeIterator {
1576- self . contents . iter ( )
1577- }
1578-
1579- pub fn push_user_type ( mut self , base_user_type : UserTypeAnnotationIndex ) -> Self {
1580- self . contents . push ( UserTypeProjection { base : base_user_type, projs : vec ! [ ] } ) ;
1581- self
1582- }
1583-
1584- fn map_projections ( mut self , f : impl FnMut ( UserTypeProjection ) -> UserTypeProjection ) -> Self {
1585- self . contents = self . contents . into_iter ( ) . map ( f) . collect ( ) ;
1586- self
1587- }
1588-
1589- pub fn index ( self ) -> Self {
1590- self . map_projections ( |pat_ty_proj| pat_ty_proj. index ( ) )
1591- }
1592-
1593- pub fn subslice ( self , from : u64 , to : u64 ) -> Self {
1594- self . map_projections ( |pat_ty_proj| pat_ty_proj. subslice ( from, to) )
1595- }
1575+ /// One of a list of "operations" that can be used to reconstruct user-type projections.
1576+ #[ derive( Clone , Debug , TyEncodable , TyDecodable , HashStable , TypeFoldable , TypeVisitable ) ]
1577+ pub enum ProjectedUserTypesOp {
1578+ PushUserType { base : UserTypeAnnotationIndex } ,
1579+
1580+ Index ,
1581+ Subslice { from : u64 , to : u64 } ,
1582+ Deref ,
1583+ Leaf { field : FieldIdx } ,
1584+ Variant { name : Symbol , variant : VariantIdx , field : FieldIdx } ,
1585+ }
15961586
1597- pub fn deref ( self ) -> Self {
1598- self . map_projections ( |pat_ty_proj| pat_ty_proj. deref ( ) )
1587+ impl UserTypeProjections {
1588+ pub fn from_ops_reversed ( ops_reversed : impl Iterator < Item = ProjectedUserTypesOp > ) -> Self {
1589+ let ops_reversed = ops_reversed. collect :: < ThinVec < _ > > ( ) ;
1590+ // The "first" op should always be `PushUserType`, because it would be
1591+ // useless for other ops to modify an empty list of projections.
1592+ assert_matches ! (
1593+ ops_reversed. last( ) ,
1594+ None | Some ( ProjectedUserTypesOp :: PushUserType { .. } )
1595+ ) ;
1596+ Self { ops_reversed }
15991597 }
16001598
1601- pub fn leaf ( self , field : FieldIdx ) -> Self {
1602- self . map_projections ( |pat_ty_proj| pat_ty_proj. leaf ( field) )
1603- }
1599+ pub fn is_empty ( & self ) -> bool {
1600+ self . ops_reversed . is_empty ( )
1601+ }
1602+
1603+ pub fn projections ( & self ) -> impl Iterator < Item = UserTypeProjection > + ExactSizeIterator {
1604+ let mut projections = vec ! [ ] ;
1605+ // Iterate over the list of ops in "non-reversed" order.
1606+ for op in self . ops_reversed . iter ( ) . rev ( ) {
1607+ match * op {
1608+ ProjectedUserTypesOp :: PushUserType { base } => {
1609+ // Add a new user type to the list of projections, which
1610+ // will then be modified by subsequent projection ops.
1611+ projections. push ( UserTypeProjection { base, projs : vec ! [ ] } ) ;
1612+ }
16041613
1605- pub fn variant (
1606- self ,
1607- adt_def : AdtDef < ' tcx > ,
1608- variant_index : VariantIdx ,
1609- field_index : FieldIdx ,
1610- ) -> Self {
1611- self . map_projections ( |pat_ty_proj| pat_ty_proj. variant ( adt_def, variant_index, field_index) )
1614+ ProjectedUserTypesOp :: Index => {
1615+ projections. iter_mut ( ) . for_each ( |p| p. index ( ) ) ;
1616+ }
1617+ ProjectedUserTypesOp :: Subslice { from, to } => {
1618+ projections. iter_mut ( ) . for_each ( |p| p. subslice ( from, to) ) ;
1619+ }
1620+ ProjectedUserTypesOp :: Deref => {
1621+ projections. iter_mut ( ) . for_each ( |p| p. deref ( ) ) ;
1622+ }
1623+ ProjectedUserTypesOp :: Leaf { field } => {
1624+ projections. iter_mut ( ) . for_each ( |p| p. leaf ( field) ) ;
1625+ }
1626+ ProjectedUserTypesOp :: Variant { name, variant, field } => {
1627+ projections. iter_mut ( ) . for_each ( |p| p. variant ( name, variant, field) ) ;
1628+ }
1629+ }
1630+ }
1631+ projections. into_iter ( )
16121632 }
16131633}
16141634
@@ -1635,38 +1655,25 @@ pub struct UserTypeProjection {
16351655}
16361656
16371657impl UserTypeProjection {
1638- pub ( crate ) fn index ( mut self ) -> Self {
1658+ fn index ( & mut self ) {
16391659 self . projs . push ( ProjectionElem :: Index ( ( ) ) ) ;
1640- self
16411660 }
16421661
1643- pub ( crate ) fn subslice ( mut self , from : u64 , to : u64 ) -> Self {
1662+ fn subslice ( & mut self , from : u64 , to : u64 ) {
16441663 self . projs . push ( ProjectionElem :: Subslice { from, to, from_end : true } ) ;
1645- self
16461664 }
16471665
1648- pub ( crate ) fn deref ( mut self ) -> Self {
1666+ fn deref ( & mut self ) {
16491667 self . projs . push ( ProjectionElem :: Deref ) ;
1650- self
16511668 }
16521669
1653- pub ( crate ) fn leaf ( mut self , field : FieldIdx ) -> Self {
1670+ fn leaf ( & mut self , field : FieldIdx ) {
16541671 self . projs . push ( ProjectionElem :: Field ( field, ( ) ) ) ;
1655- self
16561672 }
16571673
1658- pub ( crate ) fn variant (
1659- mut self ,
1660- adt_def : AdtDef < ' _ > ,
1661- variant_index : VariantIdx ,
1662- field_index : FieldIdx ,
1663- ) -> Self {
1664- self . projs . push ( ProjectionElem :: Downcast (
1665- Some ( adt_def. variant ( variant_index) . name ) ,
1666- variant_index,
1667- ) ) ;
1668- self . projs . push ( ProjectionElem :: Field ( field_index, ( ) ) ) ;
1669- self
1674+ fn variant ( & mut self , name : Symbol , variant : VariantIdx , field : FieldIdx ) {
1675+ self . projs . push ( ProjectionElem :: Downcast ( Some ( name) , variant) ) ;
1676+ self . projs . push ( ProjectionElem :: Field ( field, ( ) ) ) ;
16701677 }
16711678}
16721679
0 commit comments