2
2
//!
3
3
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
4
4
5
+ use std:: assert_matches:: assert_matches;
5
6
use std:: borrow:: Cow ;
6
7
use std:: fmt:: { self , Debug , Formatter } ;
7
8
use std:: ops:: { Index , IndexMut } ;
@@ -37,7 +38,7 @@ use crate::ty::codec::{TyDecoder, TyEncoder};
37
38
use crate :: ty:: print:: { FmtPrinter , Printer , pretty_print_const, with_no_trimmed_paths} ;
38
39
use crate :: ty:: visit:: TypeVisitableExt ;
39
40
use crate :: ty:: {
40
- self , AdtDef , GenericArg , GenericArgsRef , Instance , InstanceKind , List , Ty , TyCtxt , TypingEnv ,
41
+ self , GenericArg , GenericArgsRef , Instance , InstanceKind , List , Ty , TyCtxt , TypingEnv ,
41
42
UserTypeAnnotationIndex ,
42
43
} ;
43
44
@@ -64,6 +65,7 @@ use pretty::pretty_print_const_value;
64
65
pub use statement:: * ;
65
66
pub use syntax:: * ;
66
67
pub use terminator:: * ;
68
+ use thin_vec:: ThinVec ;
67
69
68
70
pub use self :: generic_graph:: graphviz_safe_def_name;
69
71
pub use self :: graphviz:: write_mir_graphviz;
@@ -985,7 +987,7 @@ pub struct LocalDecl<'tcx> {
985
987
/// borrow checker needs this information since it can affect
986
988
/// region inference.
987
989
// FIXME(matthewjasper) Don't store in this in `Body`
988
- pub user_ty : Option < Box < UserTypeProjections > > ,
990
+ pub user_ty : Option < UserTypeProjections > ,
989
991
990
992
/// The *syntactic* (i.e., not visibility) source scope the local is defined
991
993
/// in. If the local was defined in a let-statement, this
@@ -1560,55 +1562,73 @@ pub struct SourceScopeLocalData {
1560
1562
/// &'static str`.
1561
1563
#[ derive( Clone , Debug , TyEncodable , TyDecodable , HashStable , TypeFoldable , TypeVisitable ) ]
1562
1564
pub 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.
1564
1573
}
1565
1574
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
+ }
1596
1586
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 }
1599
1597
}
1600
1598
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
+ }
1604
1613
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 ( )
1612
1632
}
1613
1633
}
1614
1634
@@ -1635,38 +1655,25 @@ pub struct UserTypeProjection {
1635
1655
}
1636
1656
1637
1657
impl UserTypeProjection {
1638
- pub ( crate ) fn index ( mut self ) -> Self {
1658
+ fn index ( & mut self ) {
1639
1659
self . projs . push ( ProjectionElem :: Index ( ( ) ) ) ;
1640
- self
1641
1660
}
1642
1661
1643
- pub ( crate ) fn subslice ( mut self , from : u64 , to : u64 ) -> Self {
1662
+ fn subslice ( & mut self , from : u64 , to : u64 ) {
1644
1663
self . projs . push ( ProjectionElem :: Subslice { from, to, from_end : true } ) ;
1645
- self
1646
1664
}
1647
1665
1648
- pub ( crate ) fn deref ( mut self ) -> Self {
1666
+ fn deref ( & mut self ) {
1649
1667
self . projs . push ( ProjectionElem :: Deref ) ;
1650
- self
1651
1668
}
1652
1669
1653
- pub ( crate ) fn leaf ( mut self , field : FieldIdx ) -> Self {
1670
+ fn leaf ( & mut self , field : FieldIdx ) {
1654
1671
self . projs . push ( ProjectionElem :: Field ( field, ( ) ) ) ;
1655
- self
1656
1672
}
1657
1673
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, ( ) ) ) ;
1670
1677
}
1671
1678
}
1672
1679
0 commit comments