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,64 +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 , Span ) > ,
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_and_spans (
1576- & self ,
1577- ) -> impl Iterator < Item = & ( UserTypeProjection , Span ) > + ExactSizeIterator {
1578- self . contents . iter ( )
1579- }
1580-
1581- pub fn projections ( & self ) -> impl Iterator < Item = & UserTypeProjection > + ExactSizeIterator {
1582- self . contents . iter ( ) . map ( |& ( ref user_type, _span) | user_type)
1583- }
1584-
1585- pub fn push_projection ( mut self , user_ty : & UserTypeProjection , span : Span ) -> Self {
1586- self . contents . push ( ( user_ty. clone ( ) , span) ) ;
1587- self
1588- }
1589-
1590- fn map_projections (
1591- mut self ,
1592- mut f : impl FnMut ( UserTypeProjection ) -> UserTypeProjection ,
1593- ) -> Self {
1594- self . contents = self . contents . into_iter ( ) . map ( |( proj, span) | ( f ( proj) , span) ) . collect ( ) ;
1595- self
1596- }
1597-
1598- pub fn index ( self ) -> Self {
1599- self . map_projections ( |pat_ty_proj| pat_ty_proj. index ( ) )
1600- }
1601-
1602- pub fn subslice ( self , from : u64 , to : u64 ) -> Self {
1603- self . map_projections ( |pat_ty_proj| pat_ty_proj. subslice ( from, to) )
1604- }
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+ }
16051586
1606- pub fn deref ( self ) -> Self {
1607- 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 }
16081597 }
16091598
1610- pub fn leaf ( self , field : FieldIdx ) -> Self {
1611- self . map_projections ( |pat_ty_proj| pat_ty_proj. leaf ( field) )
1612- }
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+ }
16131613
1614- pub fn variant (
1615- self ,
1616- adt_def : AdtDef < ' tcx > ,
1617- variant_index : VariantIdx ,
1618- field_index : FieldIdx ,
1619- ) -> Self {
1620- 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 ( )
16211632 }
16221633}
16231634
@@ -1644,38 +1655,25 @@ pub struct UserTypeProjection {
16441655}
16451656
16461657impl UserTypeProjection {
1647- pub ( crate ) fn index ( mut self ) -> Self {
1658+ fn index ( & mut self ) {
16481659 self . projs . push ( ProjectionElem :: Index ( ( ) ) ) ;
1649- self
16501660 }
16511661
1652- pub ( crate ) fn subslice ( mut self , from : u64 , to : u64 ) -> Self {
1662+ fn subslice ( & mut self , from : u64 , to : u64 ) {
16531663 self . projs . push ( ProjectionElem :: Subslice { from, to, from_end : true } ) ;
1654- self
16551664 }
16561665
1657- pub ( crate ) fn deref ( mut self ) -> Self {
1666+ fn deref ( & mut self ) {
16581667 self . projs . push ( ProjectionElem :: Deref ) ;
1659- self
16601668 }
16611669
1662- pub ( crate ) fn leaf ( mut self , field : FieldIdx ) -> Self {
1670+ fn leaf ( & mut self , field : FieldIdx ) {
16631671 self . projs . push ( ProjectionElem :: Field ( field, ( ) ) ) ;
1664- self
16651672 }
16661673
1667- pub ( crate ) fn variant (
1668- mut self ,
1669- adt_def : AdtDef < ' _ > ,
1670- variant_index : VariantIdx ,
1671- field_index : FieldIdx ,
1672- ) -> Self {
1673- self . projs . push ( ProjectionElem :: Downcast (
1674- Some ( adt_def. variant ( variant_index) . name ) ,
1675- variant_index,
1676- ) ) ;
1677- self . projs . push ( ProjectionElem :: Field ( field_index, ( ) ) ) ;
1678- 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, ( ) ) ) ;
16791677 }
16801678}
16811679
0 commit comments