From dc3ed43dd8d84091004947a5f1bb5f46ce0539e2 Mon Sep 17 00:00:00 2001
From: ds5678 <49847914+ds5678@users.noreply.github.com>
Date: Sun, 5 Oct 2025 00:25:47 -0700
Subject: [PATCH] Do not create object initializers for tuples
---
.../ICSharpCode.Decompiler.Tests.csproj | 1 +
.../PrettyTestRunner.cs | 6 +++
.../TestCases/Pretty/Issue3576.cs | 39 +++++++++++++++++++
...ransformCollectionAndObjectInitializers.cs | 3 ++
4 files changed, 49 insertions(+)
create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3576.cs
diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
index ae0949d9d..de9ba4ba4 100644
--- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -158,6 +158,7 @@
+
diff --git a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
index 81cca7639..089c7d764 100644
--- a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
@@ -696,6 +696,12 @@ namespace ICSharpCode.Decompiler.Tests
await RunForLibrary(cscOptions: cscOptions);
}
+ [Test]
+ public async Task Issue3576([ValueSource(nameof(roslyn2OrNewerWithNet40Options))] CompilerOptions cscOptions)
+ {
+ await RunForLibrary(cscOptions: cscOptions);
+ }
+
[Test]
public async Task AssemblyCustomAttributes([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
{
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3576.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3576.cs
new file mode 100644
index 000000000..bd81126fe
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3576.cs
@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+
+namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
+{
+ internal static class Issue3576
+ {
+ public static Issue3576_Camera GetOrCreate(long key, int frameCount, Dictionary cache)
+ {
+ if (!cache.TryGetValue(key, out var value))
+ {
+ Issue3576_GameObject issue3576_GameObject = new Issue3576_GameObject();
+ value = (issue3576_GameObject.AddComponent(), frameCount);
+ value.Item1.Property = 1;
+ issue3576_GameObject.SetActive(value: false);
+ cache[key] = value;
+ }
+ else
+ {
+ value.Item2 = frameCount;
+ cache[key] = value;
+ }
+ return value.Item1;
+ }
+ }
+ internal sealed class Issue3576_Camera
+ {
+ public int Property { get; set; }
+ }
+ internal sealed class Issue3576_GameObject
+ {
+ public T AddComponent()
+ {
+ throw null;
+ }
+ public void SetActive(bool value)
+ {
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs
index 5fd87451d..b3d90d935 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs
@@ -69,6 +69,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// anon = new { A = 5 } { 3,4,5 } is invalid syntax.
if (newObjInst.Method.DeclaringType.ContainsAnonymousType())
return;
+ // Tuples cannot have initializers
+ if (TupleTransform.MatchTupleConstruction(newObjInst, out _))
+ return;
instType = newObjInst.Method.DeclaringType;
break;
case DefaultValue defaultVal: