@@ -107,6 +107,7 @@ public struct ExprNode
107107
108108 internal ExprNode ( Type type , object obj , ExpressionType nodeType , ExprNodeKind kind , byte flags = 0 , int childIdx = 0 , int childCount = 0 , int nextIdx = 0 )
109109 {
110+ Debug . Assert ( ! RequiresInlineConstantStorage ( type , obj , nodeType ) ) ;
110111 Type = type ;
111112 Obj = obj ;
112113 var tag = ( byte ) ( ( flags << FlagsShift ) | ( byte ) kind ) ;
@@ -137,6 +138,23 @@ internal void SetChildInfo(int childIdx, int childCount) =>
137138 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
138139 internal bool IsExpression ( ) => Kind == ExprNodeKind . Expression ;
139140
141+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
142+ internal static bool RequiresInlineConstantStorage ( Type type , object obj , ExpressionType nodeType )
143+ {
144+ if ( nodeType != ExpressionType . Constant || obj == null || ReferenceEquals ( obj , InlineValueMarker ) )
145+ return false ;
146+
147+ return type . IsEnum
148+ ? IsSmallPrimitive ( Type . GetTypeCode ( Enum . GetUnderlyingType ( type ) ) )
149+ : type . IsPrimitive && IsSmallPrimitive ( Type . GetTypeCode ( type ) ) ;
150+ }
151+
152+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
153+ private static bool IsSmallPrimitive ( TypeCode tc ) =>
154+ tc == TypeCode . Boolean || tc == TypeCode . Byte || tc == TypeCode . SByte ||
155+ tc == TypeCode . Char || tc == TypeCode . Int16 || tc == TypeCode . UInt16 ||
156+ tc == TypeCode . Int32 || tc == TypeCode . UInt32 || tc == TypeCode . Single ;
157+
140158 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
141159 internal bool HasFlag ( byte flag ) => ( Flags & flag ) != 0 ;
142160
@@ -2005,22 +2023,29 @@ private static int GetConstantHashCode(ref ExprTree tree, ref ExprNode node)
20052023 {
20062024 if ( ReferenceEquals ( node . Obj , ExprNode . InlineValueMarker ) )
20072025 return GetInlineConstantHashCode ( node . Type , node . InlineValue ) ;
2026+
2027+ Debug . Assert ( ! ExprNode . RequiresInlineConstantStorage ( node . Type , node . Obj , node . NodeType ) ) ;
20082028 return GetStoredConstantValue ( ref tree , ref node ) ? . GetHashCode ( ) ?? 0 ;
20092029 }
20102030
20112031 private static bool AreConstantsEqual ( ref ExprTree xTree , ref ExprNode x , ref ExprTree yTree , ref ExprNode y )
20122032 {
2013- var xObj = GetStoredConstantValue ( ref xTree , ref x ) ;
2014- var yObj = GetStoredConstantValue ( ref yTree , ref y ) ;
20152033 var xInline = ReferenceEquals ( x . Obj , ExprNode . InlineValueMarker ) ;
20162034 var yInline = ReferenceEquals ( y . Obj , ExprNode . InlineValueMarker ) ;
2017- if ( ! ( xInline && yInline ) )
2035+ Debug . Assert ( xInline == yInline ) ;
2036+ if ( xInline != yInline )
2037+ return false ;
2038+
2039+ if ( ! xInline )
2040+ {
2041+ Debug . Assert ( ! ExprNode . RequiresInlineConstantStorage ( x . Type , x . Obj , x . NodeType ) ) ;
2042+ var xObj = GetStoredConstantValue ( ref xTree , ref x ) ;
2043+ var yObj = GetStoredConstantValue ( ref yTree , ref y ) ;
20182044 return ReferenceEquals ( xObj , yObj ) || Equals ( xObj , yObj ) ;
2045+ }
20192046
20202047 if ( x . Type . IsEnum )
2021- {
20222048 return x . InlineValue == y . InlineValue ;
2023- }
20242049
20252050 return Type . GetTypeCode ( x . Type ) switch
20262051 {
@@ -2033,7 +2058,7 @@ private static bool AreConstantsEqual(ref ExprTree xTree, ref ExprNode x, ref Ex
20332058 TypeCode . Int32 => GetInlineInt32 ( ref x ) == GetInlineInt32 ( ref y ) ,
20342059 TypeCode . UInt32 => GetInlineUInt32 ( ref x ) == GetInlineUInt32 ( ref y ) ,
20352060 TypeCode . Single => GetInlineSingle ( ref x ) . Equals ( GetInlineSingle ( ref y ) ) ,
2036- _ => ReferenceEquals ( xObj , yObj ) || Equals ( xObj , yObj )
2061+ _ => FlatExpressionThrow . UnsupportedInlineConstantType < bool > ( x . Type )
20372062 } ;
20382063 }
20392064
0 commit comments