@@ -1858,7 +1858,7 @@ public static bool TryEmit(Expression expr, IReadOnlyList<PE> paramExprs,
18581858 case ExpressionType . Equal :
18591859 case ExpressionType . NotEqual :
18601860 var binaryExpr = ( BinaryExpression ) expr ;
1861- return TryEmitComparison ( binaryExpr . Left , binaryExpr . Right , binaryExpr . NodeType , paramExprs , il , ref closure , setup , parent ) ;
1861+ return TryEmitComparison ( binaryExpr . Left , binaryExpr . Right , binaryExpr . NodeType , expr . Type , paramExprs , il , ref closure , setup , parent ) ;
18621862
18631863 case ExpressionType . Add :
18641864 case ExpressionType . AddChecked :
@@ -2723,7 +2723,7 @@ private static bool TryEmitNot(UnaryExpression expr, IReadOnlyList<PE> paramExpr
27232723 if ( expr . Operand . NodeType == ExpressionType . Equal )
27242724 {
27252725 var equalExpr = ( BinaryExpression ) expr . Operand ;
2726- return TryEmitComparison ( equalExpr . Left , equalExpr . Right , ExpressionType . NotEqual , paramExprs , il , ref closure , setup , parent ) ;
2726+ return TryEmitComparison ( equalExpr . Left , equalExpr . Right , ExpressionType . NotEqual , equalExpr . Type , paramExprs , il , ref closure , setup , parent ) ;
27272727 }
27282728
27292729 if ( ! TryEmit ( expr . Operand , paramExprs , il , ref closure , setup , parent ) )
@@ -4391,7 +4391,7 @@ private static bool TryEmitSwitch(SwitchExpression expr, IReadOnlyList<PE> param
43914391
43924392 foreach ( var caseTestValue in cs . TestValues )
43934393 {
4394- if ( ! TryEmitComparison ( expr . SwitchValue , caseTestValue , ExpressionType . Equal , paramExprs , il , ref closure , setup , dontIgnoreTestResult ) )
4394+ if ( ! TryEmitComparison ( expr . SwitchValue , caseTestValue , ExpressionType . Equal , typeof ( bool ) , paramExprs , il , ref closure , setup , dontIgnoreTestResult ) )
43954395 return false ;
43964396 il . Emit ( OpCodes . Brtrue , labels [ caseIndex ] ) ;
43974397 }
@@ -4419,7 +4419,7 @@ private static bool TryEmitSwitch(SwitchExpression expr, IReadOnlyList<PE> param
44194419 return true ;
44204420 }
44214421
4422- private static bool TryEmitComparison ( Expression exprLeft , Expression exprRight , ExpressionType expressionType ,
4422+ private static bool TryEmitComparison ( Expression exprLeft , Expression exprRight , ExpressionType expressionType , Type exprType ,
44234423#if LIGHT_EXPRESSION
44244424 IParameterProvider paramExprs ,
44254425#else
@@ -4579,10 +4579,19 @@ var methodName
45794579 EmitLoadLocalVariableAddress ( il , lVarIndex ) ;
45804580 EmitMethodCall ( il , leftNullableHasValueGetterMethod ) ;
45814581
4582+ var isLiftedToNull = exprType == typeof ( bool ? ) ;
4583+ var leftHasValueVar = - 1 ;
4584+ if ( isLiftedToNull )
4585+ EmitStoreAndLoadLocalVariable ( il , leftHasValueVar = il . GetNextLocalVarIndex ( typeof ( bool ) ) ) ;
4586+
45824587 // ReSharper disable once AssignNullToNotNullAttribute
45834588 EmitLoadLocalVariableAddress ( il , rVarIndex ) ;
45844589 EmitMethodCall ( il , leftNullableHasValueGetterMethod ) ;
45854590
4591+ var rightHasValueVar = - 1 ;
4592+ if ( isLiftedToNull )
4593+ EmitStoreAndLoadLocalVariable ( il , rightHasValueVar = il . GetNextLocalVarIndex ( typeof ( bool ) ) ) ;
4594+
45864595 switch ( expressionType )
45874596 {
45884597 case ExpressionType . Equal :
@@ -4610,6 +4619,20 @@ var methodName
46104619 default :
46114620 return false ;
46124621 }
4622+
4623+ if ( isLiftedToNull )
4624+ {
4625+ var resultLabel = il . DefineLabel ( ) ;
4626+ var isNullLabel = il . DefineLabel ( ) ;
4627+ EmitLoadLocalVariable ( il , leftHasValueVar ) ;
4628+ il . Emit ( OpCodes . Brfalse , isNullLabel ) ;
4629+ EmitLoadLocalVariable ( il , rightHasValueVar ) ;
4630+ il . Emit ( OpCodes . Brtrue , resultLabel ) ;
4631+ il . MarkLabel ( isNullLabel ) ;
4632+ il . Emit ( OpCodes . Pop ) ;
4633+ il . Emit ( OpCodes . Ldnull ) ;
4634+ il . MarkLabel ( resultLabel ) ;
4635+ }
46134636 }
46144637
46154638 return il . EmitPopIfIgnoreResult ( parent ) ;
@@ -6633,27 +6656,28 @@ void PrintPart(Expression part)
66336656
66346657 if ( e is BinaryExpression b )
66356658 {
6636- if ( e . NodeType == ExpressionType . ArrayIndex )
6659+ var nodeType = e . NodeType ;
6660+ if ( nodeType == ExpressionType . ArrayIndex )
66376661 {
66386662 b . Left . ToCSharpString ( sb . Append ( '(' ) , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) . Append ( ')' ) ;
66396663 return b . Right . ToCSharpString ( sb . Append ( "[" ) , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) . Append ( "]" ) ;
66406664 }
66416665
6642- if ( e . NodeType == ExpressionType . Assign ||
6643- e . NodeType == ExpressionType . PowerAssign ||
6644- e . NodeType == ExpressionType . AndAssign ||
6645- e . NodeType == ExpressionType . OrAssign ||
6646- e . NodeType == ExpressionType . AddAssign ||
6647- e . NodeType == ExpressionType . ExclusiveOrAssign ||
6648- e . NodeType == ExpressionType . AddAssignChecked ||
6649- e . NodeType == ExpressionType . SubtractAssign ||
6650- e . NodeType == ExpressionType . SubtractAssignChecked ||
6651- e . NodeType == ExpressionType . MultiplyAssign ||
6652- e . NodeType == ExpressionType . MultiplyAssignChecked ||
6653- e . NodeType == ExpressionType . DivideAssign ||
6654- e . NodeType == ExpressionType . LeftShiftAssign ||
6655- e . NodeType == ExpressionType . RightShiftAssign ||
6656- e . NodeType == ExpressionType . ModuloAssign
6666+ if ( nodeType == ExpressionType . Assign ||
6667+ nodeType == ExpressionType . PowerAssign ||
6668+ nodeType == ExpressionType . AndAssign ||
6669+ nodeType == ExpressionType . OrAssign ||
6670+ nodeType == ExpressionType . AddAssign ||
6671+ nodeType == ExpressionType . ExclusiveOrAssign ||
6672+ nodeType == ExpressionType . AddAssignChecked ||
6673+ nodeType == ExpressionType . SubtractAssign ||
6674+ nodeType == ExpressionType . SubtractAssignChecked ||
6675+ nodeType == ExpressionType . MultiplyAssign ||
6676+ nodeType == ExpressionType . MultiplyAssignChecked ||
6677+ nodeType == ExpressionType . DivideAssign ||
6678+ nodeType == ExpressionType . LeftShiftAssign ||
6679+ nodeType == ExpressionType . RightShiftAssign ||
6680+ nodeType == ExpressionType . ModuloAssign
66576681 )
66586682 {
66596683 // 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`
@@ -6667,39 +6691,37 @@ void PrintPart(Expression part)
66676691 }
66686692
66696693 b . Left . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) ;
6670- if ( e . NodeType == ExpressionType . PowerAssign )
6694+ if ( nodeType == ExpressionType . PowerAssign )
66716695 {
66726696 sb . Append ( " = System.Math.Pow(" ) ;
66736697 b . Left . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) . Append ( ", " ) ;
66746698 return b . Right . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) . Append ( ")" ) ;
66756699 }
66766700
6677- sb . Append ( OperatorToCSharpString ( e . NodeType ) ) ;
6701+ sb . Append ( OperatorToCSharpString ( nodeType ) ) ;
66786702
66796703 return b . Right . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) ;
66806704 }
66816705
6682-
6683- b . Left . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) ;
6706+ b . Left . ToCSharpString ( sb . Append ( '(' ) , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) ;
66846707
6685- if ( e . NodeType == ExpressionType . Equal )
6708+ if ( nodeType == ExpressionType . Equal )
66866709 {
66876710 if ( b . Right is ConstantExpression r && r . Value is bool rb && rb )
66886711 return sb ;
66896712 sb . Append ( " == " ) ;
66906713 }
6691- else if ( e . NodeType == ExpressionType . NotEqual )
6714+ else if ( nodeType == ExpressionType . NotEqual )
66926715 {
66936716 if ( b . Right is ConstantExpression r && r . Value is bool rb )
66946717 return rb ? sb . Append ( " == false" ) : sb ;
66956718 sb . Append ( " != " ) ;
66966719 }
66976720 else
6698- {
6699- sb . Append ( OperatorToCSharpString ( e . NodeType ) ) ;
6700- }
6721+ sb . Append ( OperatorToCSharpString ( nodeType ) ) ;
67016722
6702- return b . Right . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant ) ;
6723+ return b . Right . ToCSharpString ( sb , lineIdent , stripNamespace , printType , identSpaces , tryPrintConstant )
6724+ . Append ( ')' ) ;
67036725 }
67046726
67056727 return sb . Append ( e . ToString ( ) ) ; // falling back ToString and hoping for the best
@@ -7070,23 +7092,23 @@ public static string ToCode(this Type type,
70707092 string buildInTypeString = null ;
70717093 if ( type == typeof ( void ) )
70727094 buildInTypeString = "void" ;
7073- if ( type == typeof ( object ) )
7095+ else if ( type == typeof ( object ) )
70747096 buildInTypeString = "object" ;
7075- if ( type == typeof ( bool ) )
7097+ else if ( type == typeof ( bool ) )
70767098 buildInTypeString = "bool" ;
7077- if ( type == typeof ( int ) )
7099+ else if ( type == typeof ( int ) )
70787100 buildInTypeString = "int" ;
7079- if ( type == typeof ( short ) )
7101+ else if ( type == typeof ( short ) )
70807102 buildInTypeString = "short" ;
7081- if ( type == typeof ( byte ) )
7103+ else if ( type == typeof ( byte ) )
70827104 buildInTypeString = "byte" ;
7083- if ( type == typeof ( double ) )
7105+ else if ( type == typeof ( double ) )
70847106 buildInTypeString = "double" ;
7085- if ( type == typeof ( float ) )
7107+ else if ( type == typeof ( float ) )
70867108 buildInTypeString = "float" ;
7087- if ( type == typeof ( char ) )
7109+ else if ( type == typeof ( char ) )
70887110 buildInTypeString = "char" ;
7089- if ( type == typeof ( string ) )
7111+ else if ( type == typeof ( string ) )
70907112 buildInTypeString = "string" ;
70917113
70927114 if ( buildInTypeString != null )
0 commit comments