dotnet / dotnet/runtime

IL2080 from deconstruction assignment "using" ValueTuple

Open
#133,911 4 comments 1 reaction 2 assignees Claimed by @jtschuster View on GitHub
area-System.Reflection
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Description

This is similar to #123767, *except* that the *assignment* is fully defined, as opposed to coming from a method parameter:

```csharp
var (methodName, declType) = condition ? ("x", typeof(A)) : ("y", typeof(B));
var method = declType.GetMethod(methodName);
```

### Reproduction Steps

Consider the following project: [net11-il2080-valuetuple.zip](https://github.com/user-attachments/files/32208432/net11-il2080-valuetuple.zip)

Or create with:

```sh
dotnet new classlib -n net11-il2080-valuetuple
cd net11-il2080-valuetuple
cat <<'EOF' | git apply
diff --git a/Class1.cs b/Class1.cs
index 550b959..e637880 100644
--- a/Class1.cs
+++ b/Class1.cs
@@ -1,6 +1,37 @@
-namespace net11_il2080_valuetuple;
+using System.Reflection;
+
+namespace net11_il2080_valuetuple;

public class Class1
{
+ public void M()
+ {
+ int _icuVersion = 42;
+#if !NO_DESTRUCTURE
+ (var methodName, var type) = MyOS.IsBrowser()
+ ? ($"uno_{typeof(T).Name}", typeof(BrowserICUSymbols))
+ : ($"{typeof(T).Name}_{_icuVersion}", typeof(IOSICUSymbols));
+#else
+ var type = MyOS.IsBrowser()
+ ? typeof(BrowserICUSymbols)
+ : typeof(IOSICUSymbols);
+ var methodName = MyOS.IsBrowser()
+ ? $"uno_{typeof(T).Name}"
+ : $"{typeof(T).Name}_{_icuVersion}";
+#endif
+ var method = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static);
+ }
+}
+
+static class MyOS
+{
+ public static bool IsBrowser() => false;
+}

+static class BrowserICUSymbols
+{
+}
+
+static class IOSICUSymbols
+{
}
diff --git a/net11-il2080-valuetuple.csproj b/net11-il2080-valuetuple.csproj
index dabad04..40692be 100644
--- a/net11-il2080-valuetuple.csproj
+++ b/net11-il2080-valuetuple.csproj
@@ -1,10 +1,12 @@



- net10.0
+ net11.0
net11_il2080_valuetuple
enable
enable
+ true
+ $(DefineConstants);NO_DESTRUCTURE



EOF
```

Build the project:

```dotnetcli
dotnet build
```

### Expected behavior

No warning? No warning was emitted in .NET 10. (Which may not matter, as #123767 was not fixed in .NET 10 , but *is* fixed in .NET 11 rc.1…)

### Actual behavior

An IL2080 warning is generated:

> Class1.cs(22,22): warning IL2080: 'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.NonPublicMethods' in call to 'System.Type.GetMethod(String, BindingFlags)'. The field '(System.String, System.Type).Item2' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.

This warning is new in .NET 11 rc.1.

### Regression?

"Yes", in that previously warning-free code now emits warnings, which become errors, due to the joy that is `$(TreatWarningsAsErrors)`=true.

### Known Workarounds

"Deconstruct" the deconstruction assignment, i.e. "don't do that."

The offending code is this statement:

```csharp
(var methodName, var type) = MyOS.IsBrowser()
? ($"uno_{typeof(T).Name}", typeof(BrowserICUSymbols))
: ($"{typeof(T).Name}_{_icuVersion}", typeof(IOSICUSymbols));
var method = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static);
```

If you build the project with `-p:NoDestructure=1`, then *no* IL2080 warning is generated, as this alternate codepath is used:

```csharp
var type = MyOS.IsBrowser()
? typeof(BrowserICUSymbols)
: typeof(IOSICUSymbols);
var methodName = MyOS.IsBrowser()
? $"uno_{typeof(T).Name}"
: $"{typeof(T).Name}_{_icuVersion}";
var method = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static);
```

The runtime conditional is still present, we just remove the use of `ValueTuple`.

### Configuration

* .NET 11 rc.1. (Did *not* happen in .NET 11 Preview 7.)
* macOS 26, though I doubt the host OS matters.
* arm64, though I doubt the host OS matters.

### Other information

When writing this up I had *thought* that use of `ValueTuple<…>` along with deconstruction assignment was "the problem."

…until I ran `ildasm` on the warning-emitting binary, and saw *no use* of `ValueTuple<…>`! I thus lack an explanation for why the originating "deconstruction assignment" usage is problematic. (If`ValueTuple<…>` *had* been present, then it would make sense that `var _t = new ValueTuple("m", typeof(T)); var method = _t.Item2.GetMethod(_t.Item1)` could be problematic, but when `ValueTuple<…>` isn't even in the IL stream…)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.