/// <summary> /// Returns true if the constraint is valid. Otherwise /// returns false and generates a diagnostic. /// </summary> internal static bool IsValidConstraint( string typeParameterName, TypeConstraintSyntax syntax, TypeWithAnnotations type, TypeParameterConstraintKind constraints, ArrayBuilder <TypeWithAnnotations> constraintTypes, DiagnosticBag diagnostics) { if (!IsValidConstraintType(syntax, type, diagnostics)) { return(false); } // Ignore nullability when comparing constraints. if (constraintTypes.Contains(c => type.Equals(c, TypeCompareKind.IgnoreNullableModifiersForReferenceTypes))) { // "Duplicate constraint '{0}' for type parameter '{1}'" Error(diagnostics, ErrorCode.ERR_DuplicateBound, syntax, type.Type.SetUnknownNullabilityForReferenceTypes(), typeParameterName); return(false); } if (type.TypeKind == TypeKind.Class) { // If there is already a struct or class constraint (class constraint could be // 'class' or explicit type), report an error and drop this class. If we don't // drop this additional class, we may end up with conflicting class constraints. if (constraintTypes.Count > 0) { // "The class type constraint '{0}' must come before any other constraints" Error(diagnostics, ErrorCode.ERR_ClassBoundNotFirst, syntax, type.Type); return(false); } if ((constraints & (TypeParameterConstraintKind.ReferenceType)) != 0) { switch (type.SpecialType) { case SpecialType.System_Enum: case SpecialType.System_Delegate: case SpecialType.System_MulticastDelegate: break; default: // "'{0}': cannot specify both a constraint class and the 'class' or 'struct' constraint" Error(diagnostics, ErrorCode.ERR_RefValBoundWithClass, syntax, type.Type); return(false); } } else if (type.SpecialType != SpecialType.System_Enum) { if ((constraints & TypeParameterConstraintKind.ValueType) != 0) { // "'{0}': cannot specify both a constraint class and the 'class' or 'struct' constraint" Error(diagnostics, ErrorCode.ERR_RefValBoundWithClass, syntax, type.Type); return(false); } else if ((constraints & TypeParameterConstraintKind.Unmanaged) != 0) { // "'{0}': cannot specify both a constraint class and the 'unmanaged' constraint" Error(diagnostics, ErrorCode.ERR_UnmanagedBoundWithClass, syntax, type.Type); return(false); } } } return(true); }