diff --git a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs index 126ac8608..d4cb8e090 100644 --- a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs @@ -1079,7 +1079,9 @@ namespace ICSharpCode.Decompiler.CSharp { // Operator calls do not survive as calls: ReplaceMethodCallsWithOperators turns // them into operator or cast syntax, where the operand determines which operator - // is resolved, so it must keep its explicit type. + // is resolved, so it must keep its explicit type. Unlike the null literal, which + // still narrows the candidate set, the default literal converts to every type: + // C# rejects it as the operand of any binary operator except == and != (CS8310). arg = arg.RestoreDefaultLiteralType(expressionBuilder); } diff --git a/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs b/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs index d36ddaf3a..4d40d998f 100644 --- a/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs +++ b/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs @@ -229,16 +229,16 @@ namespace ICSharpCode.Decompiler.CSharp // Make explicit conversion implicit, if possible if (allowImplicitConversion) { - if (Expression is DefaultValueExpression { Type: not null } + if (Expression is DefaultValueExpression { Type: not null } defaultValue && expressionBuilder.settings.DefaultLiterals) { // The target type is supplied by the context, so "default(T)" can be // shortened to the C# 7.1 default literal. - var shortened = new DefaultValueExpression(); - shortened.CopyAnnotationsFrom(Expression); - shortened.RemoveAnnotations(); - return shortened.WithRR(new DefaultLiteralResolveResult(type)) - .WithoutILInstruction(); + defaultValue.Type = null; + defaultValue.RemoveAnnotations(); + var literalRR = new DefaultLiteralResolveResult(type); + defaultValue.AddAnnotation(literalRR); + return new TranslatedExpression(defaultValue, literalRR); } switch (ResolveResult) {