if (!strcmp (tm, "InternalGetHashCode")) {
*op = MINT_INTRINS_GET_HASHCODE;
} else if (!strcmp (tm, "GetType")) {
- if (constrained_class && m_class_is_valuetype (constrained_class)) {
+ if (constrained_class && m_class_is_valuetype (constrained_class) && !mono_class_is_nullable (constrained_class)) {
// If constrained_class is valuetype we already know its type.
// Resolve GetType to a constant so we can fold type comparisons
ERROR_DECL(error);
return TRUE;
} else {
if (constrained_class) {
- // deref the managed pointer to get the object
- interp_add_ins (td, MINT_LDIND_I);
+ if (mono_class_is_nullable (constrained_class)) {
+ // We can't determine the behavior here statically because we don't know if the
+ // nullable vt has a value or not. If it has a value, the result type is
+ // m_class_get_cast_class (constrained_class), otherwise GetType should throw NRE.
+ interp_add_ins (td, MINT_BOX_NULLABLE_PTR);
+ td->last_ins->data [0] = get_data_item_index (td, constrained_class);
+ } else {
+ // deref the managed pointer to get the object
+ interp_add_ins (td, MINT_LDIND_I);
+ }
td->sp--;
interp_ins_set_sreg (td->last_ins, td->sp [0].local);
push_simple_type (td, STACK_TYPE_O);
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+class C<T>
+{
+ public IEnumerable<T> Data { get; set; }
+
+ public C() { }
+
+ public bool Check()
+ {
+ return Data.ElementAt(0).GetType() == typeof(bool);
+ }
+}
+
+public class P
+{
+ public static int Main()
+ {
+ C<bool?> c = new();
+
+ // Try a nullable with value
+ c.Data = new List<bool?> { true };
+ if(!c.Check())
+ return 666;
+
+ // Try a nullable without value. Should throw NRE
+ c.Data = new List<bool?> { new Nullable<bool>() };
+
+ bool thrown = false;
+ try
+ {
+ c.Check();
+ }
+ catch(NullReferenceException)
+ {
+ thrown = true;
+ }
+ if(!thrown)
+ return 667;
+ return 100;
+ }
+}
+
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestPriority>1</CLRTestPriority>
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType>Full</DebugType>
+ <Optimize>False</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="gettype.cs" />
+ </ItemGroup>
+</Project>
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestPriority>1</CLRTestPriority>
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType>Full</DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="gettype.cs" />
+ </ItemGroup>
+</Project>
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestPriority>1</CLRTestPriority>
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType>None</DebugType>
+ <Optimize>False</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="gettype.cs" />
+ </ItemGroup>
+</Project>
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <CLRTestPriority>1</CLRTestPriority>
+ </PropertyGroup>
+ <PropertyGroup>
+ <DebugType>None</DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="gettype.cs" />
+ </ItemGroup>
+</Project>