@@ -1856,7 +1856,7 @@ public static bool TryEmit(Expression expr, IReadOnlyList<PE> paramExprs,
18561856 case ExpressionType . Equal :
18571857 case ExpressionType . NotEqual :
18581858 var binaryExpr = ( BinaryExpression ) expr ;
1859- return TryEmitComparison ( binaryExpr . Left , binaryExpr . Right , binaryExpr . NodeType , paramExprs , il , ref closure , setup , parent ) ;
1859+ return TryEmitComparison ( binaryExpr . Left , binaryExpr . Right , binaryExpr . NodeType , expr . Type , paramExprs , il , ref closure , setup , parent ) ;
18601860
18611861 case ExpressionType . Add :
18621862 case ExpressionType . AddChecked :
@@ -2716,7 +2716,7 @@ private static bool TryEmitNot(UnaryExpression expr, IReadOnlyList<PE> paramExpr
27162716 if ( expr . Operand . NodeType == ExpressionType . Equal )
27172717 {
27182718 var equalExpr = ( BinaryExpression ) expr . Operand ;
2719- return TryEmitComparison ( equalExpr . Left , equalExpr . Right , ExpressionType . NotEqual , paramExprs , il , ref closure , setup , parent ) ;
2719+ return TryEmitComparison ( equalExpr . Left , equalExpr . Right , ExpressionType . NotEqual , equalExpr . Type , paramExprs , il , ref closure , setup , parent ) ;
27202720 }
27212721
27222722 if ( ! TryEmit ( expr . Operand , paramExprs , il , ref closure , setup , parent ) )
@@ -4374,7 +4374,7 @@ private static bool TryEmitSwitch(SwitchExpression expr, IReadOnlyList<PE> param
43744374
43754375 foreach ( var caseTestValue in cs . TestValues )
43764376 {
4377- if ( ! TryEmitComparison ( expr . SwitchValue , caseTestValue , ExpressionType . Equal , paramExprs , il , ref closure , setup , dontIgnoreTestResult ) )
4377+ if ( ! TryEmitComparison ( expr . SwitchValue , caseTestValue , ExpressionType . Equal , typeof ( bool ) , paramExprs , il , ref closure , setup , dontIgnoreTestResult ) )
43784378 return false ;
43794379 il . Emit ( OpCodes . Brtrue , labels [ caseIndex ] ) ;
43804380 }
@@ -4402,7 +4402,7 @@ private static bool TryEmitSwitch(SwitchExpression expr, IReadOnlyList<PE> param
44024402 return true ;
44034403 }
44044404
4405- private static bool TryEmitComparison ( Expression exprLeft , Expression exprRight , ExpressionType expressionType ,
4405+ private static bool TryEmitComparison ( Expression exprLeft , Expression exprRight , ExpressionType expressionType , Type exprType ,
44064406#if LIGHT_EXPRESSION
44074407 IParameterProvider paramExprs ,
44084408#else
@@ -4562,10 +4562,19 @@ var methodName
45624562 EmitLoadLocalVariableAddress ( il , lVarIndex ) ;
45634563 EmitMethodCall ( il , leftNullableHasValueGetterMethod ) ;
45644564
4565+ var isLiftedToNull = exprType == typeof ( bool ? ) ;
4566+ var leftHasValueVar = - 1 ;
4567+ if ( isLiftedToNull )
4568+ EmitStoreAndLoadLocalVariable ( il , leftHasValueVar = il . GetNextLocalVarIndex ( typeof ( bool ) ) ) ;
4569+
45654570 // ReSharper disable once AssignNullToNotNullAttribute
45664571 EmitLoadLocalVariableAddress ( il , rVarIndex ) ;
45674572 EmitMethodCall ( il , leftNullableHasValueGetterMethod ) ;
45684573
4574+ var rightHasValueVar = - 1 ;
4575+ if ( isLiftedToNull )
4576+ EmitStoreAndLoadLocalVariable ( il , rightHasValueVar = il . GetNextLocalVarIndex ( typeof ( bool ) ) ) ;
4577+
45694578 switch ( expressionType )
45704579 {
45714580 case ExpressionType . Equal :
@@ -4593,6 +4602,20 @@ var methodName
45934602 default :
45944603 return false ;
45954604 }
4605+
4606+ if ( isLiftedToNull )
4607+ {
4608+ var resultLabel = il . DefineLabel ( ) ;
4609+ var isNullLabel = il . DefineLabel ( ) ;
4610+ EmitLoadLocalVariable ( il , leftHasValueVar ) ;
4611+ il . Emit ( OpCodes . Brfalse , isNullLabel ) ;
4612+ EmitLoadLocalVariable ( il , rightHasValueVar ) ;
4613+ il . Emit ( OpCodes . Brtrue , resultLabel ) ;
4614+ il . MarkLabel ( isNullLabel ) ;
4615+ il . Emit ( OpCodes . Pop ) ;
4616+ il . Emit ( OpCodes . Ldnull ) ;
4617+ il . MarkLabel ( resultLabel ) ;
4618+ }
45964619 }
45974620
45984621 return il . EmitPopIfIgnoreResult ( parent ) ;
@@ -6616,27 +6639,28 @@ void PrintPart(Expression part)
66166639
66176640 if ( e is BinaryExpression b )
66186641 {
6619- if ( e . NodeType == ExpressionType . ArrayIndex )
6642+ var nodeType = e . NodeType ;
6643+ if ( nodeType == ExpressionType . ArrayIndex )
66206644 {
66216645 b . Left . ToCSharpString ( sb . Append ( '(' ) , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) . Append ( ')' ) ;
66226646 return b . Right . ToCSharpString ( sb . Append ( "[" ) , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) . Append ( "]" ) ;
66236647 }
66246648
6625- if ( e . NodeType == ExpressionType . Assign ||
6626- e . NodeType == ExpressionType . PowerAssign ||
6627- e . NodeType == ExpressionType . AndAssign ||
6628- e . NodeType == ExpressionType . OrAssign ||
6629- e . NodeType == ExpressionType . AddAssign ||
6630- e . NodeType == ExpressionType . ExclusiveOrAssign ||
6631- e . NodeType == ExpressionType . AddAssignChecked ||
6632- e . NodeType == ExpressionType . SubtractAssign ||
6633- e . NodeType == ExpressionType . SubtractAssignChecked ||
6634- e . NodeType == ExpressionType . MultiplyAssign ||
6635- e . NodeType == ExpressionType . MultiplyAssignChecked ||
6636- e . NodeType == ExpressionType . DivideAssign ||
6637- e . NodeType == ExpressionType . LeftShiftAssign ||
6638- e . NodeType == ExpressionType . RightShiftAssign ||
6639- e . NodeType == ExpressionType . ModuloAssign
6649+ if ( nodeType == ExpressionType . Assign ||
6650+ nodeType == ExpressionType . PowerAssign ||
6651+ nodeType == ExpressionType . AndAssign ||
6652+ nodeType == ExpressionType . OrAssign ||
6653+ nodeType == ExpressionType . AddAssign ||
6654+ nodeType == ExpressionType . ExclusiveOrAssign ||
6655+ nodeType == ExpressionType . AddAssignChecked ||
6656+ nodeType == ExpressionType . SubtractAssign ||
6657+ nodeType == ExpressionType . SubtractAssignChecked ||
6658+ nodeType == ExpressionType . MultiplyAssign ||
6659+ nodeType == ExpressionType . MultiplyAssignChecked ||
6660+ nodeType == ExpressionType . DivideAssign ||
6661+ nodeType == ExpressionType . LeftShiftAssign ||
6662+ nodeType == ExpressionType . RightShiftAssign ||
6663+ nodeType == ExpressionType . ModuloAssign
66406664 )
66416665 {
66426666 // todo: @perf handle the right part is condition with the blocks for If and/or Else, e.g. see #261 test `Serialize_the_nullable_struct_array`
@@ -6650,39 +6674,37 @@ void PrintPart(Expression part)
66506674 }
66516675
66526676 b . Left . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) ;
6653- if ( e . NodeType == ExpressionType . PowerAssign )
6677+ if ( nodeType == ExpressionType . PowerAssign )
66546678 {
66556679 sb . Append ( " = System.Math.Pow(" ) ;
66566680 b . Left . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) . Append ( ", " ) ;
66576681 return b . Right . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) . Append ( ")" ) ;
66586682 }
66596683
6660- sb . Append ( OperatorToCSharpString ( e . NodeType ) ) ;
6684+ sb . Append ( OperatorToCSharpString ( nodeType ) ) ;
66616685
66626686 return b . Right . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) ;
66636687 }
66646688
6665-
6666- b . Left . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) ;
6689+ b . Left . ToCSharpString ( sb . Append ( '(' ) , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) ;
66676690
6668- if ( e . NodeType == ExpressionType . Equal )
6691+ if ( nodeType == ExpressionType . Equal )
66696692 {
66706693 if ( b . Right is ConstantExpression r && r . Value is bool rb && rb )
66716694 return sb ;
66726695 sb . Append ( " == " ) ;
66736696 }
6674- else if ( e . NodeType == ExpressionType . NotEqual )
6697+ else if ( nodeType == ExpressionType . NotEqual )
66756698 {
66766699 if ( b . Right is ConstantExpression r && r . Value is bool rb )
66776700 return rb ? sb . Append ( " == false" ) : sb ;
66786701 sb . Append ( " != " ) ;
66796702 }
66806703 else
6681- {
6682- sb . Append ( OperatorToCSharpString ( e . NodeType ) ) ;
6683- }
6704+ sb . Append ( OperatorToCSharpString ( nodeType ) ) ;
66846705
6685- return b . Right . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) ;
6706+ return b . Right . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant )
6707+ . Append ( ')' ) ;
66866708 }
66876709
66886710 return sb . Append ( e . ToString ( ) ) ; // falling back ToString and hoping for the best
@@ -7047,23 +7069,23 @@ public static string ToCode(this Type type,
70477069 string buildInTypeString = null ;
70487070 if ( type == typeof ( void ) )
70497071 buildInTypeString = "void" ;
7050- if ( type == typeof ( object ) )
7072+ else if ( type == typeof ( object ) )
70517073 buildInTypeString = "object" ;
7052- if ( type == typeof ( bool ) )
7074+ else if ( type == typeof ( bool ) )
70537075 buildInTypeString = "bool" ;
7054- if ( type == typeof ( int ) )
7076+ else if ( type == typeof ( int ) )
70557077 buildInTypeString = "int" ;
7056- if ( type == typeof ( short ) )
7078+ else if ( type == typeof ( short ) )
70577079 buildInTypeString = "short" ;
7058- if ( type == typeof ( byte ) )
7080+ else if ( type == typeof ( byte ) )
70597081 buildInTypeString = "byte" ;
7060- if ( type == typeof ( double ) )
7082+ else if ( type == typeof ( double ) )
70617083 buildInTypeString = "double" ;
7062- if ( type == typeof ( float ) )
7084+ else if ( type == typeof ( float ) )
70637085 buildInTypeString = "float" ;
7064- if ( type == typeof ( char ) )
7086+ else if ( type == typeof ( char ) )
70657087 buildInTypeString = "char" ;
7066- if ( type == typeof ( string ) )
7088+ else if ( type == typeof ( string ) )
70677089 buildInTypeString = "string" ;
70687090
70697091 if ( buildInTypeString != null )
0 commit comments