Fix generic dictionary lookups for param types and function pointers (#85369)
authorJan Kotas <jkotas@microsoft.com>
Wed, 26 Apr 2023 19:51:27 +0000 (12:51 -0700)
committerGitHub <noreply@github.com>
Wed, 26 Apr 2023 19:51:27 +0000 (12:51 -0700)
* Fix generic dictionary lookups for param types and function pointers

Fixes #85240

* AllowUnsafeBlocks

* Disable test on Mono

src/coreclr/vm/typedesc.cpp
src/coreclr/vm/typedesc.h
src/coreclr/vm/typehandle.cpp
src/tests/Regressions/coreclr/GitHub_85240/test85240.cs [new file with mode: 0644]
src/tests/Regressions/coreclr/GitHub_85240/test85240.csproj [new file with mode: 0644]
src/tests/issues.targets

index db045069c2691fcb16e01eb5cabd65770d084ca3..0650f58475a9be7473af22d49cc1c377fb635146 100644 (file)
@@ -87,6 +87,23 @@ PTR_Module TypeDesc::GetLoaderModule()
     }
 }
 
+BOOL TypeDesc::IsSharedByGenericInstantiations()
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    if (HasTypeParam())
+    {
+        return GetRootTypeParam().IsCanonicalSubtype();
+    }
+
+    if (IsFnPtr())
+    {
+        return dac_cast<PTR_FnPtrTypeDesc>(this)->IsSharedByGenericInstantiations();
+    }
+
+    return FALSE;
+}
+
 PTR_BaseDomain TypeDesc::GetDomain()
 {
     CONTRACTL
@@ -1634,18 +1651,26 @@ OBJECTREF TypeVarTypeDesc::GetManagedClassObject()
 TypeHandle *
 FnPtrTypeDesc::GetRetAndArgTypes()
 {
-    CONTRACTL
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-    }
-    CONTRACTL_END;
-
+    LIMITED_METHOD_CONTRACT;
 
     return m_RetAndArgTypes;
 } // FnPtrTypeDesc::GetRetAndArgTypes
 
+BOOL
+FnPtrTypeDesc::IsSharedByGenericInstantiations()
+{
+    LIMITED_METHOD_DAC_CONTRACT;
+
+    for (DWORD i = 0; i <= m_NumArgs; i++)
+    {
+        if (m_RetAndArgTypes[i].IsCanonicalSubtype())
+        {
+            return TRUE;
+        }
+    }
+    return FALSE;
+} // FnPtrTypeDesc::IsSharedByGenericInstantiations
+
 #ifndef DACCESS_COMPILE
 
 // Returns TRUE if all return and argument types are externally visible.
@@ -1660,10 +1685,9 @@ FnPtrTypeDesc::IsExternallyVisible() const
     }
     CONTRACTL_END;
 
-    const TypeHandle * rgRetAndArgTypes = GetRetAndArgTypes();
     for (DWORD i = 0; i <= m_NumArgs; i++)
     {
-        if (!rgRetAndArgTypes[i].IsExternallyVisible())
+        if (!m_RetAndArgTypes[i].IsExternallyVisible())
         {
             return FALSE;
         }
index 7134195d8fd6a68d2b10269172806b0e878ab6a1..a306930342aee683882a8bcf8a12199f92c5fe46 100644 (file)
@@ -181,6 +181,8 @@ public:
         return GetLoaderModule()->GetLoaderAllocator();
     }
 
+    BOOL IsSharedByGenericInstantiations();
+
  protected:
     // See methodtable.h for details of the flags with the same name there
     enum
@@ -524,6 +526,8 @@ public:
         return PTR_TypeHandle(m_RetAndArgTypes);
     }
 
+    BOOL IsSharedByGenericInstantiations();
+
 #ifndef DACCESS_COMPILE
     // Returns TRUE if all return and argument types are externally visible.
     BOOL IsExternallyVisible() const;
index 292d14f036f9525384a0e51878ddf78a241a04e5..647e14eeaa6f648a494f4c6e98e5fc4c61746d29 100644 (file)
@@ -325,12 +325,15 @@ BOOL TypeHandle::IsSharedByGenericInstantiations() const
 {
     LIMITED_METHOD_DAC_CONTRACT;
 
-    if (IsArray())
+    if (IsTypeDesc())
     {
-        return GetArrayElementTypeHandle().IsCanonicalSubtype();
+        return AsTypeDesc()->IsSharedByGenericInstantiations();
     }
-    else if (!IsTypeDesc())
+    else
     {
+        if (IsArray())
+            return GetArrayElementTypeHandle().IsCanonicalSubtype();
+
         return AsMethodTable()->IsSharedByGenericInstantiations();
     }
 
diff --git a/src/tests/Regressions/coreclr/GitHub_85240/test85240.cs b/src/tests/Regressions/coreclr/GitHub_85240/test85240.cs
new file mode 100644 (file)
index 0000000..e56c7d4
--- /dev/null
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+#pragma warning disable 8500
+
+public unsafe class Program
+{
+    static void AssertEqual<T>(T actual, T expected)
+    {
+        if (!actual.Equals(expected))
+            throw new Exception($"Failed Scenario. Actual = {actual}. Expected = {expected}");
+    }
+
+    public static Type GrabArray<T>() => typeof(T[]);
+    public static Type GrabPtr<T>() => typeof(T*);
+    public static Type GrabFnptr<T>() => typeof(delegate*<T>);
+
+    public static int Main()
+    {
+        AssertEqual(GrabArray<int>().GetElementType(), typeof(int));
+        AssertEqual(GrabArray<string>().GetElementType(), typeof(string));
+
+        AssertEqual(GrabPtr<uint>().GetElementType(), typeof(uint));
+        AssertEqual(GrabPtr<object>().GetElementType(), typeof(object));
+
+        AssertEqual(GrabFnptr<DateTime>().GetFunctionPointerReturnType(), typeof(DateTime));
+        AssertEqual(GrabFnptr<Action>().GetFunctionPointerReturnType(), typeof(Action));
+
+        return 100;
+    }
+}
diff --git a/src/tests/Regressions/coreclr/GitHub_85240/test85240.csproj b/src/tests/Regressions/coreclr/GitHub_85240/test85240.csproj
new file mode 100644 (file)
index 0000000..2dc4ce7
--- /dev/null
@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="test85240.cs" />
+  </ItemGroup>
+</Project>
index f0d8e1b5d5ab111712f031238e5a93e366744770..c32e9c47c40dfef38bd7e64c5bc1d60d05103486 100644 (file)
 
     <!-- Known failures for mono runtime on *all* architectures/operating systems in *all* runtime modes -->
     <ItemGroup Condition="'$(RuntimeFlavor)' == 'mono'" >
+        <ExcludeList Include="$(XunitTestBinBase)/Regressions/coreclr/GitHub_85240/test85240/**">
+            <Issue>https://github.com/dotnet/runtime/issues/71095</Issue>
+        </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/JIT/opt/Remainder/Regressions/Regression1/**">
             <Issue>https://github.com/dotnet/runtime/issues/79022</Issue>
         </ExcludeList>