public static bool CheckConstraints(this MethodDesc method, InstantiationContext context = null)
        {
            if (!method.OwningType.CheckConstraints(context))
            {
                return(false);
            }

            // Non-generic methods always pass constraints check
            if (!method.HasInstantiation)
            {
                return(true);
            }

            var        paramContext         = new InstantiationContext(method.OwningType.Instantiation, method.Instantiation);
            MethodDesc uninstantiatedMethod = method.GetMethodDefinition();

            for (int i = 0; i < uninstantiatedMethod.Instantiation.Length; i++)
            {
                if (!VerifyGenericParamConstraint(paramContext, (GenericParameterDesc)uninstantiatedMethod.Instantiation[i], context, method.Instantiation[i]))
                {
                    return(false);
                }
            }

            return(true);
        }
        private static void GetInstantiatedConstraintsRecursive(InstantiationContext typeContext, TypeDesc type, ref ArrayBuilder <TypeDesc> instantiatedConstraints)
        {
            if (!type.IsGenericParameter || typeContext == null)
            {
                return;
            }

            GenericParameterDesc genericParam = (GenericParameterDesc)type;

            foreach (var constraint in genericParam.TypeConstraints)
            {
                var instantiatedType = constraint.InstantiateSignature(typeContext.TypeInstantiation, typeContext.MethodInstantiation);

                if (instantiatedType.IsGenericParameter)
                {
                    // Make sure it is save to call this method recursively
                    if (!instantiatedConstraints.Contains(instantiatedType))
                    {
                        instantiatedConstraints.Add(instantiatedType);

                        // Constraints of this constraint apply to 'genericParam' too
                        GetInstantiatedConstraintsRecursive(typeContext, instantiatedType, ref instantiatedConstraints);
                    }
                }
                else
                {
                    instantiatedConstraints.Add(instantiatedType);
                }
            }
        }
        private static bool VerifyGenericParamConstraint(InstantiationContext genericParamContext, GenericParameterDesc genericParam,
                                                         InstantiationContext instantiationParamContext, TypeDesc instantiationParam)
        {
            GenericConstraints constraints = genericParam.Constraints;

            // Check class constraint
            if ((constraints & GenericConstraints.ReferenceTypeConstraint) != 0)
            {
                if (!instantiationParam.IsGCPointer &&
                    !CheckGenericSpecialConstraint(instantiationParam, GenericConstraints.ReferenceTypeConstraint))
                {
                    return(false);
                }
            }

            // Check default constructor constraint
            if ((constraints & GenericConstraints.DefaultConstructorConstraint) != 0)
            {
                if (!instantiationParam.HasExplicitOrImplicitDefaultConstructor() &&
                    !CheckGenericSpecialConstraint(instantiationParam, GenericConstraints.DefaultConstructorConstraint))
                {
                    return(false);
                }
            }

            // Check struct constraint
            if ((constraints & GenericConstraints.NotNullableValueTypeConstraint) != 0)
            {
                if ((!instantiationParam.IsValueType || instantiationParam.IsNullable) &&
                    !CheckGenericSpecialConstraint(instantiationParam, GenericConstraints.NotNullableValueTypeConstraint))
                {
                    return(false);
                }
            }

            var instantiatedConstraints = new ArrayBuilder <TypeDesc>();

            GetInstantiatedConstraintsRecursive(instantiationParamContext, instantiationParam, ref instantiatedConstraints);

            foreach (var constraintType in genericParam.TypeConstraints)
            {
                var instantiatedType = constraintType.InstantiateSignature(genericParamContext.TypeInstantiation, genericParamContext.MethodInstantiation);
                if (CanCastConstraint(ref instantiatedConstraints, instantiatedType))
                {
                    continue;
                }

                if (!instantiationParam.CanCastTo(instantiatedType))
                {
                    return(false);
                }
            }

            return(true);
        }
        public static bool CheckConstraints(this TypeDesc type, InstantiationContext context = null)
        {
            TypeDesc uninstantiatedType = type.GetTypeDefinition();

            // Non-generic types always pass constraints check
            if (uninstantiatedType == type)
            {
                return(true);
            }

            var paramContext = new InstantiationContext(type.Instantiation, default(Instantiation));

            for (int i = 0; i < uninstantiatedType.Instantiation.Length; i++)
            {
                if (!VerifyGenericParamConstraint(paramContext, (GenericParameterDesc)uninstantiatedType.Instantiation[i], context, type.Instantiation[i]))
                {
                    return(false);
                }
            }

            return(true);
        }