+ if (tparam.HasSpecialStruct && (!TypeManager.IsValueType (atype) || TypeManager.IsNullableType (atype))) {
+ report.Error (453, loc,
+ "The type `{0}' must be a non-nullable value type in order to use it as type parameter `{1}' in the generic type or method `{2}'",
+ TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ());
+ return false;
+ }
+
+ //
+ // The class constraint comes next.
+ //
+ if (tparam.HasTypeConstraint) {
+ CheckConversion (context, atype, tparam, tparam.BaseType, loc, report);
+ }
+
+ //
+ // Now, check the interfaces and type parameters constraints
+ //
+ if (tparam.Interfaces != null) {
+ if (TypeManager.IsNullableType (atype)) {
+ report.Error (313, loc,
+ "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. The nullable type `{0}' never satisfies interface constraint",
+ atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError ());
+ } else {
+ foreach (TypeSpec iface in tparam.Interfaces) {
+ CheckConversion (context, atype, tparam, iface, loc, report);
+ }
+ }
+ }
+
+ //
+ // Finally, check the constructor constraint.
+ //
+ if (!tparam.HasSpecialConstructor)
+ return true;
+
+ if (!HasDefaultConstructor (atype)) {
+ report.SymbolRelatedToPreviousError (atype);
+ report.Error (310, loc,
+ "The type `{0}' must have a public parameterless constructor in order to use it as parameter `{1}' in the generic type or method `{2}'",
+ TypeManager.CSharpName (atype), tparam.GetSignatureForError (), context.GetSignatureForError ());
+ return false;
+ }
+
+ return true;
+ }
+
+ static void CheckConversion (MemberSpec context, TypeSpec atype, TypeParameterSpec tparam, TypeSpec ttype, Location loc, Report report)
+ {
+ var expr = new EmptyExpression (atype);
+ if (!Convert.ImplicitStandardConversionExists (expr, ttype)) {
+ report.SymbolRelatedToPreviousError (tparam);
+ if (TypeManager.IsValueType (atype)) {
+ report.Error (315, loc, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing conversion from `{0}' to `{3}'",
+ atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
+ } else if (atype.IsGenericParameter) {
+ report.Error (314, loc, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no boxing or type parameter conversion from `{0}' to `{3}'",
+ atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
+ } else {
+ report.Error (311, loc, "The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. There is no implicit reference conversion from `{0}' to `{3}'",
+ atype.GetSignatureForError (), tparam.GetSignatureForError (), context.GetSignatureForError (), ttype.GetSignatureForError ());
+ }
+ }
+ }
+
+ static bool HasDefaultConstructor (TypeSpec atype)
+ {
+ var tp = atype as TypeParameterSpec;
+ if (tp != null) {
+ return tp.HasSpecialConstructor || tp.HasSpecialStruct;
+ }
+
+ if (atype.IsStruct || atype.IsEnum)
+ return true;
+
+ if (atype.IsAbstract)
+ return false;