@@ -13,8 +13,8 @@ use crate::{
1313 } ,
1414 i256, impl_deserialize, impl_serialize,
1515 sum_type:: { OPTION_NONE_TAG , OPTION_SOME_TAG } ,
16- u256, AlgebraicType , AlgebraicValue , ProductType , ProductTypeElement , ProductValue , SumType , SumTypeVariant ,
17- SumValue , WithTypespace ,
16+ u256, AlgebraicType , AlgebraicValue , ArrayType , ProductType , ProductTypeElement , ProductValue , SumType ,
17+ SumTypeVariant , SumValue , WithTypespace ,
1818} ;
1919use core:: ops:: { Index , Mul } ;
2020use core:: { mem, ops:: Deref } ;
@@ -199,8 +199,8 @@ impl AlgebraicTypeLayout {
199199 // but we don't care to avoid that and optimize right now,
200200 // as this is only executed during upgrade / migration,
201201 // and that doesn't need to be fast right now.
202- let old = AlgebraicTypeLayout :: from ( old. deref ( ) . clone ( ) ) ;
203- let new = AlgebraicTypeLayout :: from ( new. deref ( ) . clone ( ) ) ;
202+ let old = AlgebraicTypeLayout :: from ( old. elem_ty . deref ( ) . clone ( ) ) ;
203+ let new = AlgebraicTypeLayout :: from ( new. elem_ty . deref ( ) . clone ( ) ) ;
204204 old. is_compatible_with ( & new)
205205 }
206206 ( Self :: VarLen ( VarLenType :: String ) , Self :: VarLen ( VarLenType :: String ) ) => true ,
@@ -515,11 +515,11 @@ impl HasLayout for PrimitiveType {
515515pub enum VarLenType {
516516 /// The string type corresponds to `AlgebraicType::String`.
517517 String ,
518- /// An array type. The whole outer `AlgebraicType` is stored here.
518+ /// An array type. The inner `AlgebraicType` is stored here.
519519 ///
520- /// Storing the whole `AlgebraicType` here allows us to directly call BSATN ser/de,
521- /// and to report type errors .
522- Array ( Box < AlgebraicType > ) ,
520+ /// Previously, the outer type, i.e., `AlgebraicType::Array` was stored.
521+ /// However, this is both more inefficient and bug prone .
522+ Array ( ArrayType ) ,
523523}
524524
525525#[ cfg( feature = "memory-usage" ) ]
@@ -554,7 +554,7 @@ impl From<AlgebraicType> for AlgebraicTypeLayout {
554554 AlgebraicType :: Product ( prod) => AlgebraicTypeLayout :: Product ( prod. into ( ) ) ,
555555
556556 AlgebraicType :: String => AlgebraicTypeLayout :: VarLen ( VarLenType :: String ) ,
557- AlgebraicType :: Array ( _ ) => AlgebraicTypeLayout :: VarLen ( VarLenType :: Array ( Box :: new ( ty ) ) ) ,
557+ AlgebraicType :: Array ( array ) => AlgebraicTypeLayout :: VarLen ( VarLenType :: Array ( array ) ) ,
558558
559559 AlgebraicType :: Bool => AlgebraicTypeLayout :: Bool ,
560560 AlgebraicType :: I8 => AlgebraicTypeLayout :: I8 ,
@@ -690,19 +690,11 @@ impl AlgebraicTypeLayout {
690690 /// It is intended for use in error paths, where performance is a secondary concern.
691691 pub fn algebraic_type ( & self ) -> AlgebraicType {
692692 match self {
693- AlgebraicTypeLayout :: Primitive ( prim) => prim. algebraic_type ( ) ,
694- AlgebraicTypeLayout :: VarLen ( var_len) => var_len. algebraic_type ( ) ,
695- AlgebraicTypeLayout :: Product ( prod) => AlgebraicType :: Product ( prod. view ( ) . product_type ( ) ) ,
696- AlgebraicTypeLayout :: Sum ( sum) => AlgebraicType :: Sum ( sum. sum_type ( ) ) ,
697- }
698- }
699- }
700-
701- impl VarLenType {
702- fn algebraic_type ( & self ) -> AlgebraicType {
703- match self {
704- VarLenType :: String => AlgebraicType :: String ,
705- VarLenType :: Array ( ty) => ty. as_ref ( ) . clone ( ) ,
693+ Self :: Primitive ( prim) => prim. algebraic_type ( ) ,
694+ Self :: VarLen ( VarLenType :: String ) => AlgebraicType :: String ,
695+ Self :: VarLen ( VarLenType :: Array ( array) ) => AlgebraicType :: Array ( array. clone ( ) ) ,
696+ Self :: Product ( prod) => AlgebraicType :: Product ( prod. view ( ) . product_type ( ) ) ,
697+ Self :: Sum ( sum) => AlgebraicType :: Sum ( sum. sum_type ( ) ) ,
706698 }
707699 }
708700}
@@ -828,7 +820,9 @@ impl<'de> DeserializeSeed<'de> for &AlgebraicTypeLayout {
828820 AlgebraicTypeLayout :: Primitive ( PrimitiveType :: U256 ) => u256:: deserialize ( de) . map ( Into :: into) ,
829821 AlgebraicTypeLayout :: Primitive ( PrimitiveType :: F32 ) => f32:: deserialize ( de) . map ( Into :: into) ,
830822 AlgebraicTypeLayout :: Primitive ( PrimitiveType :: F64 ) => f64:: deserialize ( de) . map ( Into :: into) ,
831- AlgebraicTypeLayout :: VarLen ( VarLenType :: Array ( ty) ) => WithTypespace :: empty ( & * * ty) . deserialize ( de) ,
823+ AlgebraicTypeLayout :: VarLen ( VarLenType :: Array ( ty) ) => {
824+ WithTypespace :: empty ( ty) . deserialize ( de) . map ( AlgebraicValue :: Array )
825+ }
832826 AlgebraicTypeLayout :: VarLen ( VarLenType :: String ) => <Box < str > >:: deserialize ( de) . map ( Into :: into) ,
833827 }
834828 }
@@ -1124,4 +1118,15 @@ mod test {
11241118 }
11251119 }
11261120 }
1121+
1122+ #[ test]
1123+ fn infinite_recursion_in_is_compatible_with_with_array_type ( ) {
1124+ let ty = AlgebraicTypeLayout :: from ( AlgebraicType :: array ( AlgebraicType :: U64 ) ) ;
1125+ // This would previously cause an infinite recursion / stack overflow
1126+ // due the setup where `AlgebraicTypeLayout::VarLen(Array(x))` stored
1127+ // `x = Box::new(AlgebraicType::Array(elem_ty))`.
1128+ // The method `AlgebraicTypeLayout::is_compatible_with` was not setup to handle that.
1129+ // To avoid such bugs in the future, `x` is now `elem_ty` instead.
1130+ assert ! ( ty. is_compatible_with( & ty) ) ;
1131+ }
11271132}
0 commit comments