Browse Source

Shorten default(T) in place, and say why operators keep the type

Mutating the DefaultValueExpression is enough here; ConvertTo already hands
out mutated input nodes elsewhere (UnwrapChild), so building a replacement
node and copying the annotations over bought nothing.

The operator special case is easy to mistake for a cosmetic preference,
because the null literal is accepted in the same position: it converts only
to reference and nullable types, so it still narrows operator overload
resolution, whereas the default literal converts to everything and C#
rejects it outright for every binary operator except == and !=.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
pull/4014/head
Christoph Wille 1 month ago committed by Siegfried Pammer
parent
commit
9238c3b63c
  1. 4
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  2. 12
      ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

4
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -1079,7 +1079,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -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);
}

12
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -229,16 +229,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -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<ResolveResult>();
return shortened.WithRR(new DefaultLiteralResolveResult(type))
.WithoutILInstruction();
defaultValue.Type = null;
defaultValue.RemoveAnnotations<ResolveResult>();
var literalRR = new DefaultLiteralResolveResult(type);
defaultValue.AddAnnotation(literalRR);
return new TranslatedExpression(defaultValue, literalRR);
}
switch (ResolveResult)
{

Loading…
Cancel
Save