@@ -61,6 +61,7 @@ public struct ExprNode
6161 private const uint MetaKeepWithoutNext = 0xFFFF0000u ;
6262 // _data layout: bits [31:16]=ChildCount | [15:0]=ChildIdx (or full uint for inline constants)
6363 private const int DataCountShift = 16 ;
64+ private const uint DataKeepWithoutChildIdx = 0xFFFF0000u ;
6465 private const uint DataIdxMask = 0xFFFFu ;
6566 private const int FlagsShift = 4 ;
6667 private const uint KindMask = 0x0Fu ;
@@ -139,6 +140,19 @@ internal void SetChildInfo(int childIdx, int childCount) =>
139140 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
140141 internal bool HasFlag ( byte flag ) => ( Flags & flag ) != 0 ;
141142
143+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
144+ internal bool HasSameHeaderExceptNext ( ref ExprNode other ) =>
145+ Type == other . Type && ( _meta & MetaKeepWithoutNext ) == ( other . _meta & MetaKeepWithoutNext ) ;
146+
147+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
148+ internal bool HasSameShapeExceptLinks ( ref ExprNode other ) =>
149+ HasSameHeaderExceptNext ( ref other ) &&
150+ ( _data & DataKeepWithoutChildIdx ) == ( other . _data & DataKeepWithoutChildIdx ) ;
151+
152+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
153+ internal bool HasSameShapeExceptNext ( ref ExprNode other ) =>
154+ HasSameHeaderExceptNext ( ref other ) && _data == other . _data ;
155+
142156 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
143157 internal bool ShouldCloneWhenLinked ( ) =>
144158 ReferenceEquals ( Obj , InlineValueMarker ) ||
@@ -1646,7 +1660,17 @@ public bool Eq(ref ExprTree xTree, ref ExprTree yTree)
16461660 {
16471661 ref var x = ref xTree . Nodes . GetSurePresentRef ( xIdx ) ;
16481662 ref var y = ref yTree . Nodes . GetSurePresentRef ( yIdx ) ;
1649- if ( x . Kind != y . Kind || x . NodeType != y . NodeType || x . Type != y . Type || x . Flags != y . Flags )
1663+ if ( x . Kind == ExprNodeKind . UInt16Pair )
1664+ {
1665+ if ( ! x . HasSameShapeExceptNext ( ref y ) )
1666+ return false ;
1667+ }
1668+ else if ( x . NodeType == ExpressionType . Constant )
1669+ {
1670+ if ( ! x . HasSameHeaderExceptNext ( ref y ) )
1671+ return false ;
1672+ }
1673+ else if ( ! x . HasSameShapeExceptLinks ( ref y ) )
16501674 return false ;
16511675
16521676 var descendX = 0 ;
@@ -1655,122 +1679,117 @@ public bool Eq(ref ExprTree xTree, ref ExprTree yTree)
16551679 var restoreXParameterCount = - 1 ;
16561680 var restoreYParameterCount = - 1 ;
16571681
1658- if ( x . Kind == ExprNodeKind . LabelTarget )
1682+ if ( x . Kind != ExprNodeKind . UInt16Pair )
16591683 {
1660- if ( ! EqLabelTarget ( ref x , ref y ) )
1661- return false ;
1662- }
1663- else if ( x . Kind == ExprNodeKind . UInt16Pair )
1664- {
1665- if ( x . ChildIdx != y . ChildIdx || x . ChildCount != y . ChildCount )
1666- return false ;
1667- }
1668- else if ( x . Kind == ExprNodeKind . CatchBlock )
1669- {
1670- if ( x . ChildCount != y . ChildCount )
1671- return false ;
1672-
1673- restoreXParameterCount = _xParameterIds . Count ;
1674- restoreYParameterCount = _yParameterIds . Count ;
1675- descendX = x . ChildIdx ;
1676- descendY = y . ChildIdx ;
1677- descendChildCount = x . ChildCount - ( x . HasFlag ( CatchHasVariableFlag ) ? 1 : 0 ) ;
1678- if ( x . HasFlag ( CatchHasVariableFlag ) )
1684+ if ( x . Kind == ExprNodeKind . LabelTarget )
16791685 {
1680- ref var xv = ref xTree . Nodes . GetSurePresentRef ( descendX ) ;
1681- ref var yv = ref yTree . Nodes . GetSurePresentRef ( descendY ) ;
1682- if ( ! AreEquivalentParameterDeclarations ( ref xv , ref yv ) )
1686+ if ( ! EqLabelTarget ( ref x , ref y ) )
16831687 return false ;
1684- _xParameterIds . Add ( ToStoredUShortIdx ( xv . ChildIdx ) ) ;
1685- _yParameterIds . Add ( ToStoredUShortIdx ( yv . ChildIdx ) ) ;
1686- descendX = xv . NextIdx ;
1687- descendY = yv . NextIdx ;
16881688 }
1689- }
1690- else
1691- {
1692- switch ( x . NodeType )
1689+ else if ( x . Kind == ExprNodeKind . CatchBlock )
16931690 {
1694- case ExpressionType . Parameter :
1695- if ( ! EqParameter ( ref x , ref y ) )
1696- return false ;
1697- break ;
1698-
1699- case ExpressionType . Constant :
1700- if ( ! AreConstantsEqual ( ref xTree , ref x , ref yTree , ref y ) )
1701- return false ;
1702- break ;
1703-
1704- case ExpressionType . Lambda :
1705- if ( x . ChildCount != y . ChildCount || x . ChildCount == 0 )
1691+ restoreXParameterCount = _xParameterIds . Count ;
1692+ restoreYParameterCount = _yParameterIds . Count ;
1693+ descendX = x . ChildIdx ;
1694+ descendY = y . ChildIdx ;
1695+ descendChildCount = x . ChildCount - ( x . HasFlag ( CatchHasVariableFlag ) ? 1 : 0 ) ;
1696+ if ( x . HasFlag ( CatchHasVariableFlag ) )
1697+ {
1698+ ref var xv = ref xTree . Nodes . GetSurePresentRef ( descendX ) ;
1699+ ref var yv = ref yTree . Nodes . GetSurePresentRef ( descendY ) ;
1700+ if ( ! AreEquivalentParameterDeclarations ( ref xv , ref yv ) )
17061701 return false ;
1707-
1708- restoreXParameterCount = _xParameterIds . Count ;
1709- restoreYParameterCount = _yParameterIds . Count ;
1710- descendX = x . ChildIdx ;
1711- descendY = y . ChildIdx ;
1712- descendChildCount = 1 ;
1713- var xParameterIdx = xTree . Nodes . GetSurePresentRef ( descendX ) . NextIdx ;
1714- var yParameterIdx = yTree . Nodes . GetSurePresentRef ( descendY ) . NextIdx ;
1715- for ( var i = 1 ; i < x . ChildCount ; ++ i )
1716- {
1717- ref var xp = ref xTree . Nodes . GetSurePresentRef ( xParameterIdx ) ;
1718- ref var yp = ref yTree . Nodes . GetSurePresentRef ( yParameterIdx ) ;
1719- if ( ! AreEquivalentParameterDeclarations ( ref xp , ref yp ) )
1702+ _xParameterIds . Add ( ToStoredUShortIdx ( xv . ChildIdx ) ) ;
1703+ _yParameterIds . Add ( ToStoredUShortIdx ( yv . ChildIdx ) ) ;
1704+ descendX = xv . NextIdx ;
1705+ descendY = yv . NextIdx ;
1706+ }
1707+ }
1708+ else
1709+ {
1710+ switch ( x . NodeType )
1711+ {
1712+ case ExpressionType . Parameter :
1713+ if ( ! EqParameter ( ref x , ref y ) )
17201714 return false ;
1721- _xParameterIds . Add ( ToStoredUShortIdx ( xp . ChildIdx ) ) ;
1722- _yParameterIds . Add ( ToStoredUShortIdx ( yp . ChildIdx ) ) ;
1723- xParameterIdx = xp . NextIdx ;
1724- yParameterIdx = yp . NextIdx ;
1725- }
1726- break ;
1715+ break ;
17271716
1728- case ExpressionType . Block :
1729- if ( x . ChildCount != y . ChildCount || x . ChildCount == 0 )
1730- return false ;
1717+ case ExpressionType . Constant :
1718+ if ( ! AreConstantsEqual ( ref xTree , ref x , ref yTree , ref y ) )
1719+ return false ;
1720+ break ;
17311721
1732- restoreXParameterCount = _xParameterIds . Count ;
1733- restoreYParameterCount = _yParameterIds . Count ;
1734- descendX = x . ChildIdx ;
1735- descendY = y . ChildIdx ;
1736- descendChildCount = 1 ;
1737- if ( x . ChildCount == 2 )
1738- {
1739- ref var xVariables = ref xTree . Nodes . GetSurePresentRef ( descendX ) ;
1740- ref var yVariables = ref yTree . Nodes . GetSurePresentRef ( descendY ) ;
1741- if ( xVariables . Kind != ExprNodeKind . ChildList || yVariables . Kind != ExprNodeKind . ChildList ||
1742- xVariables . ChildCount != yVariables . ChildCount )
1722+ case ExpressionType . Lambda :
1723+ if ( x . ChildCount == 0 )
17431724 return false ;
17441725
1745- var xVariableIdx = xVariables . ChildIdx ;
1746- var yVariableIdx = yVariables . ChildIdx ;
1747- for ( var i = 0 ; i < xVariables . ChildCount ; ++ i )
1726+ restoreXParameterCount = _xParameterIds . Count ;
1727+ restoreYParameterCount = _yParameterIds . Count ;
1728+ descendX = x . ChildIdx ;
1729+ descendY = y . ChildIdx ;
1730+ descendChildCount = 1 ;
1731+ var xParameterIdx = xTree . Nodes . GetSurePresentRef ( descendX ) . NextIdx ;
1732+ var yParameterIdx = yTree . Nodes . GetSurePresentRef ( descendY ) . NextIdx ;
1733+ for ( var i = 1 ; i < x . ChildCount ; ++ i )
17481734 {
1749- ref var xv = ref xTree . Nodes . GetSurePresentRef ( xVariableIdx ) ;
1750- ref var yv = ref yTree . Nodes . GetSurePresentRef ( yVariableIdx ) ;
1751- if ( ! AreEquivalentParameterDeclarations ( ref xv , ref yv ) )
1735+ ref var xp = ref xTree . Nodes . GetSurePresentRef ( xParameterIdx ) ;
1736+ ref var yp = ref yTree . Nodes . GetSurePresentRef ( yParameterIdx ) ;
1737+ if ( ! AreEquivalentParameterDeclarations ( ref xp , ref yp ) )
17521738 return false ;
1753- _xParameterIds . Add ( ToStoredUShortIdx ( xv . ChildIdx ) ) ;
1754- _yParameterIds . Add ( ToStoredUShortIdx ( yv . ChildIdx ) ) ;
1755- xVariableIdx = xv . NextIdx ;
1756- yVariableIdx = yv . NextIdx ;
1739+ _xParameterIds . Add ( ToStoredUShortIdx ( xp . ChildIdx ) ) ;
1740+ _yParameterIds . Add ( ToStoredUShortIdx ( yp . ChildIdx ) ) ;
1741+ xParameterIdx = xp . NextIdx ;
1742+ yParameterIdx = yp . NextIdx ;
17571743 }
1744+ break ;
17581745
1759- descendX = xVariables . NextIdx ;
1760- descendY = yVariables . NextIdx ;
1761- }
1762- break ;
1746+ case ExpressionType . Block :
1747+ if ( x . ChildCount == 0 )
1748+ return false ;
17631749
1764- default :
1765- if ( x . ChildCount != y . ChildCount || ! EqObj ( ref x , ref y ) )
1766- return false ;
1767- if ( x . ChildCount != 0 )
1768- {
1750+ restoreXParameterCount = _xParameterIds . Count ;
1751+ restoreYParameterCount = _yParameterIds . Count ;
17691752 descendX = x . ChildIdx ;
17701753 descendY = y . ChildIdx ;
1771- descendChildCount = x . ChildCount ;
1772- }
1773- break ;
1754+ descendChildCount = 1 ;
1755+ if ( x . ChildCount == 2 )
1756+ {
1757+ ref var xVariables = ref xTree . Nodes . GetSurePresentRef ( descendX ) ;
1758+ ref var yVariables = ref yTree . Nodes . GetSurePresentRef ( descendY ) ;
1759+ if ( xVariables . Kind != ExprNodeKind . ChildList || yVariables . Kind != ExprNodeKind . ChildList ||
1760+ xVariables . ChildCount != yVariables . ChildCount )
1761+ return false ;
1762+
1763+ var xVariableIdx = xVariables . ChildIdx ;
1764+ var yVariableIdx = yVariables . ChildIdx ;
1765+ for ( var i = 0 ; i < xVariables . ChildCount ; ++ i )
1766+ {
1767+ ref var xv = ref xTree . Nodes . GetSurePresentRef ( xVariableIdx ) ;
1768+ ref var yv = ref yTree . Nodes . GetSurePresentRef ( yVariableIdx ) ;
1769+ if ( ! AreEquivalentParameterDeclarations ( ref xv , ref yv ) )
1770+ return false ;
1771+ _xParameterIds . Add ( ToStoredUShortIdx ( xv . ChildIdx ) ) ;
1772+ _yParameterIds . Add ( ToStoredUShortIdx ( yv . ChildIdx ) ) ;
1773+ xVariableIdx = xv . NextIdx ;
1774+ yVariableIdx = yv . NextIdx ;
1775+ }
1776+
1777+ descendX = xVariables . NextIdx ;
1778+ descendY = yVariables . NextIdx ;
1779+ }
1780+ break ;
1781+
1782+ default :
1783+ if ( ! EqObj ( ref x , ref y ) )
1784+ return false ;
1785+ if ( x . ChildCount != 0 )
1786+ {
1787+ descendX = x . ChildIdx ;
1788+ descendY = y . ChildIdx ;
1789+ descendChildCount = x . ChildCount ;
1790+ }
1791+ break ;
1792+ }
17741793 }
17751794 }
17761795
@@ -1848,9 +1867,9 @@ private bool EqLabelTarget(ref ExprNode x, ref ExprNode y)
18481867
18491868 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
18501869 private static bool AreEquivalentParameterDeclarations ( ref ExprNode x , ref ExprNode y ) =>
1851- x . NodeType == ExpressionType . Parameter && y . NodeType == ExpressionType . Parameter &&
1852- x . Kind == ExprNodeKind . Expression && y . Kind == ExprNodeKind . Expression &&
1853- x . Type == y . Type && x . HasFlag ( ParameterByRefFlag ) == y . HasFlag ( ParameterByRefFlag ) ;
1870+ x . NodeType == ExpressionType . Parameter &&
1871+ y . NodeType == ExpressionType . Parameter &&
1872+ x . HasSameShapeExceptLinks ( ref y ) ;
18541873
18551874 private static bool EqObj ( ref ExprNode x , ref ExprNode y )
18561875 {
0 commit comments