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); }