Skip to content

It looks like runtime verifies variance safety for static members in interfaces and throws System.TypeLoadException #39612

@AlekseyTs

Description

@AlekseyTs

Below is IL equivalent to the following C# code:

class Program
{
    static void Main()
    {
        System.Console.WriteLine(I2<string, string>.M1("a"));
        System.Console.WriteLine(I2<string, string>.M2("b"));
    }
}

interface I2<out T1, in T2>
{
    static T1 M1(T1 x) => x;
    static T2 M2(T2 x) => x;
}

The IL:

//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.8.3928.0
//  Copyright (c) Microsoft Corporation.  All rights reserved.



// Metadata version: v4.0.30319
.assembly extern System.Runtime
{
  .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )                         // .?_....:
  .ver 4:2:2:0
}
.assembly extern System.Console
{
  .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )                         // .?_....:
  .ver 4:1:2:0
}
.assembly ConsoleApp5
{
  .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
  .custom instance void [System.Runtime]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                                   63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.

  // --- The following custom attribute is added automatically, do not uncomment -------
  //  .custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 

  .custom instance void [System.Runtime]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 18 2E 4E 45 54 43 6F 72 65 41 70 70 2C 56   // ....NETCoreApp,V
                                                                                                              65 72 73 69 6F 6E 3D 76 33 2E 31 01 00 54 0E 14   // ersion=v3.1..T..
                                                                                                              46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C 61 79   // FrameworkDisplay
                                                                                                              4E 61 6D 65 00 )                                  // Name.
  .custom instance void [System.Runtime]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 0B 43 6F 6E 73 6F 6C 65 41 70 70 35 00 00 ) // ...ConsoleApp5..
  .custom instance void [System.Runtime]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 05 44 65 62 75 67 00 00 )                   // ...Debug..
  .custom instance void [System.Runtime]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 )             // ...1.0.0.0..
  .custom instance void [System.Runtime]System.Reflection.AssemblyInformationalVersionAttribute::.ctor(string) = ( 01 00 05 31 2E 30 2E 30 00 00 )                   // ...1.0.0..
  .custom instance void [System.Runtime]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 0B 43 6F 6E 73 6F 6C 65 41 70 70 35 00 00 ) // ...ConsoleApp5..
  .custom instance void [System.Runtime]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0B 43 6F 6E 73 6F 6C 65 41 70 70 35 00 00 ) // ...ConsoleApp5..
  .hash algorithm 0x00008004
  .ver 1:0:0:0
}
.module ConsoleApp5.dll
// MVID: {580B623A-FB1A-403C-8F9C-8DB0E42D429C}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x047E0000


// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi beforefieldinit Program
       extends [System.Runtime]System.Object
{
  .method private hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       34 (0x22)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      "a"
    IL_0006:  call       !0 class I2`2<string,string>::M1(!0)
    IL_000b:  call       void [System.Console]System.Console::WriteLine(string)
    IL_0010:  nop
    IL_0011:  ldstr      "b"
    IL_0016:  call       !1 class I2`2<string,string>::M2(!1)
    IL_001b:  call       void [System.Console]System.Console::WriteLine(string)
    IL_0020:  nop
    IL_0021:  ret
  } // end of method Program::Main

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [System.Runtime]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method Program::.ctor

} // end of class Program

.class interface private abstract auto ansi I2`2<+ T1,- T2>
{
  .method public hidebysig static !T1  M1(!T1 x) cil managed
  {
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  ret
  } // end of method I2`2::M1

  .method public hidebysig static !T2  M2(!T2 x) cil managed
  {
    // Code size       2 (0x2)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  ret
  } // end of method I2`2::M2

} // end of class I2`2


// =============================================================

// *********** DISASSEMBLY COMPLETE ***********************

An attempt to run it produces the following output:

Unhandled exception. System.TypeLoadException: Could not load type 'I2`2' from assembly 'ConsoleApp5, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
because a covariant or contravariant type parameter was used illegally in the signature for an argument in method 'M1'.
   at Program.Main()

Expected output:

a
b

This is blocking implementation of the following C# feature: https://github.com/dotnet/csharplang/blob/master/proposals/variance-safety-for-static-interface-members.md

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions