+ /// <summary>
+ /// Check the constraints; we're called from ResolveAsTypeTerminal()
+ /// after fully resolving the constructed type.
+ /// </summary>
+ public bool CheckConstraints (IResolveContext ec)
+ {
+ for (int i = 0; i < gen_params.Length; i++) {
+ if (!CheckConstraints (ec, i))
+ return false;
+ }
+
+ return true;
+ }
+
+ protected bool CheckConstraints (IResolveContext ec, int index)
+ {
+ Type atype = atypes [index];
+ Type ptype = gen_params [index];
+
+ if (atype == ptype)
+ return true;
+
+ Expression aexpr = new EmptyExpression (atype);
+
+ GenericConstraints gc = TypeManager.GetTypeParameterConstraints (ptype);
+ if (gc == null)
+ return true;
+
+ bool is_class, is_struct;
+ if (atype.IsGenericParameter) {
+ GenericConstraints agc = TypeManager.GetTypeParameterConstraints (atype);
+ if (agc != null) {
+ if (agc is Constraints)
+ ((Constraints) agc).Resolve (ec);
+ is_class = agc.IsReferenceType;
+ is_struct = agc.IsValueType;
+ } else {
+ is_class = is_struct = false;
+ }
+ } else {
+#if MS_COMPATIBLE
+ is_class = false;
+ if (!atype.IsGenericType)
+#endif
+ is_class = atype.IsClass || atype.IsInterface;
+ is_struct = atype.IsValueType && !TypeManager.IsNullableType (atype);
+ }
+
+ //
+ // First, check the `class' and `struct' constraints.
+ //
+ if (gc.HasReferenceTypeConstraint && !is_class) {
+ Report.Error (452, loc, "The type `{0}' must be " +
+ "a reference type in order to use it " +
+ "as type parameter `{1}' in the " +
+ "generic type or method `{2}'.",
+ TypeManager.CSharpName (atype),
+ TypeManager.CSharpName (ptype),
+ GetSignatureForError ());
+ return false;
+ } else if (gc.HasValueTypeConstraint && !is_struct) {
+ 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),
+ TypeManager.CSharpName (ptype),
+ GetSignatureForError ());
+ return false;
+ }
+
+ //
+ // The class constraint comes next.
+ //
+ if (gc.HasClassConstraint) {
+ if (!CheckConstraint (ec, ptype, aexpr, gc.ClassConstraint))
+ return false;
+ }
+
+ //
+ // Now, check the interface constraints.
+ //
+ if (gc.InterfaceConstraints != null) {
+ foreach (Type it in gc.InterfaceConstraints) {
+ if (!CheckConstraint (ec, ptype, aexpr, it))
+ return false;
+ }
+ }
+
+ //
+ // Finally, check the constructor constraint.
+ //
+
+ if (!gc.HasConstructorConstraint)
+ return true;
+
+ if (TypeManager.IsBuiltinType (atype) || atype.IsValueType)
+ return true;
+
+ if (HasDefaultConstructor (ec.DeclContainer.TypeBuilder, atype))
+ return true;
+
+ Report_SymbolRelatedToPreviousError ();
+ 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),
+ TypeManager.CSharpName (ptype),
+ GetSignatureForError ());
+ return false;
+ }
+
+ protected bool CheckConstraint (IResolveContext ec, Type ptype, Expression expr,
+ Type ctype)
+ {
+ if (TypeManager.HasGenericArguments (ctype)) {
+ Type[] types = TypeManager.GetTypeArguments (ctype);
+
+ TypeArguments new_args = new TypeArguments (loc);
+
+ for (int i = 0; i < types.Length; i++) {
+ Type t = types [i];
+
+ if (t.IsGenericParameter) {
+ int pos = t.GenericParameterPosition;
+ t = atypes [pos];
+ }
+ new_args.Add (new TypeExpression (t, loc));
+ }
+
+ TypeExpr ct = new ConstructedType (ctype, new_args, loc);
+ if (ct.ResolveAsTypeStep (ec, false) == null)
+ return false;
+ ctype = ct.Type;
+ } else if (ctype.IsGenericParameter) {
+ int pos = ctype.GenericParameterPosition;
+ ctype = atypes [pos];
+ }
+
+ if (Convert.ImplicitStandardConversionExists (expr, ctype))
+ return true;
+
+ Error_TypeMustBeConvertible (expr.Type, ctype, ptype);
+ return false;
+ }
+
+ bool HasDefaultConstructor (Type containerType, Type atype)
+ {
+ if (atype.IsAbstract)
+ return false;
+
+ again:
+ atype = TypeManager.DropGenericTypeArguments (atype);
+ if (atype is TypeBuilder) {
+ TypeContainer tc = TypeManager.LookupTypeContainer (atype);
+ if (tc.InstanceConstructors == null) {
+ atype = atype.BaseType;
+ goto again;
+ }
+
+ foreach (Constructor c in tc.InstanceConstructors) {
+ if ((c.ModFlags & Modifiers.PUBLIC) == 0)
+ continue;
+ if ((c.Parameters.FixedParameters != null) &&
+ (c.Parameters.FixedParameters.Length != 0))
+ continue;
+ if (c.Parameters.HasArglist || c.Parameters.HasParams)
+ continue;
+
+ return true;
+ }
+ }
+
+ TypeParameter tparam = TypeManager.LookupTypeParameter (atype);
+ if (tparam != null)
+ return tparam.HasConstructorConstraint;
+
+ MemberList list = TypeManager.FindMembers (
+ atype, MemberTypes.Constructor,
+ BindingFlags.Public | BindingFlags.Instance |
+ BindingFlags.DeclaredOnly, null, null);
+
+ if (atype.IsAbstract || (list == null))
+ return false;
+
+ foreach (MethodBase mb in list) {
+ ParameterData pd = TypeManager.GetParameterData (mb);
+ if ((pd.Count == 0) && mb.IsPublic && !mb.IsStatic)
+ return true;
+ }
+
+ return false;
+ }
+
+ protected abstract string GetSignatureForError ();
+ protected abstract void Report_SymbolRelatedToPreviousError ();
+
+ void Error_TypeMustBeConvertible (Type atype, Type gc, Type ptype)
+ {
+ Report_SymbolRelatedToPreviousError ();
+ Report.SymbolRelatedToPreviousError (atype);
+ Report.Error (309, loc,
+ "The type `{0}' must be convertible to `{1}' in order to " +
+ "use it as parameter `{2}' in the generic type or method `{3}'",
+ TypeManager.CSharpName (atype), TypeManager.CSharpName (gc),
+ TypeManager.CSharpName (ptype), GetSignatureForError ());
+ }
+
+ public static bool CheckConstraints (EmitContext ec, MethodBase definition,
+ MethodBase instantiated, Location loc)
+ {
+ MethodConstraintChecker checker = new MethodConstraintChecker (
+ definition, definition.GetGenericArguments (),
+ instantiated.GetGenericArguments (), loc);
+
+ return checker.CheckConstraints (ec);
+ }
+
+ public static bool CheckConstraints (IResolveContext ec, Type gt, Type[] gen_params,
+ Type[] atypes, Location loc)
+ {
+ TypeConstraintChecker checker = new TypeConstraintChecker (
+ gt, gen_params, atypes, loc);
+
+ return checker.CheckConstraints (ec);
+ }
+
+ protected class MethodConstraintChecker : ConstraintChecker
+ {
+ MethodBase definition;
+
+ public MethodConstraintChecker (MethodBase definition, Type[] gen_params,
+ Type[] atypes, Location loc)
+ : base (gen_params, atypes, loc)
+ {
+ this.definition = definition;
+ }
+
+ protected override string GetSignatureForError ()
+ {
+ return TypeManager.CSharpSignature (definition);
+ }
+
+ protected override void Report_SymbolRelatedToPreviousError ()
+ {
+ Report.SymbolRelatedToPreviousError (definition);
+ }
+ }
+
+ protected class TypeConstraintChecker : ConstraintChecker
+ {
+ Type gt;
+
+ public TypeConstraintChecker (Type gt, Type[] gen_params, Type[] atypes,
+ Location loc)
+ : base (gen_params, atypes, loc)
+ {
+ this.gt = gt;
+ }
+
+ protected override string GetSignatureForError ()
+ {
+ return TypeManager.CSharpName (gt);
+ }
+
+ protected override void Report_SymbolRelatedToPreviousError ()
+ {
+ Report.SymbolRelatedToPreviousError (gt);
+ }
+ }
+ }
+
+ /// <summary>
+ /// A generic method definition.
+ /// </summary>
+ public class GenericMethod : DeclSpace
+ {
+ Expression return_type;
+ Parameters parameters;
+
+ public GenericMethod (NamespaceEntry ns, DeclSpace parent, MemberName name,
+ Expression return_type, Parameters parameters)
+ : base (ns, parent, name, null)
+ {
+ this.return_type = return_type;
+ this.parameters = parameters;
+ }
+
+ public override TypeBuilder DefineType ()