Skip to content

Commit

Permalink
Implement a simple prototype for const type parameter constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
hez2010 committed Aug 5, 2023
1 parent edab29d commit e1fa0c3
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 2 deletions.
98 changes: 96 additions & 2 deletions src/coreclr/vm/typedesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1561,9 +1561,14 @@ BOOL TypeVarTypeDesc::SatisfiesConstraints(SigTypeContext *pTypeContextOfConstra
ClassLoader::FailIfUninstDefOrRef,
ClassLoader::LoadTypes,
CLASS_DEPENDENCIES_LOADED);

// A const value will only be satisfied if the evaluation result is equal to it
if (thArg.IsConstValue())
{
if (thArg.GetConstValue() != EvaluateConstValueConstraint(thConstraint))
return FALSE;
}
// System.Object constraint will be always satisfied - even if argList is empty
if (!thConstraint.IsObjectType())
else if (!thConstraint.IsObjectType())
{
BOOL fCanCast = FALSE;

Expand Down Expand Up @@ -1652,6 +1657,95 @@ BOOL TypeVarTypeDesc::SatisfiesConstraints(SigTypeContext *pTypeContextOfConstra
return TRUE;
}

uint64_t TypeVarTypeDesc::EvaluateConstValueConstraint(TypeHandle thConstraint, CorElementType* type)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_ANY;

PRECONDITION(!thConstraint.IsNull());
INJECT_FAULT(COMPlusThrowOM());
}
CONTRACTL_END;

SString s;
uint64_t ret = 0;
thConstraint.AsMethodTable()->_GetFullyQualifiedNameForClass(s);

if (strcmp(s.GetUTF8(), "IBinaryExpression`3") == 0)
{
Instantiation inst = thConstraint.GetInstantiation();
_ASSERTE(inst.GetNumArgs() == 3);
CorElementType leftType;
uint64_t left = EvaluateConstValueConstraint(inst[1], &leftType);
CorElementType rightType;
uint64_t right = EvaluateConstValueConstraint(inst[2], &rightType);
_ASSERTE(leftType == rightType);
inst[0].AsMethodTable()->_GetFullyQualifiedNameForClass(s);
switch (leftType)
{
case ELEMENT_TYPE_BOOLEAN:
{
EvalBinary(uint8_t);
break;
}
case ELEMENT_TYPE_I1:
case ELEMENT_TYPE_U1:
{
EvalBinary(uint8_t);
break;
}
case ELEMENT_TYPE_I2:
case ELEMENT_TYPE_U2:
case ELEMENT_TYPE_CHAR:
{
EvalBinary(uint16_t);
break;
}
case ELEMENT_TYPE_I4:
case ELEMENT_TYPE_U4:
{
EvalBinary(uint32_t);
break;
}
case ELEMENT_TYPE_I8:
case ELEMENT_TYPE_U8:
{
EvalBinary(uint64_t);
break;
}
case ELEMENT_TYPE_R4:
{
EvalBinary(float);
break;
}
case ELEMENT_TYPE_R8:
{
EvalBinary(double);
break;
}
default:
_ASSERTE(!"EVALUATION NOT SUPPORTED");
if (type)
*type = ELEMENT_TYPE_END;
break;
}
}

if (strcmp(s.GetUTF8(), "IConstantExpression`2") == 0)
{
Instantiation inst = thConstraint.GetInstantiation();
_ASSERTE(inst.GetNumArgs() == 2);
if (type)
*type = inst[1].AsConstValue()->GetConstValueType().GetInternalCorElementType();
ret = inst[1].AsConstValue()->GetConstValue();
}

return ret;
}

OBJECTREF TypeVarTypeDesc::GetManagedClassObject()
{
CONTRACTL {
Expand Down
13 changes: 13 additions & 0 deletions src/coreclr/vm/typedesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@
#define TYPEDESC_H
#include <specstrings.h>

#define EvalBinary(dataType) \
if (strcmp(s.GetUTF8(), "AdditionOperator") == 0) { dataType res = *(dataType*)&left + *(dataType*)&right; if (type) *type = leftType; memcpy(&ret, &res, sizeof(dataType)); } \
if (strcmp(s.GetUTF8(), "SubtractionOperator") == 0) { dataType res = *(dataType*)&left - *(dataType*)&right; if (type) *type = leftType; memcpy(&ret, &res, sizeof(dataType)); } \
if (strcmp(s.GetUTF8(), "MultiplyOperator") == 0) { dataType res = *(dataType*)&left * *(dataType*)&right; if (type) *type = leftType; memcpy(&ret, &res, sizeof(dataType)); } \
if (strcmp(s.GetUTF8(), "DivisionOperator") == 0) { dataType res = *(dataType*)&left / *(dataType*)&right; if (type) *type = leftType; memcpy(&ret, &res, sizeof(dataType)); } \
if (strcmp(s.GetUTF8(), "EqualityOperator") == 0) { BOOL res = *(dataType*)&left == *(dataType*)&right; if (type) *type = CorElementType::ELEMENT_TYPE_BOOLEAN; memcpy(&ret, &res, sizeof(BOOL)); } \
if (strcmp(s.GetUTF8(), "LessThanOperator") == 0) { BOOL res = *(dataType*)&left < *(dataType*)&right; if (type) *type = CorElementType::ELEMENT_TYPE_BOOLEAN; memcpy(&ret, &res, sizeof(BOOL)); } \
if (strcmp(s.GetUTF8(), "ConjunctionOperator") == 0) { BOOL res = *(dataType*)&left && *(dataType*)&right; if (type) *type = CorElementType::ELEMENT_TYPE_BOOLEAN; memcpy(&ret, &res, sizeof(BOOL)); } \
if (strcmp(s.GetUTF8(), "DisjunctionOperator") == 0) { BOOL res = *(dataType*)&left || *(dataType*)&right; if (type) *type = CorElementType::ELEMENT_TYPE_BOOLEAN; memcpy(&ret, &res, sizeof(BOOL)); }

class TypeHandleList;

/*************************************************************************/
Expand Down Expand Up @@ -504,6 +514,9 @@ class TypeVarTypeDesc : public TypeDesc
BOOL SatisfiesConstraints(SigTypeContext *pTypeContext, TypeHandle thArg,
const InstantiationContext *pInstContext = NULL);

// Evaluate the result of const value constraint
uint64_t EvaluateConstValueConstraint(TypeHandle thConstraint, CorElementType* type = NULL);

// Check whether the constraints on this type force it to be a reference type (i.e. it is impossible
// to instantiate it with a value type).
BOOL ConstrainedAsObjRef();
Expand Down

0 comments on commit e1fa0c3

Please sign in to comment.