2 // generic.cs: Generics support
4 // Authors: Martin Baulig (martin@ximian.com)
5 // Miguel de Icaza (miguel@ximian.com)
7 // Licensed under the terms of the GNU GPL
9 // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
10 // (C) 2004 Novell, Inc
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Globalization;
16 using System.Collections;
18 using System.Text.RegularExpressions;
20 namespace Mono.CSharp {
22 public abstract class GenericConstraints {
23 public abstract GenericParameterAttributes Attributes {
27 public bool HasConstructorConstraint {
28 get { return (Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0; }
31 public bool HasReferenceTypeConstraint {
32 get { return (Attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0; }
35 public bool HasValueTypeConstraint {
36 get { return (Attributes & GenericParameterAttributes.ValueTypeConstraint) != 0; }
39 public virtual bool HasClassConstraint {
40 get { return ClassConstraint != null; }
43 public abstract Type ClassConstraint {
47 public abstract Type[] InterfaceConstraints {
51 public abstract Type EffectiveBaseClass {
56 // Returns whether the type parameter is "known to be a reference type".
58 public virtual bool IsReferenceType {
60 if (HasReferenceTypeConstraint)
62 if (HasValueTypeConstraint)
65 if (ClassConstraint != null) {
66 if (ClassConstraint.IsValueType)
69 if (ClassConstraint != TypeManager.object_type)
73 foreach (Type t in InterfaceConstraints) {
74 if (!t.IsGenericParameter)
77 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
78 if ((gc != null) && gc.IsReferenceType)
87 // Returns whether the type parameter is "known to be a value type".
89 public virtual bool IsValueType {
91 if (HasValueTypeConstraint)
93 if (HasReferenceTypeConstraint)
96 if (ClassConstraint != null) {
97 if (!ClassConstraint.IsValueType)
100 if (ClassConstraint != TypeManager.value_type)
104 foreach (Type t in InterfaceConstraints) {
105 if (!t.IsGenericParameter)
108 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
109 if ((gc != null) && gc.IsValueType)
118 public enum SpecialConstraint
126 // Tracks the constraints for a type parameter
128 public class Constraints : GenericConstraints {
130 ArrayList constraints;
134 // name is the identifier, constraints is an arraylist of
135 // Expressions (with types) or `true' for the constructor constraint.
137 public Constraints (string name, ArrayList constraints,
141 this.constraints = constraints;
145 public string TypeParameter {
151 GenericParameterAttributes attrs;
152 TypeExpr class_constraint;
153 ArrayList iface_constraints;
154 ArrayList type_param_constraints;
155 int num_constraints, first_constraint;
156 Type class_constraint_type;
157 Type[] iface_constraint_types;
158 Type effective_base_type;
160 public bool Resolve (EmitContext ec)
162 iface_constraints = new ArrayList ();
163 type_param_constraints = new ArrayList ();
165 foreach (object obj in constraints) {
166 if (HasConstructorConstraint) {
167 Report.Error (401, loc,
168 "The new() constraint must be last.");
172 if (obj is SpecialConstraint) {
173 SpecialConstraint sc = (SpecialConstraint) obj;
175 if (sc == SpecialConstraint.Constructor) {
176 if (!HasValueTypeConstraint) {
177 attrs |= GenericParameterAttributes.DefaultConstructorConstraint;
182 451, loc, "The new () constraint " +
183 "cannot be used with the `struct' " +
188 if ((num_constraints > 0) || HasReferenceTypeConstraint || HasValueTypeConstraint) {
189 Report.Error (449, loc,
190 "The `class' or `struct' " +
191 "constraint must be first");
195 if (sc == SpecialConstraint.ReferenceType)
196 attrs |= GenericParameterAttributes.ReferenceTypeConstraint;
198 attrs |= GenericParameterAttributes.ValueTypeConstraint;
203 if (obj is ConstructedType) {
204 ConstructedType cexpr = (ConstructedType) obj;
205 if (!cexpr.ResolveConstructedType (ec))
209 expr = ((Expression) obj).ResolveAsTypeTerminal (ec);
214 TypeParameterExpr texpr = expr as TypeParameterExpr;
216 type_param_constraints.Add (expr);
217 else if (expr.IsInterface)
218 iface_constraints.Add (expr);
219 else if (class_constraint != null) {
220 Report.Error (406, loc,
221 "`{0}': the class constraint for `{1}' " +
222 "must come before any other constraints.",
225 } else if (HasReferenceTypeConstraint || HasValueTypeConstraint) {
226 Report.Error (450, loc, "`{0}': cannot specify both " +
227 "a constraint class and the `class' " +
228 "or `struct' constraint.", expr.Name);
231 class_constraint = expr;
239 bool CheckTypeParameterConstraints (TypeParameter tparam, Hashtable seen)
241 seen.Add (tparam, true);
243 Constraints constraints = tparam.Constraints;
244 if (constraints == null)
247 if (constraints.HasValueTypeConstraint) {
248 Report.Error (456, loc, "Type parameter `{0}' has " +
249 "the `struct' constraint, so it cannot " +
250 "be used as a constraint for `{1}'",
255 if (constraints.type_param_constraints == null)
258 foreach (TypeParameterExpr expr in constraints.type_param_constraints) {
259 if (seen.Contains (expr.TypeParameter)) {
260 Report.Error (454, loc, "Circular constraint " +
261 "dependency involving `{0}' and `{1}'",
262 tparam.Name, expr.Name);
266 if (!CheckTypeParameterConstraints (expr.TypeParameter, seen))
273 public bool ResolveTypes (EmitContext ec)
275 foreach (object obj in constraints) {
276 ConstructedType cexpr = obj as ConstructedType;
280 if (!cexpr.CheckConstraints (ec))
284 foreach (TypeParameterExpr expr in type_param_constraints) {
285 Hashtable seen = new Hashtable ();
286 if (!CheckTypeParameterConstraints (expr.TypeParameter, seen))
290 ArrayList list = new ArrayList ();
292 foreach (TypeExpr iface_constraint in iface_constraints) {
293 foreach (Type type in list) {
294 if (!type.Equals (iface_constraint.Type))
297 Report.Error (405, loc,
298 "Duplicate constraint `{0}' for type " +
299 "parameter `{1}'.", iface_constraint.Type,
304 list.Add (iface_constraint.Type);
307 foreach (TypeParameterExpr expr in type_param_constraints) {
308 foreach (Type type in list) {
309 if (!type.Equals (expr.Type))
312 Report.Error (405, loc,
313 "Duplicate constraint `{0}' for type " +
314 "parameter `{1}'.", expr.Type, name);
318 list.Add (expr.Type);
321 iface_constraint_types = new Type [list.Count];
322 list.CopyTo (iface_constraint_types, 0);
324 if (class_constraint != null) {
325 class_constraint_type = class_constraint.Type;
326 if (class_constraint_type == null)
329 if (class_constraint_type.IsSealed) {
330 Report.Error (701, loc,
331 "`{0}' is not a valid bound. Bounds " +
332 "must be interfaces or non sealed " +
333 "classes", class_constraint_type);
337 if ((class_constraint_type == TypeManager.array_type) ||
338 (class_constraint_type == TypeManager.delegate_type) ||
339 (class_constraint_type == TypeManager.enum_type) ||
340 (class_constraint_type == TypeManager.value_type) ||
341 (class_constraint_type == TypeManager.object_type)) {
342 Report.Error (702, loc,
343 "Bound cannot be special class `{0}'",
344 class_constraint_type);
349 if (class_constraint_type != null)
350 effective_base_type = class_constraint_type;
351 else if (HasValueTypeConstraint)
352 effective_base_type = TypeManager.value_type;
354 effective_base_type = TypeManager.object_type;
359 public bool CheckDependencies (EmitContext ec)
361 foreach (TypeParameterExpr expr in type_param_constraints) {
362 if (!CheckDependencies (expr.TypeParameter, ec))
369 bool CheckDependencies (TypeParameter tparam, EmitContext ec)
371 Constraints constraints = tparam.Constraints;
372 if (constraints == null)
375 if (HasValueTypeConstraint && constraints.HasClassConstraint) {
376 Report.Error (455, loc, "Type parameter `{0}' inherits " +
377 "conflicting constraints `{1}' and `{2}'",
378 name, constraints.ClassConstraint,
383 if (HasClassConstraint && constraints.HasClassConstraint) {
384 Type t1 = ClassConstraint;
385 TypeExpr e1 = class_constraint;
386 Type t2 = constraints.ClassConstraint;
387 TypeExpr e2 = constraints.class_constraint;
389 if (!Convert.ImplicitReferenceConversionExists (ec, e1, t2) &&
390 !Convert.ImplicitReferenceConversionExists (ec, e2, t1)) {
391 Report.Error (455, loc,
392 "Type parameter `{0}' inherits " +
393 "conflicting constraints `{1}' and `{2}'",
399 if (constraints.type_param_constraints == null)
402 foreach (TypeParameterExpr expr in constraints.type_param_constraints) {
403 if (!CheckDependencies (expr.TypeParameter, ec))
410 public void Define (GenericTypeParameterBuilder type)
412 type.SetGenericParameterAttributes (attrs);
415 public override GenericParameterAttributes Attributes {
416 get { return attrs; }
419 public override bool HasClassConstraint {
420 get { return class_constraint != null; }
423 public override Type ClassConstraint {
424 get { return class_constraint_type; }
427 public override Type[] InterfaceConstraints {
428 get { return iface_constraint_types; }
431 public override Type EffectiveBaseClass {
432 get { return effective_base_type; }
435 internal bool IsSubclassOf (Type t)
437 if ((class_constraint_type != null) &&
438 class_constraint_type.IsSubclassOf (t))
441 if (iface_constraint_types == null)
444 foreach (Type iface in iface_constraint_types) {
445 if (TypeManager.IsSubclassOf (iface, t))
452 public bool CheckInterfaceMethod (EmitContext ec, GenericConstraints gc)
454 if (!ResolveTypes (ec))
457 if (gc.Attributes != attrs)
460 if (HasClassConstraint != gc.HasClassConstraint)
462 if (HasClassConstraint && !TypeManager.IsEqual (gc.ClassConstraint, ClassConstraint))
465 int gc_icount = gc.InterfaceConstraints != null ?
466 gc.InterfaceConstraints.Length : 0;
467 int icount = InterfaceConstraints != null ?
468 InterfaceConstraints.Length : 0;
470 if (gc_icount != icount)
473 foreach (Type iface in gc.InterfaceConstraints) {
475 foreach (Type check in InterfaceConstraints) {
476 if (TypeManager.IsEqual (iface, check)) {
491 // This type represents a generic type parameter
493 public class TypeParameter : MemberCore, IMemberContainer {
495 GenericConstraints gc;
496 Constraints constraints;
498 GenericTypeParameterBuilder type;
500 public TypeParameter (TypeContainer parent, string name,
501 Constraints constraints, Location loc)
502 : base (parent, new MemberName (name), null, loc)
505 this.constraints = constraints;
509 public GenericConstraints GenericConstraints {
511 return gc != null ? gc : constraints;
515 public Constraints Constraints {
521 public bool HasConstructorConstraint {
523 if (constraints != null)
524 return constraints.HasConstructorConstraint;
536 public bool Resolve (DeclSpace ds)
538 if (constraints != null)
539 return constraints.Resolve (ds.EmitContext);
544 public void Define (GenericTypeParameterBuilder type)
546 if (this.type != null)
547 throw new InvalidOperationException ();
550 TypeManager.AddTypeParameter (type, this);
553 public void DefineConstraints ()
555 if (constraints != null)
556 constraints.Define (type);
559 public bool DefineType (EmitContext ec)
561 return DefineType (ec, null, null, false);
564 public bool DefineType (EmitContext ec, MethodBuilder builder,
565 MethodInfo implementing, bool is_override)
567 if (implementing != null) {
568 if (is_override && (constraints != null)) {
570 460, loc, "Constraints for override and " +
571 "explicit interface implementation methods " +
572 "are inherited from the base method so they " +
573 "cannot be specified directly");
577 MethodBase mb = implementing;
578 if (mb.Mono_IsInflatedMethod)
579 mb = mb.GetGenericMethodDefinition ();
581 int pos = type.GenericParameterPosition;
582 ParameterData pd = Invocation.GetParameterData (mb);
583 GenericConstraints temp_gc = pd.GenericConstraints (pos);
584 Type mparam = mb.GetGenericArguments () [pos];
587 gc = new InflatedConstraints (temp_gc, implementing.DeclaringType);
588 else if (constraints != null)
589 gc = new InflatedConstraints (constraints, implementing.DeclaringType);
592 if (constraints != null) {
595 else if (!constraints.CheckInterfaceMethod (ec, gc))
598 if (!is_override && (temp_gc != null))
603 Report.SymbolRelatedToPreviousError (implementing);
606 425, loc, "The constraints for type " +
607 "parameter `{0}' of method `{1}' must match " +
608 "the constraints for type parameter `{2}' " +
609 "of interface method `{3}'. Consider using " +
610 "an explicit interface implementation instead",
611 Name, TypeManager.CSharpSignature (builder),
612 mparam, TypeManager.CSharpSignature (mb));
616 if (constraints != null) {
617 if (!constraints.ResolveTypes (ec))
621 gc = (GenericConstraints) constraints;
627 if (gc.HasClassConstraint)
628 type.SetBaseTypeConstraint (gc.ClassConstraint);
630 type.SetInterfaceConstraints (gc.InterfaceConstraints);
631 TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
636 public bool CheckDependencies (EmitContext ec)
638 if (constraints != null)
639 return constraints.CheckDependencies (ec);
644 public override string DocCommentHeader {
646 throw new InvalidOperationException (
647 "Unexpected attempt to get doc comment from " + this.GetType () + ".");
655 public override bool Define ()
660 protected override void VerifyObsoleteAttribute ()
663 public override void ApplyAttributeBuilder (Attribute a,
664 CustomAttributeBuilder cb)
667 public override AttributeTargets AttributeTargets {
669 return (AttributeTargets) 0;
673 public override string[] ValidAttributeTargets {
675 return new string [0];
683 string IMemberContainer.Name {
687 MemberCache IMemberContainer.BaseCache {
691 bool IMemberContainer.IsInterface {
695 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
697 return FindMembers (mt, bf, null, null);
700 MemberCache IMemberContainer.MemberCache {
704 public MemberList FindMembers (MemberTypes mt, BindingFlags bf,
705 MemberFilter filter, object criteria)
707 if (constraints == null)
708 return MemberList.Empty;
710 ArrayList members = new ArrayList ();
712 GenericConstraints gc = (GenericConstraints) constraints;
714 if (gc.HasClassConstraint) {
715 MemberList list = TypeManager.FindMembers (
716 gc.ClassConstraint, mt, bf, filter, criteria);
718 members.AddRange (list);
721 foreach (Type t in gc.InterfaceConstraints) {
722 MemberList list = TypeManager.FindMembers (
723 t, mt, bf, filter, criteria);
725 members.AddRange (list);
728 return new MemberList (members);
731 public bool IsSubclassOf (Type t)
736 if (constraints != null)
737 return constraints.IsSubclassOf (t);
742 public override string ToString ()
744 return "TypeParameter[" + name + "]";
747 protected class InflatedConstraints : GenericConstraints
749 GenericConstraints gc;
751 Type class_constraint;
752 Type[] iface_constraints;
756 public InflatedConstraints (GenericConstraints gc, Type declaring)
759 this.declaring = declaring;
761 dargs = TypeManager.GetTypeArguments (declaring);
763 ArrayList list = new ArrayList ();
764 if (gc.HasClassConstraint)
765 list.Add (inflate (gc.ClassConstraint));
766 foreach (Type iface in gc.InterfaceConstraints)
767 list.Add (inflate (iface));
769 bool has_class_constr = false;
770 if (list.Count > 0) {
771 Type first = (Type) list [0];
772 has_class_constr = !first.IsInterface && !first.IsGenericParameter;
775 if ((list.Count > 0) && has_class_constr) {
776 class_constraint = (Type) list [0];
777 iface_constraints = new Type [list.Count - 1];
778 list.CopyTo (1, iface_constraints, 0, list.Count - 1);
780 iface_constraints = new Type [list.Count];
781 list.CopyTo (iface_constraints, 0);
784 if (HasValueTypeConstraint)
785 base_type = TypeManager.value_type;
786 else if (class_constraint != null)
787 base_type = class_constraint;
789 base_type = TypeManager.object_type;
792 Type inflate (Type t)
796 if (t.IsGenericParameter)
797 return dargs [t.GenericParameterPosition];
798 if (t.IsGenericInstance) {
799 t = t.GetGenericTypeDefinition ();
800 t = t.BindGenericParameters (dargs);
806 public override GenericParameterAttributes Attributes {
807 get { return gc.Attributes; }
810 public override Type ClassConstraint {
811 get { return class_constraint; }
814 public override Type EffectiveBaseClass {
815 get { return base_type; }
818 public override Type[] InterfaceConstraints {
819 get { return iface_constraints; }
825 // This type represents a generic type parameter reference.
827 // These expressions are born in a fully resolved state.
829 public class TypeParameterExpr : TypeExpr {
830 TypeParameter type_parameter;
832 public override string Name {
834 return type_parameter.Name;
838 public override string FullName {
840 return type_parameter.Name;
844 public TypeParameter TypeParameter {
846 return type_parameter;
850 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
852 this.type_parameter = type_parameter;
856 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
858 type = type_parameter.Type;
863 public override bool IsInterface {
864 get { return false; }
867 public override bool CheckAccessLevel (DeclSpace ds)
872 public void Error_CannotUseAsUnmanagedType (Location loc)
874 Report.Error (-203, loc, "Can not use type parameter as unamanged type");
878 public class TypeArguments {
879 public readonly Location Location;
886 public TypeArguments (Location loc)
888 args = new ArrayList ();
892 public TypeArguments (int dimension, Location loc)
894 this.dimension = dimension;
898 public void Add (Expression type)
901 throw new InvalidOperationException ();
906 public void Add (TypeArguments new_args)
909 throw new InvalidOperationException ();
911 args.AddRange (new_args.args);
914 public string[] GetDeclarations ()
916 string[] ret = new string [args.Count];
917 for (int i = 0; i < args.Count; i++) {
918 SimpleName sn = args [i] as SimpleName;
924 Report.Error (81, Location, "Type parameter declaration " +
925 "must be an identifier not a type");
931 public Type[] Arguments {
937 public bool HasTypeArguments {
939 return has_type_args;
952 public bool IsUnbound {
954 return dimension > 0;
958 public override string ToString ()
960 StringBuilder s = new StringBuilder ();
963 for (int i = 0; i < count; i++){
965 // FIXME: Use TypeManager.CSharpname once we have the type
968 s.Append (args [i].ToString ());
972 return s.ToString ();
975 public bool Resolve (EmitContext ec)
977 int count = args.Count;
980 atypes = new Type [count];
982 for (int i = 0; i < count; i++){
983 TypeExpr te = ((Expression) args [i]).ResolveAsTypeTerminal (ec);
988 if (te is TypeParameterExpr)
989 has_type_args = true;
991 atypes [i] = te.Type;
997 public class ConstructedType : TypeExpr {
998 string name, full_name;
1000 Type[] gen_params, atypes;
1003 public ConstructedType (string name, TypeArguments args, Location l)
1006 this.name = MemberName.MakeName (name, args.Count);
1009 eclass = ExprClass.Type;
1010 full_name = name + "<" + args.ToString () + ">";
1013 public ConstructedType (string name, TypeParameter[] type_params, Location l)
1014 : this (type_params, l)
1019 full_name = name + "<" + args.ToString () + ">";
1022 public ConstructedType (FullNamedExpression fname, TypeArguments args, Location l)
1025 this.name = fname.FullName;
1028 eclass = ExprClass.Type;
1029 full_name = name + "<" + args.ToString () + ">";
1032 protected ConstructedType (TypeArguments args, Location l)
1037 eclass = ExprClass.Type;
1040 protected ConstructedType (TypeParameter[] type_params, Location l)
1044 args = new TypeArguments (l);
1045 foreach (TypeParameter type_param in type_params)
1046 args.Add (new TypeParameterExpr (type_param, l));
1048 eclass = ExprClass.Type;
1051 public ConstructedType (Type t, TypeParameter[] type_params, Location l)
1052 : this (type_params, l)
1054 gt = t.GetGenericTypeDefinition ();
1056 this.name = gt.FullName;
1057 full_name = gt.FullName + "<" + args.ToString () + ">";
1060 public ConstructedType (Type t, TypeArguments args, Location l)
1063 gt = t.GetGenericTypeDefinition ();
1065 this.name = gt.FullName;
1066 full_name = gt.FullName + "<" + args.ToString () + ">";
1069 public TypeArguments TypeArguments {
1070 get { return args; }
1073 protected string DeclarationName {
1075 StringBuilder sb = new StringBuilder ();
1076 sb.Append (gt.FullName);
1078 for (int i = 0; i < gen_params.Length; i++) {
1081 sb.Append (gen_params [i]);
1084 return sb.ToString ();
1088 protected bool CheckConstraint (EmitContext ec, Type ptype, Expression expr,
1091 if (TypeManager.HasGenericArguments (ctype)) {
1092 Type[] types = TypeManager.GetTypeArguments (ctype);
1094 TypeArguments new_args = new TypeArguments (loc);
1096 for (int i = 0; i < types.Length; i++) {
1099 if (t.IsGenericParameter) {
1100 int pos = t.GenericParameterPosition;
1101 t = args.Arguments [pos];
1103 new_args.Add (new TypeExpression (t, loc));
1106 TypeExpr ct = new ConstructedType (ctype, new_args, loc);
1107 if (ct.ResolveAsTypeTerminal (ec) == null)
1112 return Convert.ImplicitStandardConversionExists (ec, expr, ctype);
1115 protected bool CheckConstraints (EmitContext ec, int index)
1117 Type atype = atypes [index];
1118 Type ptype = gen_params [index];
1123 Expression aexpr = new EmptyExpression (atype);
1125 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (ptype);
1130 // First, check the `class' and `struct' constraints.
1132 if (gc.HasReferenceTypeConstraint && !atype.IsClass) {
1133 Report.Error (452, loc, "The type `{0}' must be " +
1134 "a reference type in order to use it " +
1135 "as type parameter `{1}' in the " +
1136 "generic type or method `{2}'.",
1137 atype, ptype, DeclarationName);
1139 } else if (gc.HasValueTypeConstraint && !atype.IsValueType) {
1140 Report.Error (453, loc, "The type `{0}' must be " +
1141 "a value type in order to use it " +
1142 "as type parameter `{1}' in the " +
1143 "generic type or method `{2}'.",
1144 atype, ptype, DeclarationName);
1149 // The class constraint comes next.
1151 if (gc.HasClassConstraint) {
1152 if (!CheckConstraint (ec, ptype, aexpr, gc.ClassConstraint)) {
1153 Report.Error (309, loc, "The type `{0}' must be " +
1154 "convertible to `{1}' in order to " +
1155 "use it as parameter `{2}' in the " +
1156 "generic type or method `{3}'",
1157 atype, gc.ClassConstraint, ptype, DeclarationName);
1163 // Now, check the interface constraints.
1165 foreach (Type it in gc.InterfaceConstraints) {
1167 if (it.IsGenericParameter)
1168 itype = atypes [it.GenericParameterPosition];
1172 if (!CheckConstraint (ec, ptype, aexpr, itype)) {
1173 Report.Error (309, loc, "The type `{0}' must be " +
1174 "convertible to `{1}' in order to " +
1175 "use it as parameter `{2}' in the " +
1176 "generic type or method `{3}'",
1177 atype, itype, ptype, DeclarationName);
1183 // Finally, check the constructor constraint.
1186 if (!gc.HasConstructorConstraint)
1189 if (TypeManager.IsBuiltinType (atype) || atype.IsValueType)
1192 MethodGroupExpr mg = Expression.MemberLookup (
1193 ec, atype, ".ctor", MemberTypes.Constructor,
1194 BindingFlags.Public | BindingFlags.Instance |
1195 BindingFlags.DeclaredOnly, loc)
1198 if (atype.IsAbstract || (mg == null) || !mg.IsInstance) {
1199 Report.Error (310, loc, "The type `{0}' must have a public " +
1200 "parameterless constructor in order to use it " +
1201 "as parameter `{1}' in the generic type or " +
1202 "method `{2}'", atype, ptype, DeclarationName);
1209 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
1211 if (!ResolveConstructedType (ec))
1217 public bool CheckConstraints (EmitContext ec)
1219 for (int i = 0; i < gen_params.Length; i++) {
1220 if (!CheckConstraints (ec, i))
1227 public override TypeExpr ResolveAsTypeTerminal (EmitContext ec)
1229 if (base.ResolveAsTypeTerminal (ec) == null)
1232 if (!CheckConstraints (ec))
1238 public bool ResolveConstructedType (EmitContext ec)
1243 return DoResolveType (ec);
1246 // First, resolve the generic type.
1249 Type nested = ec.DeclSpace.FindNestedType (loc, name, out ds);
1250 if (nested != null) {
1251 gt = nested.GetGenericTypeDefinition ();
1253 TypeArguments new_args = new TypeArguments (loc);
1255 foreach (TypeParameter param in ds.TypeParameters)
1256 new_args.Add (new TypeParameterExpr (param, loc));
1258 new_args.Add (args);
1261 return DoResolveType (ec);
1267 SimpleName sn = new SimpleName (name, loc);
1268 TypeExpr resolved = sn.ResolveAsTypeTerminal (ec);
1269 if (resolved == null)
1274 Report.Error (246, loc, "Cannot find type `{0}'<...>",
1279 num_args = TypeManager.GetNumberOfTypeArguments (t);
1280 if (num_args == 0) {
1281 Report.Error (308, loc,
1282 "The non-generic type `{0}' cannot " +
1283 "be used with type arguments.",
1284 TypeManager.CSharpName (t));
1288 gt = t.GetGenericTypeDefinition ();
1289 return DoResolveType (ec);
1292 bool DoResolveType (EmitContext ec)
1295 // Resolve the arguments.
1297 if (args.Resolve (ec) == false)
1300 gen_params = gt.GetGenericArguments ();
1301 atypes = args.Arguments;
1303 if (atypes.Length != gen_params.Length) {
1304 Report.Error (305, loc,
1305 "Using the generic type `{0}' " +
1306 "requires {1} type arguments",
1307 TypeManager.GetFullName (gt),
1313 // Now bind the parameters.
1315 type = gt.BindGenericParameters (atypes);
1319 public Expression GetSimpleName (EmitContext ec)
1321 return new SimpleName (Basename, args, loc);
1324 public override bool CheckAccessLevel (DeclSpace ds)
1326 return ds.CheckAccessLevel (gt);
1329 public override bool AsAccessible (DeclSpace ds, int flags)
1331 return ds.AsAccessible (gt, flags);
1334 public override bool IsClass {
1335 get { return gt.IsClass; }
1338 public override bool IsValueType {
1339 get { return gt.IsValueType; }
1342 public override bool IsInterface {
1343 get { return gt.IsInterface; }
1346 public override bool IsSealed {
1347 get { return gt.IsSealed; }
1350 public override bool IsAttribute {
1351 get { return false; }
1354 public override bool Equals (object obj)
1356 ConstructedType cobj = obj as ConstructedType;
1360 if ((type == null) || (cobj.type == null))
1363 return type == cobj.type;
1366 public override int GetHashCode ()
1368 return base.GetHashCode ();
1371 public string Basename {
1373 int pos = name.LastIndexOf ('`');
1375 return name.Substring (0, pos);
1381 public override string Name {
1388 public override string FullName {
1395 public class GenericMethod : DeclSpace
1397 public GenericMethod (NamespaceEntry ns, TypeContainer parent,
1398 MemberName name, Location l)
1399 : base (ns, parent, name, null, l)
1402 public override TypeBuilder DefineType ()
1404 throw new Exception ();
1407 public override bool Define ()
1409 for (int i = 0; i < TypeParameters.Length; i++)
1410 if (!TypeParameters [i].Resolve (Parent))
1416 public bool Define (MethodBuilder mb, Type return_type)
1421 GenericTypeParameterBuilder[] gen_params;
1422 string[] names = MemberName.TypeArguments.GetDeclarations ();
1423 gen_params = mb.DefineGenericParameters (names);
1424 for (int i = 0; i < TypeParameters.Length; i++)
1425 TypeParameters [i].Define (gen_params [i]);
1427 ec = new EmitContext (
1428 this, this, Location, null, return_type, ModFlags, false);
1433 public bool DefineType (EmitContext ec, MethodBuilder mb,
1434 MethodInfo implementing, bool is_override)
1436 for (int i = 0; i < TypeParameters.Length; i++)
1437 if (!TypeParameters [i].DefineType (
1438 ec, mb, implementing, is_override))
1444 public override bool DefineMembers (TypeContainer parent)
1449 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
1450 MemberFilter filter, object criteria)
1452 throw new Exception ();
1455 public override MemberCache MemberCache {
1461 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
1466 protected override void VerifyObsoleteAttribute()
1471 public override AttributeTargets AttributeTargets {
1473 return AttributeTargets.Method | AttributeTargets.ReturnValue;
1477 public override string DocCommentHeader {
1478 get { return "M:"; }
1482 public class DefaultValueExpression : Expression
1485 LocalTemporary temp_storage;
1487 public DefaultValueExpression (Expression expr, Location loc)
1493 public override Expression DoResolve (EmitContext ec)
1495 TypeExpr texpr = expr.ResolveAsTypeTerminal (ec);
1500 if (type.IsGenericParameter || TypeManager.IsValueType (type))
1501 temp_storage = new LocalTemporary (ec, type);
1503 eclass = ExprClass.Variable;
1507 public override void Emit (EmitContext ec)
1509 if (temp_storage != null) {
1510 temp_storage.AddressOf (ec, AddressOp.LoadStore);
1511 ec.ig.Emit (OpCodes.Initobj, type);
1512 temp_storage.Emit (ec);
1514 ec.ig.Emit (OpCodes.Ldnull);
1518 public partial class TypeManager
1521 // A list of core types that the compiler requires or uses
1523 static public Type new_constraint_attr_type;
1524 static public Type activator_type;
1525 static public Type generic_ienumerator_type;
1526 static public Type generic_ienumerable_type;
1529 // Tracks the generic parameters.
1531 static PtrHashtable builder_to_type_param;
1534 // These methods are called by code generated by the compiler
1536 static public MethodInfo activator_create_instance;
1538 static void InitGenerics ()
1540 builder_to_type_param = new PtrHashtable ();
1543 static void CleanUpGenerics ()
1545 builder_to_type_param = null;
1548 static void InitGenericCoreTypes ()
1550 activator_type = CoreLookupType ("System.Activator");
1551 new_constraint_attr_type = CoreLookupType (
1552 "System.Runtime.CompilerServices.NewConstraintAttribute");
1554 generic_ienumerator_type = CoreLookupType (
1555 MemberName.MakeName ("System.Collections.Generic.IEnumerator", 1));
1556 generic_ienumerable_type = CoreLookupType (
1557 MemberName.MakeName ("System.Collections.Generic.IEnumerable", 1));
1560 static void InitGenericCodeHelpers ()
1563 Type [] type_arg = { type_type };
1564 activator_create_instance = GetMethod (
1565 activator_type, "CreateInstance", type_arg);
1568 public static void AddTypeParameter (Type t, TypeParameter tparam)
1570 if (!builder_to_type_param.Contains (t))
1571 builder_to_type_param.Add (t, tparam);
1574 public static TypeContainer LookupGenericTypeContainer (Type t)
1576 while (t.IsGenericInstance)
1577 t = t.GetGenericTypeDefinition ();
1579 return LookupTypeContainer (t);
1582 public static TypeParameter LookupTypeParameter (Type t)
1584 return (TypeParameter) builder_to_type_param [t];
1587 public static bool HasConstructorConstraint (Type t)
1589 GenericConstraints gc = GetTypeParameterConstraints (t);
1593 return (gc.Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0;
1596 public static GenericConstraints GetTypeParameterConstraints (Type t)
1598 if (!t.IsGenericParameter)
1599 throw new InvalidOperationException ();
1601 TypeParameter tparam = LookupTypeParameter (t);
1603 return tparam.GenericConstraints;
1605 return new ReflectionConstraints (t);
1608 public static bool IsGeneric (Type t)
1610 DeclSpace ds = (DeclSpace) builder_to_declspace [t];
1612 return ds.IsGeneric;
1615 public static bool HasGenericArguments (Type t)
1617 return GetNumberOfTypeArguments (t) > 0;
1620 public static int GetNumberOfTypeArguments (Type t)
1622 DeclSpace tc = LookupDeclSpace (t);
1624 return tc.IsGeneric ? tc.CountTypeParameters : 0;
1626 return t.HasGenericArguments ? t.GetGenericArguments ().Length : 0;
1629 public static Type[] GetTypeArguments (Type t)
1631 DeclSpace tc = LookupDeclSpace (t);
1634 return Type.EmptyTypes;
1636 TypeParameter[] tparam = tc.TypeParameters;
1637 Type[] ret = new Type [tparam.Length];
1638 for (int i = 0; i < tparam.Length; i++) {
1639 ret [i] = tparam [i].Type;
1640 if (ret [i] == null)
1641 throw new InternalErrorException ();
1646 return t.GetGenericArguments ();
1649 public static bool IsEqual (Type a, Type b)
1654 if ((a is TypeBuilder) && a.IsGenericTypeDefinition && b.IsGenericInstance) {
1656 // `a' is a generic type definition's TypeBuilder and `b' is a
1657 // generic instance of the same type.
1663 // void Test (Stack<T> stack) { }
1666 // The first argument of `Test' will be the generic instance
1667 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
1670 // We hit this via Closure.Filter() for gen-82.cs.
1672 if (a != b.GetGenericTypeDefinition ())
1675 Type[] aparams = a.GetGenericArguments ();
1676 Type[] bparams = b.GetGenericArguments ();
1678 if (aparams.Length != bparams.Length)
1681 for (int i = 0; i < aparams.Length; i++)
1682 if (!IsEqual (aparams [i], bparams [i]))
1688 if (a.IsGenericParameter && b.IsGenericParameter) {
1689 if ((a.DeclaringMethod == null) || (b.DeclaringMethod == null))
1691 return a.GenericParameterPosition == b.GenericParameterPosition;
1694 if (a.IsArray && b.IsArray) {
1695 if (a.GetArrayRank () != b.GetArrayRank ())
1697 return IsEqual (a.GetElementType (), b.GetElementType ());
1700 if (a.IsGenericInstance && b.IsGenericInstance) {
1701 if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1704 Type[] aargs = a.GetGenericArguments ();
1705 Type[] bargs = b.GetGenericArguments ();
1707 if (aargs.Length != bargs.Length)
1710 for (int i = 0; i < aargs.Length; i++) {
1711 if (!IsEqual (aargs [i], bargs [i]))
1721 public static bool MayBecomeEqualGenericTypes (Type a, Type b, Type[] class_infered, Type[] method_infered)
1723 if (a.IsGenericParameter) {
1725 // If a is an array of a's type, they may never
1729 b = b.GetElementType ();
1735 // If b is a generic parameter or an actual type,
1736 // they may become equal:
1738 // class X<T,U> : I<T>, I<U>
1739 // class X<T> : I<T>, I<float>
1741 if (b.IsGenericParameter || !b.IsGenericInstance) {
1742 int pos = a.GenericParameterPosition;
1743 Type[] args = a.DeclaringMethod != null ? method_infered : class_infered;
1744 if (args [pos] == null) {
1749 return args [pos] == a;
1753 // We're now comparing a type parameter with a
1754 // generic instance. They may become equal unless
1755 // the type parameter appears anywhere in the
1756 // generic instance:
1758 // class X<T,U> : I<T>, I<X<U>>
1759 // -> error because you could instanciate it as
1762 // class X<T> : I<T>, I<X<T>> -> ok
1765 Type[] bargs = GetTypeArguments (b);
1766 for (int i = 0; i < bargs.Length; i++) {
1767 if (a.Equals (bargs [i]))
1774 if (b.IsGenericParameter)
1775 return MayBecomeEqualGenericTypes (b, a, class_infered, method_infered);
1778 // At this point, neither a nor b are a type parameter.
1780 // If one of them is a generic instance, let
1781 // MayBecomeEqualGenericInstances() compare them (if the
1782 // other one is not a generic instance, they can never
1786 if (a.IsGenericInstance || b.IsGenericInstance)
1787 return MayBecomeEqualGenericInstances (a, b, class_infered, method_infered);
1790 // If both of them are arrays.
1793 if (a.IsArray && b.IsArray) {
1794 if (a.GetArrayRank () != b.GetArrayRank ())
1797 a = a.GetElementType ();
1798 b = b.GetElementType ();
1800 return MayBecomeEqualGenericTypes (a, b, class_infered, method_infered);
1804 // Ok, two ordinary types.
1807 return a.Equals (b);
1811 // Checks whether two generic instances may become equal for some
1812 // particular instantiation (26.3.1).
1814 public static bool MayBecomeEqualGenericInstances (Type a, Type b,
1815 Type[] class_infered, Type[] method_infered)
1817 if (!a.IsGenericInstance || !b.IsGenericInstance)
1819 if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1822 return MayBecomeEqualGenericInstances (
1823 GetTypeArguments (a), GetTypeArguments (b), class_infered, method_infered);
1826 public static bool MayBecomeEqualGenericInstances (Type[] aargs, Type[] bargs,
1827 Type[] class_infered, Type[] method_infered)
1829 if (aargs.Length != bargs.Length)
1832 for (int i = 0; i < aargs.Length; i++) {
1833 if (!MayBecomeEqualGenericTypes (aargs [i], bargs [i], class_infered, method_infered))
1840 public static bool IsEqualGenericInstance (Type type, Type parent)
1842 int tcount = GetNumberOfTypeArguments (type);
1843 int pcount = GetNumberOfTypeArguments (parent);
1845 if (type.IsGenericInstance)
1846 type = type.GetGenericTypeDefinition ();
1847 if (parent.IsGenericInstance)
1848 parent = parent.GetGenericTypeDefinition ();
1850 if (tcount != pcount)
1853 return type.Equals (parent);
1856 static public bool IsGenericMethod (MethodBase mb)
1858 if (mb.DeclaringType is TypeBuilder) {
1859 IMethodData method = (IMethodData) builder_to_method [mb];
1863 return method.GenericMethod != null;
1866 return mb.IsGenericMethodDefinition;
1873 static bool InferType (Type pt, Type at, Type[] infered)
1875 if (pt.IsGenericParameter && (pt.DeclaringMethod != null)) {
1876 int pos = pt.GenericParameterPosition;
1878 if (infered [pos] == null) {
1880 while (check.IsArray)
1881 check = check.GetElementType ();
1890 if (infered [pos] != at)
1896 if (!pt.ContainsGenericParameters) {
1897 if (at.ContainsGenericParameters)
1898 return InferType (at, pt, infered);
1905 (at.GetArrayRank () != pt.GetArrayRank ()))
1908 return InferType (pt.GetElementType (), at.GetElementType (), infered);
1913 (pt.GetArrayRank () != at.GetArrayRank ()))
1916 return InferType (pt.GetElementType (), at.GetElementType (), infered);
1919 if (pt.IsByRef && at.IsByRef)
1920 return InferType (pt.GetElementType (), at.GetElementType (), infered);
1921 ArrayList list = new ArrayList ();
1922 if (at.IsGenericInstance)
1925 for (Type bt = at.BaseType; bt != null; bt = bt.BaseType)
1928 list.AddRange (TypeManager.GetInterfaces (at));
1931 bool found_one = false;
1933 foreach (Type type in list) {
1934 if (!type.IsGenericInstance)
1937 Type[] infered_types = new Type [infered.Length];
1939 if (!InferGenericInstance (pt, type, infered_types))
1942 for (int i = 0; i < infered_types.Length; i++) {
1943 if (infered [i] == null) {
1944 infered [i] = infered_types [i];
1948 if (infered [i] != infered_types [i])
1958 static bool InferGenericInstance (Type pt, Type at, Type[] infered_types)
1960 Type[] at_args = at.GetGenericArguments ();
1961 Type[] pt_args = pt.GetGenericArguments ();
1963 if (at_args.Length != pt_args.Length)
1966 for (int i = 0; i < at_args.Length; i++) {
1967 if (!InferType (pt_args [i], at_args [i], infered_types))
1971 for (int i = 0; i < infered_types.Length; i++) {
1972 if (infered_types [i] == null)
1979 public static bool InferParamsTypeArguments (EmitContext ec, ArrayList arguments,
1980 ref MethodBase method)
1982 if ((arguments == null) || !TypeManager.IsGenericMethod (method))
1987 if (arguments == null)
1990 arg_count = arguments.Count;
1992 ParameterData pd = Invocation.GetParameterData (method);
1994 int pd_count = pd.Count;
1999 if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
2002 if (pd_count - 1 > arg_count)
2005 if (pd_count == 1 && arg_count == 0)
2008 Type[] method_args = method.GetGenericArguments ();
2009 Type[] infered_types = new Type [method_args.Length];
2012 // If we have come this far, the case which
2013 // remains is when the number of parameters is
2014 // less than or equal to the argument count.
2016 for (int i = 0; i < pd_count - 1; ++i) {
2017 Argument a = (Argument) arguments [i];
2019 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
2022 Type pt = pd.ParameterType (i);
2025 if (!InferType (pt, at, infered_types))
2029 Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
2031 for (int i = pd_count - 1; i < arg_count; i++) {
2032 Argument a = (Argument) arguments [i];
2034 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
2037 if (!InferType (element_type, a.Type, infered_types))
2041 for (int i = 0; i < infered_types.Length; i++)
2042 if (infered_types [i] == null)
2045 method = method.BindGenericParameters (infered_types);
2049 public static bool InferTypeArguments (Type[] param_types, Type[] arg_types, Type[] infered_types)
2051 if (infered_types == null)
2054 for (int i = 0; i < arg_types.Length; i++) {
2055 if (arg_types [i] == null)
2058 if (!InferType (param_types [i], arg_types [i], infered_types))
2062 for (int i = 0; i < infered_types.Length; i++)
2063 if (infered_types [i] == null)
2069 public static bool InferTypeArguments (EmitContext ec, ArrayList arguments,
2070 ref MethodBase method)
2072 if (!TypeManager.IsGenericMethod (method))
2076 if (arguments != null)
2077 arg_count = arguments.Count;
2081 ParameterData pd = Invocation.GetParameterData (method);
2082 if (arg_count != pd.Count)
2085 Type[] method_args = method.GetGenericArguments ();
2087 bool is_open = false;
2088 for (int i = 0; i < method_args.Length; i++) {
2089 if (method_args [i].IsGenericParameter) {
2097 Type[] infered_types = new Type [method_args.Length];
2099 Type[] param_types = new Type [pd.Count];
2100 Type[] arg_types = new Type [pd.Count];
2102 for (int i = 0; i < arg_count; i++) {
2103 param_types [i] = pd.ParameterType (i);
2105 Argument a = (Argument) arguments [i];
2106 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
2109 arg_types [i] = a.Type;
2112 if (!InferTypeArguments (param_types, arg_types, infered_types))
2115 method = method.BindGenericParameters (infered_types);
2119 public static bool InferTypeArguments (EmitContext ec, ParameterData apd,
2120 ref MethodBase method)
2122 if (!TypeManager.IsGenericMethod (method))
2125 ParameterData pd = Invocation.GetParameterData (method);
2126 if (apd.Count != pd.Count)
2129 Type[] method_args = method.GetGenericArguments ();
2130 Type[] infered_types = new Type [method_args.Length];
2132 Type[] param_types = new Type [pd.Count];
2133 Type[] arg_types = new Type [pd.Count];
2135 for (int i = 0; i < apd.Count; i++) {
2136 param_types [i] = pd.ParameterType (i);
2137 arg_types [i] = apd.ParameterType (i);
2140 if (!InferTypeArguments (param_types, arg_types, infered_types))
2143 method = method.BindGenericParameters (infered_types);