Skip to content

Commit

Permalink
Fixed creating generic type with abstract type when it is has a defau…
Browse files Browse the repository at this point in the history
…lt constractor constrant (#101963)

* Fixed creating generic type with abstract type when it is has a default constructor constraint

* Fix missing ; in test.

---------

Co-authored-by: Ivan Diaz <[email protected]>
  • Loading branch information
Faolan-Rad and ivdiazsa authored Aug 16, 2024
1 parent 78def3e commit 1a305e6
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ private static bool SatisfiesConstraints(this Type genericVariable, SigTypeConte

if ((attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
{
if (!typeArg.HasExplicitOrImplicitPublicDefaultConstructor())
if (!typeArg.HasExplicitOrImplicitPublicDefaultConstructor() || typeArg.IsAbstract)
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/typedesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1455,7 +1455,7 @@ BOOL TypeVarTypeDesc::SatisfiesConstraints(SigTypeContext *pTypeContextOfConstra

if ((specialConstraints & gpDefaultConstructorConstraint) != 0)
{
if (thArg.IsTypeDesc() || (!thArg.AsMethodTable()->HasExplicitOrImplicitPublicDefaultConstructor()))
if (thArg.IsTypeDesc() || (!thArg.AsMethodTable()->HasExplicitOrImplicitPublicDefaultConstructor() || thArg.IsAbstract()))
return FALSE;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public static bool CanSpecialize(Type type, GenericParameterAttributes attribute
if ((attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0)
{
// value types always have default constructors
if (!type.IsValueType && (type.GetConstructor(Type.EmptyTypes) == null))
if (!type.IsValueType && ((type.GetConstructor(Type.EmptyTypes) == null) || type.IsAbstract))
{
return false;
}
Expand Down
3 changes: 2 additions & 1 deletion src/mono/mono/metadata/verify.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/class-internals.h>
#include <mono/metadata/class-init.h>
#include <mono/metadata/class-inlines.h>
#include <mono/metadata/tokentype.h>
#include <mono/metadata/mono-basic-block.h>
#include <mono/metadata/attrdefs.h>
Expand Down Expand Up @@ -99,7 +100,7 @@ is_valid_generic_instantiation (MonoGenericContainer *gc, MonoGenericContext *co
if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT) && m_class_is_valuetype (paramClass))
return FALSE;

if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !m_class_is_valuetype (paramClass) && !mono_class_has_default_constructor (paramClass, TRUE))
if ((param_info->flags & GENERIC_PARAMETER_ATTRIBUTE_CONSTRUCTOR_CONSTRAINT) && !m_class_is_valuetype (paramClass) && (!mono_class_has_default_constructor (paramClass, TRUE) || mono_class_is_abstract (paramClass)))
return FALSE;

if (!param_info->constraints)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// 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.Reflection;
using Xunit;

public class X
{
public abstract class AbstractClassWithConstructor
{
public AbstractClassWithConstructor()
{
}
}

public static T TestConstructorMethod<T>() where T : new()
{
return new T();
}

public interface IItemCreator
{
public object CreateItem();
}

public sealed class ItemCreator<T> : IItemCreator where T : new()
{
public object CreateItem()
{
return new T();
}
}

[Fact]
public static int TestEntryPoint()
{
var ok = true;

Type type = null;
try
{
type = typeof(ItemCreator<>).MakeGenericType(typeof(AbstractClassWithConstructor));
}
catch
{
//Could check if it is the proper type of exception
}
if (type == null) {
Console.WriteLine("Wasn't able to load type as expected");
}
else
{
Console.WriteLine("Was able to make type which wasn't expected");
ok = false;
}

MethodInfo baseMethod = typeof(X).GetMethod(nameof(TestConstructorMethod), BindingFlags.Static | BindingFlags.Public);
if (baseMethod == null)
{
Console.WriteLine("baseMethod was null which wasn't expected");
ok = false;
}
MethodInfo method = null;
try
{
method = baseMethod.MakeGenericMethod(typeof(AbstractClassWithConstructor));
}
catch
{
//Could check if it is the proper method of exception
}
if (method == null)
{
Console.WriteLine("Wasn't able to load method as expected");
}
else
{
Console.WriteLine("Was able to make method which wasn't expected");
ok = false;
}

Console.WriteLine(ok ? "PASS" : "FAIL");
return ok ? 100 : -1;
}
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<Compile Include="DisallowAbstractConstructors.cs" />
</ItemGroup>
</Project>

0 comments on commit 1a305e6

Please sign in to comment.