mirror of
https://github.com/icsharpcode/ILSpy.git
synced 2026-10-12 02:15:58 +00:00
Emit C# 7.1 default literals where the context supplies the type
Shortening default(T) is the same problem as removing the redundant cast around a lambda whose delegate type the context already fixes, so it uses the same mechanism: ConvertTo makes the explicit type implicit when the conversion is an identity conversion and the caller allows an implicit one. The literal keeps the type it was shortened from, so any later conversion to a different type - or any context that requires an explicit type, such as an overload resolution recheck falling back to CastArguments - can spell default(T) out again. That keeps the value intact where the bare literal would change it, e.g. "object o = default(SomeStruct)", which boxes a non-null struct while "default" would be null. Because the shortened literal resolves to DefaultLiteralResolveResult, CallBuilder's existing overload resolution recheck sees a real default literal and rejects ambiguous calls on its own; no separate bookkeeping about which arguments may stay untyped is needed. Only the contexts that supply no target type at all restore the explicit form: an awaited expression, and arguments of operator methods, which later become operator or cast syntax rather than calls. Assisted-by: Claude:claude-opus-5[1m]:Claude Code
This commit is contained in:
committed by
Siegfried Pammer
parent
f3f80cd463
commit
fe9f6db3ee
@@ -482,6 +482,24 @@ namespace ICSharpCode.Decompiler.Tests
|
||||
await RunForLibrary(cscOptions: cscOptions);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DefaultLiteral([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions)
|
||||
{
|
||||
await RunForLibrary(cscOptions: cscOptions);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task OverloadResolution([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions)
|
||||
{
|
||||
await RunForLibrary(cscOptions: cscOptions);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TargetTypedDefault([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions)
|
||||
{
|
||||
await RunForLibrary(cscOptions: cscOptions);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task PatternMatching([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions)
|
||||
{
|
||||
|
||||
@@ -1638,14 +1638,20 @@ namespace ICSharpCode.Decompiler.Tests.Semantics
|
||||
Assert.That(c.Method.DeclaringType.Name, Is.EqualTo("OperatorInBaseClass"));
|
||||
}
|
||||
|
||||
[Test, Ignore("C# standard 10.2.16 is not implemented: CSharpConversions.ImplicitConversion has a TODO for default literal conversions, and no ResolveResult represents a typeless default literal")]
|
||||
[Test]
|
||||
public void DefaultLiteralConversions()
|
||||
{
|
||||
// C# standard 10.2.16: an implicit conversion exists from a default_literal to
|
||||
// any type, producing the default value of the inferred type. Once the semantic
|
||||
// model gains a typeless default-literal ResolveResult, this test should assert
|
||||
// that it converts to int, string, int? and type parameters.
|
||||
Assert.Fail("Default literal conversions are not implemented.");
|
||||
// C# standard 10.2.16: an implicit conversion exists from a default_literal to any type
|
||||
var defaultLiteral = new DefaultLiteralResolveResult();
|
||||
// a default_value_expression is a constant expression (C# standard 12.8.21)
|
||||
Assert.That(defaultLiteral.IsCompileTimeConstant);
|
||||
Assert.That(conversions.ImplicitConversion(defaultLiteral, compilation.FindType(KnownTypeCode.Int32)), Is.EqualTo(C.DefaultLiteralConversion));
|
||||
Assert.That(conversions.ImplicitConversion(defaultLiteral, compilation.FindType(KnownTypeCode.String)), Is.EqualTo(C.DefaultLiteralConversion));
|
||||
Assert.That(conversions.ImplicitConversion(defaultLiteral, compilation.FindType(typeof(int?))), Is.EqualTo(C.DefaultLiteralConversion));
|
||||
ITypeParameter t = new DefaultTypeParameter(compilation, SymbolKind.Method, 0, "T");
|
||||
Assert.That(conversions.ImplicitConversion(defaultLiteral, t), Is.EqualTo(C.DefaultLiteralConversion));
|
||||
// explicit conversions include all implicit conversions, so (T)default is also valid
|
||||
Assert.That(conversions.ExplicitConversion(defaultLiteral, compilation.FindType(KnownTypeCode.Int32)), Is.EqualTo(C.DefaultLiteralConversion));
|
||||
}
|
||||
|
||||
[Test, Ignore("C# standard 10.2.18 is not implemented: no ResolveResult represents a switch expression; the decompiler converts each arm separately in ILAst")]
|
||||
|
||||
@@ -43,8 +43,82 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
|
||||
Issue2444.M2();
|
||||
Issue2741.B.Test(new Issue2741.C());
|
||||
ExtensionMethodDemo.Issue2165.Test();
|
||||
#if CS71
|
||||
DefaultLiteralTests();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CS71
|
||||
static void DefaultLiteralTests()
|
||||
{
|
||||
// The decompiled output may shorten default(T) to a default literal;
|
||||
// re-compilation must still pick the same overloads and operators.
|
||||
DefaultOverload(default(DataStruct));
|
||||
DefaultOverload(default(OtherStruct));
|
||||
DefaultNullableOverload(default(DataStruct));
|
||||
Console.WriteLine(default(DataStruct) == new DataStruct());
|
||||
Console.WriteLine(GenericDefault("x", default));
|
||||
Console.WriteLine(GenericDefault(42, default));
|
||||
}
|
||||
|
||||
struct DataStruct
|
||||
{
|
||||
public int Field;
|
||||
|
||||
public static bool operator ==(DataStruct a, DataStruct b)
|
||||
{
|
||||
Console.WriteLine("DataStruct operator ==");
|
||||
return a.Field == b.Field;
|
||||
}
|
||||
|
||||
public static bool operator !=(DataStruct a, DataStruct b)
|
||||
{
|
||||
return a.Field != b.Field;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is DataStruct other && Field == other.Field;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Field;
|
||||
}
|
||||
}
|
||||
|
||||
struct OtherStruct
|
||||
{
|
||||
public int Field;
|
||||
}
|
||||
|
||||
static void DefaultOverload(DataStruct data)
|
||||
{
|
||||
Console.WriteLine("DefaultOverload(DataStruct)");
|
||||
}
|
||||
|
||||
static void DefaultOverload(OtherStruct data)
|
||||
{
|
||||
Console.WriteLine("DefaultOverload(OtherStruct)");
|
||||
}
|
||||
|
||||
static void DefaultNullableOverload(DataStruct data)
|
||||
{
|
||||
Console.WriteLine("DefaultNullableOverload(DataStruct)");
|
||||
}
|
||||
|
||||
static void DefaultNullableOverload(DataStruct? data)
|
||||
{
|
||||
Console.WriteLine("DefaultNullableOverload(DataStruct?)");
|
||||
}
|
||||
|
||||
static T GenericDefault<T>(T a, T b)
|
||||
{
|
||||
Console.WriteLine("GenericDefault: " + typeof(T).Name);
|
||||
return b;
|
||||
}
|
||||
#endif
|
||||
|
||||
#region ConstructorTest
|
||||
static void ConstructorTest()
|
||||
{
|
||||
|
||||
@@ -5,8 +5,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.ILPretty
|
||||
{
|
||||
private void dgvItemList_CellValueChanged(object sender, DataGridViewCellEventArgs e)
|
||||
{
|
||||
string text = default(string);
|
||||
string s = default(string);
|
||||
string text = default;
|
||||
string s = default;
|
||||
switch (text)
|
||||
{
|
||||
case "rowno":
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.ILPretty
|
||||
{
|
||||
public static implicit operator ReadOnlySpan<char>(object o)
|
||||
{
|
||||
return default(ReadOnlySpan<char>);
|
||||
return default;
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<char> ConvertString(string s)
|
||||
|
||||
@@ -35,7 +35,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait
|
||||
{
|
||||
public TaskAwaiter GetAwaiter()
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TaskAwaiter);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +55,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait
|
||||
{
|
||||
public ValueTask DisposeAsync()
|
||||
{
|
||||
return default(ValueTask);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -247,7 +251,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait
|
||||
{
|
||||
public static TaskAwaiter GetAwaiter(this IAwaitableMarker marker)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TaskAwaiter);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static TaskAwaiter GetAwaiter(this int millisecondsDelay)
|
||||
@@ -257,12 +265,20 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait
|
||||
|
||||
public static TaskAwaiter GetAwaiter(this Action action)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TaskAwaiter);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static TaskAwaiter<T[]> GetAwaiter<T>(this IEnumerable<Task<T>> tasks)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TaskAwaiter<T[]>);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CS70 && !NET40
|
||||
@@ -573,7 +589,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait
|
||||
|
||||
public TaskAwaiter Self()
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TaskAwaiter);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -582,7 +602,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait
|
||||
{
|
||||
public TaskAwaiter GetAwaiter()
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TaskAwaiter);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -609,7 +633,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait
|
||||
{
|
||||
TaskAwaiter IAwaitable.GetAwaiter()
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TaskAwaiter);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,7 +646,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait
|
||||
{
|
||||
TaskAwaiter IAwaitable.GetAwaiter()
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TaskAwaiter);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,7 +658,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait
|
||||
{
|
||||
public TaskAwaiter<T> GetAwaiter()
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TaskAwaiter<T>);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -664,7 +700,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait
|
||||
public TaskAwaiter GetAwaiter()
|
||||
{
|
||||
Counter++;
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TaskAwaiter);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static async void TestAsyncUsingStruct()
|
||||
{
|
||||
await using (AsyncDisposableStruct asyncDisposableStruct = default(AsyncDisposableStruct))
|
||||
await using (AsyncDisposableStruct asyncDisposableStruct = default)
|
||||
{
|
||||
Use(asyncDisposableStruct);
|
||||
}
|
||||
@@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static async void TestAsyncUsingNullableStruct()
|
||||
{
|
||||
await using (AsyncDisposableStruct? asyncDisposableStruct = new AsyncDisposableStruct?(default(AsyncDisposableStruct)))
|
||||
await using (AsyncDisposableStruct? asyncDisposableStruct = new AsyncDisposableStruct?(default))
|
||||
{
|
||||
Use(asyncDisposableStruct);
|
||||
}
|
||||
|
||||
@@ -5024,7 +5024,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
}
|
||||
public static void CustomStructAddTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
p += default(CustomStruct);
|
||||
num += default(CustomStruct);
|
||||
Use(ref num);
|
||||
@@ -5051,7 +5055,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CustomStructSubtractTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
p -= default(CustomStruct);
|
||||
num -= default(CustomStruct);
|
||||
Use(ref num);
|
||||
@@ -5078,7 +5086,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CustomStructMultiplyTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
p *= default(CustomStruct);
|
||||
num *= default(CustomStruct);
|
||||
Use(ref num);
|
||||
@@ -5105,7 +5117,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CustomStructDivideTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
p /= default(CustomStruct);
|
||||
num /= default(CustomStruct);
|
||||
Use(ref num);
|
||||
@@ -5132,7 +5148,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CustomStructModulusTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
p %= default(CustomStruct);
|
||||
num %= default(CustomStruct);
|
||||
Use(ref num);
|
||||
@@ -5159,7 +5179,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CustomStructLeftShiftTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
p <<= 5;
|
||||
num <<= 5;
|
||||
Use(ref num);
|
||||
@@ -5186,7 +5210,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CustomStructRightShiftTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
p >>= 5;
|
||||
num >>= 5;
|
||||
Use(ref num);
|
||||
@@ -5239,7 +5267,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CustomStructBitAndTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
p &= default(CustomStruct);
|
||||
num &= default(CustomStruct);
|
||||
Use(ref num);
|
||||
@@ -5266,7 +5298,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CustomStructBitOrTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
p |= default(CustomStruct);
|
||||
num |= default(CustomStruct);
|
||||
Use(ref num);
|
||||
@@ -5293,7 +5329,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CustomStructBitXorTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
p ^= default(CustomStruct);
|
||||
num ^= default(CustomStruct);
|
||||
Use(ref num);
|
||||
@@ -5320,7 +5360,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CustomStructPostIncTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
X(p++);
|
||||
X(num++);
|
||||
Use(ref num);
|
||||
@@ -5347,7 +5391,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CustomStructPreIncTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
X(++p);
|
||||
X(++num);
|
||||
Use(ref num);
|
||||
@@ -5373,7 +5421,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
}
|
||||
public static void CustomStructPostDecTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
X(p--);
|
||||
X(num--);
|
||||
Use(ref num);
|
||||
@@ -5400,7 +5452,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CustomStructPreDecTest(CustomStruct p, CustomClass c, CustomStruct2 s)
|
||||
{
|
||||
#if CS71
|
||||
CustomStruct num = default;
|
||||
#else
|
||||
CustomStruct num = default(CustomStruct);
|
||||
#endif
|
||||
X(--p);
|
||||
X(--num);
|
||||
Use(ref num);
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static implicit operator MyInt(int x)
|
||||
{
|
||||
return default(MyInt);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,8 +89,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public void Deconstruct(out T a, out T2 b)
|
||||
{
|
||||
a = default(T);
|
||||
b = default(T2);
|
||||
a = default;
|
||||
b = default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,9 +100,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public void Deconstruct(out T a, out T2 b, out T3 c)
|
||||
{
|
||||
a = default(T);
|
||||
b = default(T2);
|
||||
c = default(T3);
|
||||
a = default;
|
||||
b = default;
|
||||
c = default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,8 +112,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public void Deconstruct(out T a, out T2 b)
|
||||
{
|
||||
a = default(T);
|
||||
b = default(T2);
|
||||
a = default;
|
||||
b = default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +177,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
private StructDeconstructionSource<T, T2> GetStructSource<T, T2>()
|
||||
{
|
||||
return default(StructDeconstructionSource<T, T2>);
|
||||
return default;
|
||||
}
|
||||
|
||||
private ref T GetRef<T>()
|
||||
@@ -187,12 +187,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
private (T, T2) GetTuple<T, T2>()
|
||||
{
|
||||
return default((T, T2));
|
||||
return default;
|
||||
}
|
||||
|
||||
private (T, T2, T3) GetTuple<T, T2, T3>()
|
||||
{
|
||||
return default((T, T2, T3));
|
||||
return default;
|
||||
}
|
||||
|
||||
private List<T> GetList<T>()
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
// Copyright (c) 2026 Siegfried Pammer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
{
|
||||
internal class DefaultLiteral
|
||||
{
|
||||
public struct Data
|
||||
{
|
||||
public int Field;
|
||||
|
||||
public static Data operator +(Data a, Data b)
|
||||
{
|
||||
return new Data {
|
||||
Field = a.Field + b.Field
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public struct OtherData
|
||||
{
|
||||
public int Field;
|
||||
}
|
||||
|
||||
public int this[Data d] => d.Field;
|
||||
|
||||
public int DeclarationWithInitializer()
|
||||
{
|
||||
Data data = default;
|
||||
return data.Field + data.Field;
|
||||
}
|
||||
|
||||
public int Assignment(Data data)
|
||||
{
|
||||
int field = data.Field;
|
||||
data = default;
|
||||
return field + data.Field;
|
||||
}
|
||||
|
||||
public Data Return()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public T ReturnGeneric<T>()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public async Task<Data> ReturnAsync()
|
||||
{
|
||||
await Task.Yield();
|
||||
return default;
|
||||
}
|
||||
|
||||
public string AmbiguousArgumentStaysTyped()
|
||||
{
|
||||
return Overloaded(default(Data));
|
||||
}
|
||||
|
||||
public string BetterConversionTargetArgument()
|
||||
{
|
||||
return OverloadedNullable(default);
|
||||
}
|
||||
|
||||
public int UnambiguousArgument()
|
||||
{
|
||||
return Single(default);
|
||||
}
|
||||
|
||||
public string BoxedArgumentStaysTyped()
|
||||
{
|
||||
return Boxed(default(Data));
|
||||
}
|
||||
|
||||
public int IndexerArgument()
|
||||
{
|
||||
return this[default];
|
||||
}
|
||||
|
||||
public Data OperatorOperandStaysTyped(Data data)
|
||||
{
|
||||
return data + default(Data);
|
||||
}
|
||||
|
||||
public string NonIdentityConversionsStayTyped()
|
||||
{
|
||||
object obj = default(Data);
|
||||
return obj.ToString() + obj.ToString();
|
||||
}
|
||||
|
||||
private int Single(Data data)
|
||||
{
|
||||
return data.Field;
|
||||
}
|
||||
|
||||
private string Boxed(object o)
|
||||
{
|
||||
return o.ToString();
|
||||
}
|
||||
|
||||
private string Overloaded(Data x)
|
||||
{
|
||||
return "Data";
|
||||
}
|
||||
|
||||
private string Overloaded(OtherData x)
|
||||
{
|
||||
return "OtherData";
|
||||
}
|
||||
|
||||
private string OverloadedNullable(Data x)
|
||||
{
|
||||
return "Data";
|
||||
}
|
||||
|
||||
private string OverloadedNullable(Data? x)
|
||||
{
|
||||
return "Data?";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -261,7 +261,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction
|
||||
{
|
||||
public Func<TCaptured> GetFunc(Func<TNonCaptured, TCaptured> f)
|
||||
{
|
||||
#if CS71
|
||||
TCaptured captured = f(default);
|
||||
#else
|
||||
TCaptured captured = f(default(TNonCaptured));
|
||||
#endif
|
||||
return () => {
|
||||
Console.WriteLine(captured.GetType().FullName);
|
||||
return captured;
|
||||
|
||||
@@ -966,7 +966,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static DateTime ParseDateTime(this object str)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(DateTime);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
{
|
||||
public static implicit operator ReadOnlySpan<int>(SpanConvertible c)
|
||||
{
|
||||
return default(ReadOnlySpan<int>);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void OutSpanOrByValue(out ReadOnlySpan<int> s)
|
||||
{
|
||||
s = default(ReadOnlySpan<int>);
|
||||
s = default;
|
||||
}
|
||||
|
||||
public static void OutSpanOrByValue(ReadOnlySpan<int> s)
|
||||
|
||||
@@ -73,7 +73,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
|
||||
|
||||
public S this[int index] {
|
||||
get {
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(S);
|
||||
#endif
|
||||
}
|
||||
set {
|
||||
}
|
||||
@@ -81,7 +85,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
|
||||
|
||||
public S this[object key] {
|
||||
get {
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(S);
|
||||
#endif
|
||||
}
|
||||
set {
|
||||
}
|
||||
@@ -158,7 +166,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.InitializerTests
|
||||
|
||||
public StructData(int initialValue)
|
||||
{
|
||||
#if CS71
|
||||
this = default;
|
||||
#else
|
||||
this = default(StructData);
|
||||
#endif
|
||||
Field = initialValue;
|
||||
Property = initialValue;
|
||||
}
|
||||
|
||||
@@ -125,12 +125,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public Byte16 GetByte16()
|
||||
{
|
||||
return default(Byte16);
|
||||
return default;
|
||||
}
|
||||
|
||||
public Generic16<T> GetGeneric<T>()
|
||||
{
|
||||
return default(Generic16<T>);
|
||||
return default;
|
||||
}
|
||||
|
||||
public int GetIndex()
|
||||
|
||||
@@ -8,13 +8,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
[StructLayout(LayoutKind.Sequential, Size = 1)]
|
||||
public readonly struct fsResult
|
||||
{
|
||||
public static fsResult Success => default(fsResult);
|
||||
public static fsResult Failure => default(fsResult);
|
||||
public static fsResult Success => default;
|
||||
public static fsResult Failure => default;
|
||||
public bool Succeeded => true;
|
||||
public bool Failed => false;
|
||||
public static fsResult operator +(fsResult a, fsResult b)
|
||||
{
|
||||
return default(fsResult);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.Issue3571_B
|
||||
[StructLayout(LayoutKind.Sequential, Size = 1)]
|
||||
public readonly struct fsResult
|
||||
{
|
||||
public static fsResult Success => default(fsResult);
|
||||
public static fsResult Failure => default(fsResult);
|
||||
public static fsResult Success => default;
|
||||
public static fsResult Failure => default;
|
||||
public bool Succeeded => true;
|
||||
public bool Failed => false;
|
||||
public static fsResult operator +(fsResult a, fsResult b)
|
||||
{
|
||||
return default(fsResult);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,13 +25,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.Issue3571_Helper
|
||||
[StructLayout(LayoutKind.Sequential, Size = 1)]
|
||||
public readonly struct fsResult
|
||||
{
|
||||
public static fsResult Success => default(fsResult);
|
||||
public static fsResult Failure => default(fsResult);
|
||||
public static fsResult Success => default;
|
||||
public static fsResult Failure => default;
|
||||
public bool Succeeded => true;
|
||||
public bool Failed => false;
|
||||
public static fsResult operator +(fsResult a, fsResult b)
|
||||
{
|
||||
return default(fsResult);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
get {
|
||||
if (i >= Length || i < 0)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(T);
|
||||
#endif
|
||||
}
|
||||
if (results[i] != null && results[i].Equals(default(T)))
|
||||
{
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public virtual U? ReturnOnly<U>()
|
||||
{
|
||||
return default(U);
|
||||
return default;
|
||||
}
|
||||
|
||||
public virtual T?[] Nested<T>(T?[] values)
|
||||
@@ -78,7 +78,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public override U? ReturnOnly<U>() where U : default
|
||||
{
|
||||
return default(U);
|
||||
return default;
|
||||
}
|
||||
|
||||
public override T?[] Nested<T>(T?[] values) where T : default
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace LocalFunctions
|
||||
public int MixedLocalFunction<T2>() where T2 : ICloneable, IConvertible
|
||||
{
|
||||
#pragma warning disable CS0219
|
||||
T2 t2 = default(T2);
|
||||
T2 t2 = default;
|
||||
object z = this;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
@@ -52,7 +52,7 @@ namespace LocalFunctions
|
||||
int NonStaticMethod<T3>(int unused)
|
||||
#endif
|
||||
{
|
||||
t2 = default(T2);
|
||||
t2 = default;
|
||||
int l = 0;
|
||||
return NonStaticMethod3<T1>() + NonStaticMethod3<T2>() + z.GetHashCode();
|
||||
int NonStaticMethod3<T4>()
|
||||
@@ -118,7 +118,7 @@ namespace LocalFunctions
|
||||
|
||||
public int MixedLocalFunction2Delegate<T2>() where T2 : ICloneable, IConvertible
|
||||
{
|
||||
T2 t2 = default(T2);
|
||||
T2 t2 = default;
|
||||
object z = this;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
@@ -126,7 +126,7 @@ namespace LocalFunctions
|
||||
i2 += StaticInvokeAsFunc(NonStaticMethod<object>);
|
||||
int NonStaticMethod<T3>()
|
||||
{
|
||||
t2 = default(T2);
|
||||
t2 = default;
|
||||
int l = 0;
|
||||
return StaticInvokeAsFunc(NonStaticMethod3<T1>) + StaticInvokeAsFunc(NonStaticMethod3<T2>) + z.GetHashCode();
|
||||
int NonStaticMethod3<T4>()
|
||||
@@ -155,7 +155,7 @@ namespace LocalFunctions
|
||||
int StaticInvokeAsFunc2<T>(Func<T, int> func)
|
||||
#endif
|
||||
{
|
||||
return func(default(T));
|
||||
return func(default);
|
||||
}
|
||||
#if CS80
|
||||
static int StaticMethod<T3>() where T3 : struct
|
||||
@@ -209,19 +209,19 @@ namespace LocalFunctions
|
||||
public static void Test_CaptureT<T2>()
|
||||
{
|
||||
#pragma warning disable CS0219
|
||||
T2 t2 = default(T2);
|
||||
T2 t2 = default;
|
||||
Method<int>();
|
||||
void Method<T3>()
|
||||
{
|
||||
t2 = default(T2);
|
||||
t2 = default;
|
||||
T2 t2x = t2;
|
||||
T3 t3 = default(T3);
|
||||
T3 t3 = default;
|
||||
Method2();
|
||||
void Method2()
|
||||
{
|
||||
t2 = default(T2);
|
||||
t2 = default;
|
||||
t2x = t2;
|
||||
t3 = default(T3);
|
||||
t3 = default;
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0219
|
||||
|
||||
@@ -515,7 +515,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static T LastOrDefault<T>(IEnumerable<T> items)
|
||||
{
|
||||
#if CS71
|
||||
T result = default;
|
||||
#else
|
||||
T result = default(T);
|
||||
#endif
|
||||
foreach (T item in items)
|
||||
{
|
||||
result = item;
|
||||
|
||||
@@ -37,7 +37,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
public void TestB(S x, ref S y)
|
||||
{
|
||||
b[5, 3] = new S[10];
|
||||
#if CS71
|
||||
b[5, 3][0] = default;
|
||||
#else
|
||||
b[5, 3][0] = default(S);
|
||||
#endif
|
||||
b[5, 3][1] = x;
|
||||
b[5, 3][2] = y;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
public readonly int ReadonlyIntVal;
|
||||
public MyClass Field;
|
||||
public MyStruct? Property1 => null;
|
||||
#if CS71
|
||||
public MyStruct Property2 => default;
|
||||
#else
|
||||
public MyStruct Property2 => default(MyStruct);
|
||||
#endif
|
||||
public MyStruct? this[int index] => null;
|
||||
public MyStruct? Method1(int arg)
|
||||
{
|
||||
@@ -58,7 +62,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
}
|
||||
public MyStruct Method2(int arg)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(MyStruct);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Done()
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
{
|
||||
public static TValue? Default<TValue>()
|
||||
{
|
||||
return default(TValue);
|
||||
return default;
|
||||
}
|
||||
|
||||
public static void CallDefault()
|
||||
@@ -204,7 +204,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
[return: MaybeNull]
|
||||
public T FirstOrDefault<T>(IEnumerable<T> source)
|
||||
{
|
||||
return default(T);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
private bool TryGet<T>(out T result)
|
||||
{
|
||||
result = default(T);
|
||||
result = default;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
// Copyright (c) 2026 Siegfried Pammer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#pragma warning disable 660, 661
|
||||
|
||||
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
{
|
||||
internal class OverloadResolution
|
||||
{
|
||||
public struct Data
|
||||
{
|
||||
public int Field;
|
||||
|
||||
public static bool operator ==(Data a, Data b)
|
||||
{
|
||||
return a.Field == b.Field;
|
||||
}
|
||||
|
||||
public static bool operator !=(Data a, Data b)
|
||||
{
|
||||
return a.Field != b.Field;
|
||||
}
|
||||
}
|
||||
|
||||
public struct OtherData
|
||||
{
|
||||
public int Field;
|
||||
}
|
||||
|
||||
public void IntegerOverloads()
|
||||
{
|
||||
Integer(1);
|
||||
Integer((short)1);
|
||||
Integer(1L);
|
||||
}
|
||||
|
||||
public void ReferenceTypeOverloads()
|
||||
{
|
||||
RefType("string");
|
||||
RefType((object)"string");
|
||||
RefType(null);
|
||||
RefType((object)null);
|
||||
}
|
||||
|
||||
public void NullableOverloads()
|
||||
{
|
||||
NullableInt(1);
|
||||
NullableInt((int?)1);
|
||||
NullableInt(null);
|
||||
}
|
||||
|
||||
public void ParamsOverloads(int n)
|
||||
{
|
||||
Params(1);
|
||||
Params(1, 2);
|
||||
Params(default(int), default(int), default(int));
|
||||
Params(new int[n]);
|
||||
}
|
||||
|
||||
public void GenericOverloads()
|
||||
{
|
||||
Generic(1);
|
||||
Generic<int>(1);
|
||||
}
|
||||
|
||||
public string AmbiguousDefaultArgumentStaysTyped()
|
||||
{
|
||||
return Ambiguous(default(Data));
|
||||
}
|
||||
|
||||
public string DefaultArgumentWithBetterConversionTarget()
|
||||
{
|
||||
return WithNullable(default);
|
||||
}
|
||||
|
||||
public bool EqualityWithDefaultStaysTyped(Data data)
|
||||
{
|
||||
return data == default(Data);
|
||||
}
|
||||
|
||||
private static void Integer(short s)
|
||||
{
|
||||
}
|
||||
|
||||
private static void Integer(int i)
|
||||
{
|
||||
}
|
||||
|
||||
private static void Integer(long l)
|
||||
{
|
||||
}
|
||||
|
||||
private static void RefType(object o)
|
||||
{
|
||||
}
|
||||
|
||||
private static void RefType(string s)
|
||||
{
|
||||
}
|
||||
|
||||
private static void NullableInt(int i)
|
||||
{
|
||||
}
|
||||
|
||||
private static void NullableInt(int? i)
|
||||
{
|
||||
}
|
||||
|
||||
private static void Params(int i)
|
||||
{
|
||||
}
|
||||
|
||||
private static void Params(params int[] xs)
|
||||
{
|
||||
}
|
||||
|
||||
private static void Generic(int i)
|
||||
{
|
||||
}
|
||||
|
||||
private static void Generic<T>(T a)
|
||||
{
|
||||
}
|
||||
|
||||
private static string Ambiguous(Data x)
|
||||
{
|
||||
return "Data";
|
||||
}
|
||||
|
||||
private static string Ambiguous(OtherData x)
|
||||
{
|
||||
return "OtherData";
|
||||
}
|
||||
|
||||
private static string WithNullable(Data x)
|
||||
{
|
||||
return "Data";
|
||||
}
|
||||
|
||||
private static string WithNullable(Data? x)
|
||||
{
|
||||
return "Data?";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public unsafe static void AssignmentGuidPointerToDateTimePointerDefault(Guid* ptr)
|
||||
{
|
||||
#if CS71
|
||||
((DateTime*)ptr)[2] = default;
|
||||
#else
|
||||
((DateTime*)ptr)[2] = default(DateTime);
|
||||
#endif
|
||||
}
|
||||
|
||||
public unsafe static void AssignmentGuidPointerToDateTimePointer_2(Guid* ptr)
|
||||
@@ -66,7 +70,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public unsafe static void AssignmentGuidPointerToDateTimePointerDefault_2(Guid* ptr)
|
||||
{
|
||||
#if CS71
|
||||
*(DateTime*)(ptr + 2) = default;
|
||||
#else
|
||||
*(DateTime*)(ptr + 2) = default(DateTime);
|
||||
#endif
|
||||
}
|
||||
|
||||
public unsafe static DateTime AccessGuidPointerToDateTimePointer(Guid* ptr)
|
||||
|
||||
@@ -33,12 +33,20 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
{
|
||||
public static Maybe<TResult> Select<T, TResult>(this Maybe<T> a, Func<T, TResult> fn)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(Maybe<TResult>);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static Maybe<T> Where<T>(this Maybe<T> a, Func<T, bool> predicate)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(Maybe<T>);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,13 +56,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
{
|
||||
public Maybe<int> Value;
|
||||
|
||||
#if CS60
|
||||
#if CS71
|
||||
public Maybe<int> this[int index] => default;
|
||||
#elif CS60
|
||||
public Maybe<int> this[int index] => default(Maybe<int>);
|
||||
#endif
|
||||
|
||||
public Func<Maybe<int>> Factory()
|
||||
{
|
||||
#if CS71
|
||||
return () => default;
|
||||
#else
|
||||
return () => default(Maybe<int>);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,12 +66,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public Span<int> ScopedSpan(scoped Span<int> span)
|
||||
{
|
||||
return default(Span<int>);
|
||||
return default;
|
||||
}
|
||||
|
||||
public void OutSpan(out Span<int> span)
|
||||
{
|
||||
span = default(Span<int>);
|
||||
span = default;
|
||||
}
|
||||
|
||||
public void CaptureIntoRef(ref Holder holder, Span<int> inner)
|
||||
@@ -81,13 +81,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public void CaptureIntoOut(out Holder holder, Span<int> inner)
|
||||
{
|
||||
holder = default(Holder);
|
||||
holder = default;
|
||||
holder.Inner = inner;
|
||||
}
|
||||
|
||||
public void CaptureRefIntoOut(out Holder holder, ref int value)
|
||||
{
|
||||
holder = default(Holder);
|
||||
holder = default;
|
||||
holder.Inner = new Span<int>(ref value);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
public Span<int> NoCaptureOut(out int value)
|
||||
{
|
||||
value = 0;
|
||||
return default(Span<int>);
|
||||
return default;
|
||||
}
|
||||
|
||||
public Span<int> Identity(Span<int> span)
|
||||
@@ -137,7 +137,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
public int ReassignScopedSpanFromOut(bool b)
|
||||
{
|
||||
int value = 0;
|
||||
scoped Span<int> span = default(Span<int>);
|
||||
scoped Span<int> span = default;
|
||||
if (b)
|
||||
{
|
||||
span = CaptureOut(out value);
|
||||
@@ -147,7 +147,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public int ImplicitScopedOutDoesNotCapture()
|
||||
{
|
||||
Span<int> span = default(Span<int>);
|
||||
Span<int> span = default;
|
||||
span = NoCaptureOut(out var value);
|
||||
Console.WriteLine(span.Length);
|
||||
return span.Length + value;
|
||||
@@ -155,8 +155,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public int ReassignScopedSpanFromReceiver(bool b)
|
||||
{
|
||||
UnscopedRefStruct unscopedRefStruct = default(UnscopedRefStruct);
|
||||
scoped Span<int> span = default(Span<int>);
|
||||
UnscopedRefStruct unscopedRefStruct = default;
|
||||
scoped Span<int> span = default;
|
||||
if (b)
|
||||
{
|
||||
span = unscopedRefStruct.AsSpan();
|
||||
@@ -166,7 +166,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public int ReassignScopedSpanFromRefParameter(bool b, ref int value)
|
||||
{
|
||||
scoped Span<int> span = default(Span<int>);
|
||||
scoped Span<int> span = default;
|
||||
if (b)
|
||||
{
|
||||
span = CreateAndCapture(ref value);
|
||||
@@ -176,7 +176,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public int ReassignScopedSpanFromStackAlloc(bool b)
|
||||
{
|
||||
scoped Span<int> span = default(Span<int>);
|
||||
scoped Span<int> span = default;
|
||||
if (b)
|
||||
{
|
||||
span = stackalloc int[1];
|
||||
@@ -186,7 +186,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public int ReassignScopedSpanFromScopedValue(bool b, scoped Span<int> value)
|
||||
{
|
||||
scoped Span<int> span = default(Span<int>);
|
||||
scoped Span<int> span = default;
|
||||
if (b)
|
||||
{
|
||||
span = value;
|
||||
@@ -197,7 +197,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
public int ReassignScopedSpanFromNestedCall(bool b)
|
||||
{
|
||||
int value = 0;
|
||||
scoped Span<int> span = default(Span<int>);
|
||||
scoped Span<int> span = default;
|
||||
if (b)
|
||||
{
|
||||
span = Identity(CreateAndCapture(ref value));
|
||||
@@ -208,7 +208,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
public int ReassignScopedSpanFromLocalCopy(bool b)
|
||||
{
|
||||
Span<int> span = stackalloc int[1];
|
||||
scoped Span<int> span2 = default(Span<int>);
|
||||
scoped Span<int> span2 = default;
|
||||
if (b)
|
||||
{
|
||||
span2 = span;
|
||||
@@ -219,7 +219,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
public int ReassignScopedSpanFromScopedRefValue(bool b)
|
||||
{
|
||||
Span<int> span = stackalloc int[1];
|
||||
scoped Span<int> span2 = default(Span<int>);
|
||||
scoped Span<int> span2 = default;
|
||||
if (b)
|
||||
{
|
||||
span2 = ScopedRefSpan(ref span);
|
||||
@@ -252,7 +252,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public int ClassParameterReceiverDoesNotNarrow(SpanProvider provider, bool b)
|
||||
{
|
||||
Span<int> span = default(Span<int>);
|
||||
Span<int> span = default;
|
||||
if (b)
|
||||
{
|
||||
span = provider.GetBuffer();
|
||||
@@ -263,7 +263,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
public int ClassLocalReceiverDoesNotNarrow(bool b)
|
||||
{
|
||||
SpanProvider spanProvider = new SpanProvider();
|
||||
Span<int> span = default(Span<int>);
|
||||
Span<int> span = default;
|
||||
if (b)
|
||||
{
|
||||
span = spanProvider.GetBuffer();
|
||||
@@ -283,7 +283,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public int FieldStoreRequiresScoped()
|
||||
{
|
||||
scoped Holder holder = default(Holder);
|
||||
scoped Holder holder = default;
|
||||
Span<int> inner = stackalloc int[4];
|
||||
holder.Inner = inner;
|
||||
return holder.Inner.Length;
|
||||
@@ -291,7 +291,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public int ReceiverCallRequiresScoped()
|
||||
{
|
||||
scoped Holder holder = default(Holder);
|
||||
scoped Holder holder = default;
|
||||
Span<int> inner = stackalloc int[4];
|
||||
holder.Set(inner);
|
||||
return holder.Inner.Length;
|
||||
@@ -299,7 +299,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public int ExtensionReceiverCallRequiresScoped()
|
||||
{
|
||||
scoped Holder holder = default(Holder);
|
||||
scoped Holder holder = default;
|
||||
Span<int> inner = stackalloc int[4];
|
||||
holder.SetExtension(inner);
|
||||
return holder.Inner.Length;
|
||||
@@ -307,7 +307,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public int RefArgumentCallRequiresScoped()
|
||||
{
|
||||
scoped Holder holder = default(Holder);
|
||||
scoped Holder holder = default;
|
||||
Span<int> inner = stackalloc int[4];
|
||||
CaptureIntoRef(ref holder, inner);
|
||||
return holder.Inner.Length;
|
||||
@@ -315,7 +315,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public int OutArgumentCallRequiresScoped()
|
||||
{
|
||||
scoped Holder holder = default(Holder);
|
||||
scoped Holder holder = default;
|
||||
Span<int> inner = stackalloc int[4];
|
||||
CaptureIntoOut(out holder, inner);
|
||||
return holder.Inner.Length;
|
||||
@@ -324,28 +324,28 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
public int OutArgumentCapturesRefRequiresScoped()
|
||||
{
|
||||
int value = 0;
|
||||
scoped Holder holder = default(Holder);
|
||||
scoped Holder holder = default;
|
||||
CaptureRefIntoOut(out holder, ref value);
|
||||
return holder.Inner[0];
|
||||
}
|
||||
|
||||
public Holder RefArgumentWideValueDoesNotRequireScoped(Span<int> wide)
|
||||
{
|
||||
Holder holder = default(Holder);
|
||||
Holder holder = default;
|
||||
CaptureIntoRef(ref holder, wide);
|
||||
return holder;
|
||||
}
|
||||
|
||||
public Holder OutArgumentWideValueDoesNotRequireScoped(Span<int> wide)
|
||||
{
|
||||
Holder holder = default(Holder);
|
||||
Holder holder = default;
|
||||
CaptureIntoOut(out holder, wide);
|
||||
return holder;
|
||||
}
|
||||
|
||||
public int RefReturnFieldStoreRequiresScoped()
|
||||
{
|
||||
scoped Holder holder = default(Holder);
|
||||
scoped Holder holder = default;
|
||||
Span<int> inner = stackalloc int[4];
|
||||
Identity(ref holder).Inner = inner;
|
||||
return holder.Inner.Length;
|
||||
@@ -353,14 +353,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public Holder RefReturnFieldStoreWideValueDoesNotRequireScoped(Span<int> wide)
|
||||
{
|
||||
Holder holder = default(Holder);
|
||||
Holder holder = default;
|
||||
Identity(ref holder).Inner = wide;
|
||||
return holder;
|
||||
}
|
||||
|
||||
public Holder ReadonlyReceiverDoesNotRequireScoped(bool b)
|
||||
{
|
||||
Holder result = default(Holder);
|
||||
Holder result = default;
|
||||
if (b)
|
||||
{
|
||||
Span<int> inner = stackalloc int[4];
|
||||
@@ -371,7 +371,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public Holder ReadonlyExtensionReceiverDoesNotRequireScoped(bool b)
|
||||
{
|
||||
Holder holder = default(Holder);
|
||||
Holder holder = default;
|
||||
if (b)
|
||||
{
|
||||
Span<int> inner = stackalloc int[4];
|
||||
@@ -466,7 +466,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
{
|
||||
public Span<int> GetBuffer()
|
||||
{
|
||||
return default(Span<int>);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static SpanFactory Create(int size)
|
||||
{
|
||||
return default(SpanFactory);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static T CreateDefault<T>() where T : allows ref struct
|
||||
{
|
||||
return default(T);
|
||||
return default;
|
||||
}
|
||||
|
||||
public static void CombinedUnmanaged<T>() where T : unmanaged, allows ref struct
|
||||
@@ -204,7 +204,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void InvokeDelegate(RefStructAction<Span<int>> action)
|
||||
{
|
||||
action(default(Span<int>));
|
||||
action(default);
|
||||
}
|
||||
|
||||
public static void LocalFunctionAllows()
|
||||
@@ -217,7 +217,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static void CapturingLocalFunction<T>(int seed) where T : allows ref struct
|
||||
{
|
||||
Nested(default(T));
|
||||
Nested(default);
|
||||
Console.WriteLine(seed);
|
||||
void Nested(scoped T value)
|
||||
{
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.StaticAbstractInterfaceM
|
||||
}
|
||||
static virtual implicit operator T(string s)
|
||||
{
|
||||
return default(T);
|
||||
return default;
|
||||
}
|
||||
static virtual explicit operator string(T t)
|
||||
{
|
||||
|
||||
@@ -150,7 +150,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static TReturn Get<TReturn>()
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TReturn);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
#if CS100
|
||||
public StructWithDefaultCtor M()
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(StructWithDefaultCtor);
|
||||
#endif
|
||||
}
|
||||
|
||||
public StructWithDefaultCtor M2()
|
||||
|
||||
@@ -0,0 +1,227 @@
|
||||
// Copyright (c) 2026 Siegfried Pammer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading;
|
||||
|
||||
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
{
|
||||
public class TargetTypedDefault
|
||||
{
|
||||
public struct ValueHolder
|
||||
{
|
||||
public int Value;
|
||||
}
|
||||
|
||||
public enum Flavor
|
||||
{
|
||||
None,
|
||||
Sweet
|
||||
}
|
||||
|
||||
#if !OPT
|
||||
public Guid guidField = default;
|
||||
#else
|
||||
public Guid guidField;
|
||||
#endif
|
||||
|
||||
public void OptGuid(Guid guid = default(Guid))
|
||||
{
|
||||
}
|
||||
|
||||
public void OptCancellationToken(CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
}
|
||||
|
||||
public void OptTimeSpan(TimeSpan timeSpan = default(TimeSpan))
|
||||
{
|
||||
}
|
||||
|
||||
public void OptDateTime(DateTime dateTime = default(DateTime))
|
||||
{
|
||||
}
|
||||
|
||||
public void OptCustomStruct(ValueHolder holder = default(ValueHolder))
|
||||
{
|
||||
}
|
||||
|
||||
public void OptDecimal(decimal d = 0m)
|
||||
{
|
||||
}
|
||||
|
||||
public void OptNullable(int? x = null)
|
||||
{
|
||||
}
|
||||
|
||||
public void OptEnum(Flavor flavor = Flavor.None)
|
||||
{
|
||||
}
|
||||
|
||||
public void OptString(string s = null)
|
||||
{
|
||||
}
|
||||
|
||||
public void OptInt(int i = 0)
|
||||
{
|
||||
}
|
||||
|
||||
public void OptGeneric<T>(T value = default(T))
|
||||
{
|
||||
}
|
||||
|
||||
public void OptGenericStruct<T>(T value = default(T)) where T : struct
|
||||
{
|
||||
}
|
||||
|
||||
public void OptTuple((int, string) pair = default((int, string)))
|
||||
{
|
||||
}
|
||||
|
||||
public void CallsWithExplicitDefaults()
|
||||
{
|
||||
OptGuid();
|
||||
OptCancellationToken();
|
||||
OptTimeSpan();
|
||||
OptCustomStruct();
|
||||
OptNullable();
|
||||
OptString();
|
||||
OptGeneric<Guid>();
|
||||
OptTuple();
|
||||
}
|
||||
|
||||
public void TakeGuid(Guid guid)
|
||||
{
|
||||
}
|
||||
|
||||
public void TakeInGuid(in Guid guid)
|
||||
{
|
||||
}
|
||||
|
||||
public void Over(int x)
|
||||
{
|
||||
}
|
||||
|
||||
public void Over(string s)
|
||||
{
|
||||
}
|
||||
|
||||
public void OverStruct(Guid guid)
|
||||
{
|
||||
}
|
||||
|
||||
public void OverStruct(TimeSpan timeSpan)
|
||||
{
|
||||
}
|
||||
|
||||
public void CallOverloads()
|
||||
{
|
||||
Over(0);
|
||||
Over(null);
|
||||
OverStruct(default(Guid));
|
||||
OverStruct(default(TimeSpan));
|
||||
}
|
||||
|
||||
public void ArgumentPositions(bool b, Guid guid)
|
||||
{
|
||||
TakeGuid(default);
|
||||
TakeInGuid(default(Guid));
|
||||
TakeGuid(b ? guid : default(Guid));
|
||||
}
|
||||
|
||||
public T GenericReturn<T>()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public T GenericClassReturn<T>() where T : class
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public T GenericNewReturn<T>() where T : new()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueHolder StructReturn()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public (int, string) TupleReturn()
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public int? NullableReturn()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void OutDefault(out Guid guid)
|
||||
{
|
||||
guid = default;
|
||||
}
|
||||
|
||||
public bool GuidIsDefault(Guid guid)
|
||||
{
|
||||
return guid == default(Guid);
|
||||
}
|
||||
|
||||
public bool TimeSpanIsDefault(TimeSpan timeSpan)
|
||||
{
|
||||
return timeSpan == default(TimeSpan);
|
||||
}
|
||||
|
||||
public bool IntIsDefault(int i)
|
||||
{
|
||||
return i == 0;
|
||||
}
|
||||
|
||||
public bool NullableIsDefault(int? x)
|
||||
{
|
||||
return !x.HasValue;
|
||||
}
|
||||
|
||||
public string CoalesceDefault(string s)
|
||||
{
|
||||
return s ?? null;
|
||||
}
|
||||
|
||||
public T[] DefaultInitializedArray<T>()
|
||||
{
|
||||
return new T[3];
|
||||
}
|
||||
|
||||
public unsafe int* PointerDefault()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Expression<Func<Guid>> GuidExpressionTree()
|
||||
{
|
||||
return () => default;
|
||||
}
|
||||
|
||||
public Expression<Func<int>> ZeroExpressionTree()
|
||||
{
|
||||
return () => 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -547,7 +547,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
private unsafe void Issue990()
|
||||
{
|
||||
#if CS71
|
||||
Data data = default;
|
||||
#else
|
||||
Data data = default(Data);
|
||||
#endif
|
||||
Data* ptr = &data;
|
||||
ConvertIntToFloat(ptr->Position.GetHashCode());
|
||||
}
|
||||
@@ -562,7 +566,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
private static T Get<T>()
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(T);
|
||||
#endif
|
||||
}
|
||||
|
||||
private unsafe static ResultStruct NestedFixedBlocks(byte[] array)
|
||||
|
||||
@@ -36,7 +36,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static implicit operator C(bool b)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(C);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,12 +81,20 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static implicit operator C(bool b)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(C);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static implicit operator C(A a)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(C);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool operator ==(C a, C b)
|
||||
@@ -141,12 +153,20 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static implicit operator T(in int val)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(T);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static explicit operator T(in long val)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(T);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +176,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static implicit operator T(in U u)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(T);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static explicit operator int(in U u)
|
||||
|
||||
@@ -50,12 +50,20 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
#if !ROSLYN3
|
||||
public static implicit operator TypeB_Issue3385(TypeA_Issue3385 a)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TypeB_Issue3385);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
public static implicit operator TypeB_Issue3385(in TypeA_Issue3385 a)
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(TypeB_Issue3385);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -191,9 +199,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
public static void Issue3385()
|
||||
{
|
||||
#if ROSLYN3
|
||||
#if CS71
|
||||
using (TypeA_Issue3385 a = default)
|
||||
#else
|
||||
using (TypeA_Issue3385 a = default(TypeA_Issue3385))
|
||||
#endif
|
||||
#else
|
||||
#if CS71
|
||||
using (TypeA_Issue3385 typeA_Issue = default)
|
||||
#else
|
||||
using (TypeA_Issue3385 typeA_Issue = default(TypeA_Issue3385))
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
#if ROSLYN3
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
public void UsingVarPatternBasedDispose()
|
||||
{
|
||||
Console.WriteLine("before using");
|
||||
using RefStructWithDispose refStructWithDispose = default(RefStructWithDispose);
|
||||
using RefStructWithDispose refStructWithDispose = default;
|
||||
Console.WriteLine("inside using");
|
||||
refStructWithDispose.Use();
|
||||
}
|
||||
|
||||
@@ -134,7 +134,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
#if !(ROSLYN && OPT) || COPY_PROPAGATION_FIXED
|
||||
public static S InitObj1()
|
||||
{
|
||||
#if CS71
|
||||
S result = default;
|
||||
#else
|
||||
S result = default(S);
|
||||
#endif
|
||||
MakeArray();
|
||||
return result;
|
||||
}
|
||||
@@ -142,12 +146,20 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static S InitObj2()
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(S);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void InitObj3(out S p)
|
||||
{
|
||||
#if CS71
|
||||
p = default;
|
||||
#else
|
||||
p = default(S);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static S CallValueTypeCtor()
|
||||
@@ -252,7 +264,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
|
||||
|
||||
public static T Get<T>()
|
||||
{
|
||||
#if CS71
|
||||
return default;
|
||||
#else
|
||||
return default(T);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void CallOnTemporary()
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.VBPretty
|
||||
public async void AwaitDefaultYieldAwaitable()
|
||||
{
|
||||
#if LEGACY_VBC || (OPTIMIZE && !ROSLYN4)
|
||||
YieldAwaitable yieldAwaitable2 = default(YieldAwaitable);
|
||||
YieldAwaitable yieldAwaitable2 = default;
|
||||
YieldAwaitable yieldAwaitable = yieldAwaitable2;
|
||||
await yieldAwaitable;
|
||||
#else
|
||||
@@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.VBPretty
|
||||
public async void AwaitDefaultHopToThreadPool()
|
||||
{
|
||||
#if LEGACY_VBC || (OPTIMIZE && !ROSLYN4)
|
||||
HopToThreadPoolAwaitable hopToThreadPoolAwaitable2 = default(HopToThreadPoolAwaitable);
|
||||
HopToThreadPoolAwaitable hopToThreadPoolAwaitable2 = default;
|
||||
HopToThreadPoolAwaitable hopToThreadPoolAwaitable = hopToThreadPoolAwaitable2;
|
||||
await hopToThreadPoolAwaitable;
|
||||
#else
|
||||
|
||||
@@ -4,6 +4,6 @@ public class Issue1906
|
||||
{
|
||||
public void M()
|
||||
{
|
||||
Console.WriteLine(Math.Min(Math.Max(long.MinValue, default(long)), long.MaxValue));
|
||||
Console.WriteLine(Math.Min(Math.Max(long.MinValue, default), long.MaxValue));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1075,6 +1075,13 @@ namespace ICSharpCode.Decompiler.CSharp
|
||||
}
|
||||
|
||||
arg = arg.ConvertTo(parameterType, expressionBuilder, allowImplicitConversion: arg.Type.Kind != TypeKind.Dynamic);
|
||||
if (method.IsOperator)
|
||||
{
|
||||
// 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.
|
||||
arg = arg.RestoreDefaultLiteralType(expressionBuilder);
|
||||
}
|
||||
|
||||
if (parameter.ReferenceKind != ReferenceKind.None)
|
||||
{
|
||||
|
||||
@@ -890,11 +890,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
|
||||
StartNode(defaultValueExpression);
|
||||
|
||||
WriteKeyword(DefaultValueExpression.DefaultKeyword);
|
||||
LPar();
|
||||
Space(policy.SpacesWithinTypeOfParentheses);
|
||||
defaultValueExpression.Type.AcceptVisitor(this);
|
||||
Space(policy.SpacesWithinTypeOfParentheses);
|
||||
RPar();
|
||||
if (defaultValueExpression.Type is not null)
|
||||
{
|
||||
LPar();
|
||||
Space(policy.SpacesWithinTypeOfParentheses);
|
||||
defaultValueExpression.Type.AcceptVisitor(this);
|
||||
Space(policy.SpacesWithinTypeOfParentheses);
|
||||
RPar();
|
||||
}
|
||||
|
||||
EndNode(defaultValueExpression);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
|
||||
if (c != Conversion.None)
|
||||
return c;
|
||||
// C# 9.0 spec: §10.2.16 default literal conversions
|
||||
// TODO
|
||||
if (resolveResult is DefaultLiteralResolveResult)
|
||||
return Conversion.DefaultLiteralConversion;
|
||||
if (resolveResult.IsCompileTimeConstant)
|
||||
{
|
||||
c = StandardImplicitConversion(resolveResult.Type, toType, allowTuple);
|
||||
|
||||
@@ -596,6 +596,13 @@ namespace ICSharpCode.Decompiler.CSharp
|
||||
if (var.LoadCount > 0 || var.AddressCount > 0)
|
||||
{
|
||||
var type = settings.AnonymousTypes && var.Type.ContainsAnonymousType() ? new SimpleType("var") : exprBuilder.ConvertType(var.Type);
|
||||
if (resource is DefaultValueExpression)
|
||||
{
|
||||
// Unlike "using (expr)", the declaration spells out the type, so the
|
||||
// resource may use the default literal.
|
||||
resource = new TranslatedExpression(resource)
|
||||
.ConvertTo(var.Type, exprBuilder, allowImplicitConversion: true);
|
||||
}
|
||||
var vds = new VariableDeclarationStatement(type, var.Name!, resource);
|
||||
vds.Variables.Single().AddAnnotation(new ILVariableResolveResult(var, var.Type));
|
||||
usingInit = vds;
|
||||
|
||||
@@ -37,6 +37,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
|
||||
public const string DefaultKeyword = "default";
|
||||
|
||||
[Slot("Type")]
|
||||
public partial AstType Type { get; set; }
|
||||
public partial AstType? Type { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -708,7 +708,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
|
||||
AstType type = context.TypeSystemAstBuilder.ConvertType(v.Type);
|
||||
if (v.DefaultInitialization == VariableInitKind.NeedsDefaultValue)
|
||||
{
|
||||
initializer = new DefaultValueExpression(type.Clone());
|
||||
// The declaration always spells out the type, so the default literal is
|
||||
// equivalent to default(T).
|
||||
initializer = context.Settings.DefaultLiterals
|
||||
? new DefaultValueExpression()
|
||||
: new DefaultValueExpression(type.Clone());
|
||||
}
|
||||
var vds = new VariableDeclarationStatement(type, v.Name, initializer);
|
||||
if (context.Settings.ScopedRef && v.ILVariable.IsScopedWithoutInitializer)
|
||||
|
||||
@@ -168,6 +168,20 @@ namespace ICSharpCode.Decompiler.CSharp
|
||||
throw new ArgumentException("descendant must be a descendant of the current node");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Undoes the shortening to the C# 7.1 default literal that <see cref="ConvertTo"/>
|
||||
/// applies, restoring the original "default(T)". Use in contexts that supply no target
|
||||
/// type for the literal, e.g. an awaited expression or an argument of a call that later
|
||||
/// becomes a cast or an operator.
|
||||
/// </summary>
|
||||
public TranslatedExpression RestoreDefaultLiteralType(ExpressionBuilder expressionBuilder)
|
||||
{
|
||||
if (ResolveResult is not DefaultLiteralResolveResult literal)
|
||||
return this;
|
||||
return expressionBuilder.GetDefaultValueExpression(literal.ShortenedFrom)
|
||||
.WithILInstruction(this.ILInstructions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds casts (if necessary) to convert this expression to the specified target type.
|
||||
/// </summary>
|
||||
@@ -195,11 +209,37 @@ namespace ICSharpCode.Decompiler.CSharp
|
||||
public TranslatedExpression ConvertTo(IType targetType, ExpressionBuilder expressionBuilder, bool checkForOverflow = false, bool allowImplicitConversion = false)
|
||||
{
|
||||
var type = this.Type;
|
||||
if (ResolveResult is DefaultLiteralResolveResult literal)
|
||||
{
|
||||
if (allowImplicitConversion
|
||||
&& NormalizeTypeVisitor.IgnoreNullabilityAndTuples.EquivalentTypes(literal.ShortenedFrom, targetType))
|
||||
{
|
||||
// The context still supplies the type the literal was shortened from.
|
||||
return this;
|
||||
}
|
||||
// Either an explicit type is required here (e.g. overload resolution needs the
|
||||
// typed form to stay unambiguous), or the context supplies a different type, in
|
||||
// which case the literal would produce a different value (e.g. null instead of
|
||||
// a boxed struct).
|
||||
return RestoreDefaultLiteralType(expressionBuilder)
|
||||
.ConvertTo(targetType, expressionBuilder, checkForOverflow, allowImplicitConversion);
|
||||
}
|
||||
if (NormalizeTypeVisitor.IgnoreNullabilityAndTuples.EquivalentTypes(type, targetType))
|
||||
{
|
||||
// Make explicit conversion implicit, if possible
|
||||
if (allowImplicitConversion)
|
||||
{
|
||||
if (Expression is DefaultValueExpression { Type: not null }
|
||||
&& 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();
|
||||
}
|
||||
switch (ResolveResult)
|
||||
{
|
||||
case ConversionResolveResult conversion:
|
||||
|
||||
@@ -633,6 +633,14 @@ namespace ICSharpCode.Decompiler
|
||||
[DecompilerSetting(CSharp.LanguageVersion.CSharp7)]
|
||||
public partial bool ThrowExpressions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets whether the C# 7.1 default literal <c>default</c> should be used instead of
|
||||
/// <c>default(T)</c>, wherever the surrounding syntax already supplies the type.
|
||||
/// </summary>
|
||||
[Description("DecompilerSettings.UseDefaultLiterals")]
|
||||
[DecompilerSetting(CSharp.LanguageVersion.CSharp7_1)]
|
||||
public partial bool DefaultLiterals { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets whether implicit conversions between tuples
|
||||
/// should be used in the decompiled output.
|
||||
|
||||
@@ -104,6 +104,11 @@ namespace ICSharpCode.Decompiler.Semantics
|
||||
/// </summary>
|
||||
public static readonly Conversion ExplicitSpanConversion = new BuiltinConversion(false, 14);
|
||||
|
||||
/// <summary>
|
||||
/// C# 7.1 default literal being converted to an arbitrary type.
|
||||
/// </summary>
|
||||
public static readonly Conversion DefaultLiteralConversion = new BuiltinConversion(true, 15);
|
||||
|
||||
public static Conversion UserDefinedConversion(IMethod operatorMethod, bool isImplicit, Conversion conversionBeforeUserDefinedOperator, Conversion conversionAfterUserDefinedOperator, bool isLifted = false, bool isAmbiguous = false)
|
||||
{
|
||||
if (operatorMethod == null)
|
||||
@@ -265,6 +270,7 @@ namespace ICSharpCode.Decompiler.Semantics
|
||||
public override bool IsInlineArrayConversion => type == 12;
|
||||
public override bool IsImplicitSpanConversion => type == 13;
|
||||
public override bool IsExplicitSpanConversion => type == 14;
|
||||
public override bool IsDefaultLiteralConversion => type == 15;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
@@ -306,6 +312,8 @@ namespace ICSharpCode.Decompiler.Semantics
|
||||
return "implicit span conversion";
|
||||
case 14:
|
||||
return "explicit span conversion";
|
||||
case 15:
|
||||
return "default-literal conversion";
|
||||
}
|
||||
return (isImplicit ? "implicit " : "explicit ") + name + " conversion";
|
||||
}
|
||||
@@ -499,6 +507,10 @@ namespace ICSharpCode.Decompiler.Semantics
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public virtual bool IsDefaultLiteralConversion {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public virtual bool IsIdentityConversion {
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2026 Siegfried Pammer
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
// software and associated documentation files (the "Software"), to deal in the Software
|
||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or
|
||||
// substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
using ICSharpCode.Decompiler.TypeSystem;
|
||||
|
||||
namespace ICSharpCode.Decompiler.Semantics
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a typeless default literal `default`, which is implicitly convertible
|
||||
/// to any type (C# standard 10.2.16 default literal conversions).
|
||||
/// </summary>
|
||||
class DefaultLiteralResolveResult : ResolveResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of the "default(T)" expression the literal was shortened from; it is restored
|
||||
/// wherever the surrounding syntax stops supplying that very type.
|
||||
/// <see cref="SpecialType.UnknownType"/> if the literal does not stand for a shortened
|
||||
/// expression.
|
||||
/// </summary>
|
||||
public readonly IType ShortenedFrom;
|
||||
|
||||
public DefaultLiteralResolveResult() : this(SpecialType.UnknownType)
|
||||
{
|
||||
}
|
||||
|
||||
public DefaultLiteralResolveResult(IType shortenedFrom) : base(SpecialType.NoType)
|
||||
{
|
||||
this.ShortenedFrom = shortenedFrom;
|
||||
}
|
||||
|
||||
// A default_value_expression is a constant expression (C# standard 12.8.21);
|
||||
// like the null literal, the typeless default literal is modeled as a constant
|
||||
// with value null (the target-typed value is only known after conversion).
|
||||
public override bool IsCompileTimeConstant {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override object ConstantValue {
|
||||
get { return null; }
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+9
@@ -1640,6 +1640,15 @@ namespace ICSharpCode.ILSpy.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use "default" literals without an explicit type.
|
||||
/// </summary>
|
||||
public static string DecompilerSettings_UseDefaultLiterals {
|
||||
get {
|
||||
return ResourceManager.GetString("DecompilerSettings.UseDefaultLiterals", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Use discards.
|
||||
/// </summary>
|
||||
|
||||
@@ -579,6 +579,9 @@ Are you sure you want to continue?</value>
|
||||
<data name="DecompilerSettings.UnsignedRightShift" xml:space="preserve">
|
||||
<value>Unsigned right shift (>>>)</value>
|
||||
</data>
|
||||
<data name="DecompilerSettings.UseDefaultLiterals" xml:space="preserve">
|
||||
<value>Use "default" literals without an explicit type</value>
|
||||
</data>
|
||||
<data name="DecompilerSettings.UseDiscards" xml:space="preserve">
|
||||
<value>Use discards</value>
|
||||
</data>
|
||||
|
||||
Reference in New Issue
Block a user