2 // generic.cs: Support classes for generics
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2003 Ximian, Inc.
10 using System.Reflection;
11 using System.Reflection.Emit;
12 using System.Globalization;
13 using System.Collections;
16 namespace Mono.CSharp {
18 public enum SpecialConstraint
26 // Tracks the constraints for a type parameter
28 public class Constraints : GenericConstraints {
30 ArrayList constraints;
34 // name is the identifier, constraints is an arraylist of
35 // Expressions (with types) or `true' for the constructor constraint.
37 public Constraints (string name, ArrayList constraints,
41 this.constraints = constraints;
45 public string TypeParameter {
51 bool has_ctor_constraint;
52 bool has_reference_type;
54 TypeExpr class_constraint;
55 ArrayList iface_constraints;
56 int num_constraints, first_constraint;
57 Type class_constraint_type;
58 Type[] iface_constraint_types;
60 public bool HasConstructorConstraint {
61 get { return has_ctor_constraint; }
64 public bool Resolve (DeclSpace ds)
66 iface_constraints = new ArrayList ();
68 foreach (object obj in constraints) {
69 if (has_ctor_constraint) {
70 Report.Error (401, loc,
71 "The new() constraint must be last.");
75 if (obj is SpecialConstraint) {
76 SpecialConstraint sc = (SpecialConstraint) obj;
78 if (sc == SpecialConstraint.Constructor) {
79 if (!has_value_type) {
80 has_ctor_constraint = true;
85 451, loc, "The new () constraint " +
86 "cannot be used with the `struct' " +
91 if ((num_constraints > 0) || has_reference_type ||
93 Report.Error (449, loc,
94 "The `class' or `struct' " +
95 "constraint must be first");
99 if (sc == SpecialConstraint.ReferenceType)
100 has_reference_type = true;
102 has_value_type = true;
106 TypeExpr expr = ds.ResolveTypeExpr ((Expression) obj, false, loc);
110 if (expr is TypeParameterExpr) {
111 Report.Error (700, loc,
112 "`{0}': naked type parameters cannot " +
113 "be used as bounds", expr.Name);
117 if (expr.IsInterface)
118 iface_constraints.Add (expr);
119 else if (class_constraint != null) {
120 Report.Error (406, loc,
121 "`{0}': the class constraint for `{1}' " +
122 "must come before any other constraints.",
125 } else if (has_reference_type || has_value_type) {
126 Report.Error (450, loc, "`{0}': cannot specify both " +
127 "a constraint class and the `class' " +
128 "or `struct' constraint.", expr.Name);
131 class_constraint = expr;
139 public TypeExpr[] InterfaceConstraints {
141 TypeExpr[] ifaces = new TypeExpr [iface_constraints.Count];
142 iface_constraints.CopyTo (ifaces, 0);
147 public bool ResolveTypes (EmitContext ec)
149 iface_constraint_types = new Type [iface_constraints.Count];
151 for (int i = 0; i < iface_constraints.Count; i++) {
152 TypeExpr iface_constraint = (TypeExpr) iface_constraints [i];
153 Type resolved = iface_constraint.ResolveType (ec);
154 if (resolved == null)
157 for (int j = 0; j < i; j++) {
158 if (!iface_constraint_types [j].Equals (resolved))
161 Report.Error (405, loc,
162 "Duplicate constraint `{0}' for type " +
163 "parameter `{1}'.", resolved, name);
167 iface_constraint_types [i] = resolved;
170 if (class_constraint != null) {
171 class_constraint_type = class_constraint.ResolveType (ec);
172 if (class_constraint_type == null)
175 if (class_constraint_type.IsSealed) {
176 Report.Error (701, loc,
177 "`{0}' is not a valid bound. Bounds " +
178 "must be interfaces or non sealed " +
179 "classes", class_constraint_type);
183 if ((class_constraint_type == TypeManager.array_type) ||
184 (class_constraint_type == TypeManager.delegate_type) ||
185 (class_constraint_type == TypeManager.enum_type) ||
186 (class_constraint_type == TypeManager.value_type) ||
187 (class_constraint_type == TypeManager.object_type)) {
188 Report.Error (702, loc,
189 "Bound cannot be special class `{0}'",
190 class_constraint_type);
195 if (has_reference_type)
196 class_constraint_type = TypeManager.object_type;
197 else if (has_value_type)
198 class_constraint_type = TypeManager.value_type;
203 public void Define (GenericTypeParameterBuilder type)
205 if (has_ctor_constraint)
206 type.Mono_SetConstructorConstraint ();
207 if (has_reference_type)
208 type.Mono_SetReferenceTypeConstraint ();
209 else if (has_value_type)
210 type.Mono_SetValueTypeConstraint ();
213 bool GenericConstraints.HasConstructor {
214 get { return has_ctor_constraint; }
217 bool GenericConstraints.IsReferenceType {
218 get { return has_reference_type; }
221 bool GenericConstraints.IsValueType {
222 get { return has_value_type; }
225 bool GenericConstraints.HasClassConstraint {
226 get { return class_constraint_type != null; }
229 Type GenericConstraints.ClassConstraint {
230 get { return class_constraint_type; }
233 Type[] GenericConstraints.InterfaceConstraints {
234 get { return iface_constraint_types; }
239 // This type represents a generic type parameter
241 public class TypeParameter : IMemberContainer {
243 Constraints constraints;
245 GenericTypeParameterBuilder type;
247 public TypeParameter (string name, Constraints constraints, Location loc)
250 this.constraints = constraints;
260 public Location Location {
266 public Constraints Constraints {
272 public bool HasConstructorConstraint {
274 if (constraints != null)
275 return constraints.HasConstructorConstraint;
287 public bool Resolve (DeclSpace ds)
289 if (constraints != null)
290 return constraints.Resolve (ds);
295 public void Define (GenericTypeParameterBuilder type)
298 TypeExpr[] ifaces = null;
299 if (constraints != null) {
300 ifaces = constraints.InterfaceConstraints;
301 constraints.Define (type);
303 TypeManager.AddTypeParameter (type, this, ifaces);
306 public bool DefineType (EmitContext ec)
308 if (constraints != null) {
309 if (!constraints.ResolveTypes (ec))
312 GenericConstraints gc = (GenericConstraints) constraints;
314 if (gc.HasClassConstraint)
315 type.SetBaseTypeConstraint (gc.ClassConstraint);
317 type.SetInterfaceConstraints (gc.InterfaceConstraints);
327 IMemberContainer IMemberContainer.Parent {
331 bool IMemberContainer.IsInterface {
335 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
337 return FindMembers (mt, bf, null, null);
340 MemberCache IMemberContainer.MemberCache {
344 public MemberList FindMembers (MemberTypes mt, BindingFlags bf,
345 MemberFilter filter, object criteria)
347 if (constraints == null)
348 return MemberList.Empty;
350 ArrayList members = new ArrayList ();
352 GenericConstraints gc = (GenericConstraints) constraints;
354 if (gc.HasClassConstraint) {
355 MemberList list = TypeManager.FindMembers (
356 gc.ClassConstraint, mt, bf, filter, criteria);
358 members.AddRange (list);
361 foreach (Type t in gc.InterfaceConstraints) {
362 MemberList list = TypeManager.FindMembers (
363 t, mt, bf, filter, criteria);
365 members.AddRange (list);
368 return new MemberList (members);
371 public override string ToString ()
373 return "TypeParameter[" + name + "]";
378 // This type represents a generic type parameter reference.
380 // These expressions are born in a fully resolved state.
382 public class TypeParameterExpr : TypeExpr {
383 TypeParameter type_parameter;
385 public override string Name {
387 return type_parameter.Name;
391 public TypeParameter TypeParameter {
393 return type_parameter;
397 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
399 this.type_parameter = type_parameter;
403 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
405 type = type_parameter.Type;
410 public void Error_CannotUseAsUnmanagedType (Location loc)
412 Report.Error (-203, loc, "Can not use type parameter as unamanged type");
416 public class TypeArguments {
417 public readonly Location Location;
423 public TypeArguments (Location loc)
425 args = new ArrayList ();
429 public void Add (Expression type)
432 throw new InvalidOperationException ();
437 public void Add (TypeArguments new_args)
440 throw new InvalidOperationException ();
442 args.AddRange (new_args.args);
445 public string[] GetDeclarations ()
447 string[] ret = new string [args.Count];
448 for (int i = 0; i < args.Count; i++) {
449 SimpleName sn = args [i] as SimpleName;
455 Report.Error (81, Location, "Type parameter declaration " +
456 "must be an identifier not a type");
462 public Type[] Arguments {
468 public bool HasTypeArguments {
470 return has_type_args;
480 public override string ToString ()
482 StringBuilder s = new StringBuilder ();
484 int count = args.Count;
485 for (int i = 0; i < count; i++){
487 // FIXME: Use TypeManager.CSharpname once we have the type
489 s.Append (args [i].ToString ());
493 return s.ToString ();
496 public bool Resolve (EmitContext ec)
498 DeclSpace ds = ec.DeclSpace;
499 int count = args.Count;
502 atypes = new Type [count];
504 for (int i = 0; i < count; i++){
505 TypeExpr te = ds.ResolveTypeExpr (
506 (Expression) args [i], false, Location);
511 if (te is TypeParameterExpr)
512 has_type_args = true;
513 atypes [i] = te.ResolveType (ec);
515 if (atypes [i] == null) {
516 Report.Error (246, Location, "Cannot find type `{0}'",
525 public class ConstructedType : TypeExpr {
526 string name, full_name;
528 Type[] gen_params, atypes;
531 public ConstructedType (string name, TypeArguments args, Location l)
534 this.name = name + "!" + args.Count;
537 eclass = ExprClass.Type;
538 full_name = name + "<" + args.ToString () + ">";
541 public ConstructedType (string name, TypeParameter[] type_params, Location l)
542 : this (type_params, l)
547 full_name = name + "<" + args.ToString () + ">";
550 protected ConstructedType (TypeArguments args, Location l)
555 eclass = ExprClass.Type;
558 protected ConstructedType (TypeParameter[] type_params, Location l)
562 args = new TypeArguments (l);
563 foreach (TypeParameter type_param in type_params)
564 args.Add (new TypeParameterExpr (type_param, l));
566 eclass = ExprClass.Type;
569 public ConstructedType (Type t, TypeParameter[] type_params, Location l)
570 : this (type_params, l)
572 gt = t.GetGenericTypeDefinition ();
574 this.name = gt.FullName;
575 full_name = gt.FullName + "<" + args.ToString () + ">";
578 public ConstructedType (Type t, TypeArguments args, Location l)
581 gt = t.GetGenericTypeDefinition ();
583 this.name = gt.FullName;
584 full_name = gt.FullName + "<" + args.ToString () + ">";
587 public TypeArguments TypeArguments {
591 protected string DeclarationName {
593 StringBuilder sb = new StringBuilder ();
594 sb.Append (gt.FullName);
596 for (int i = 0; i < gen_params.Length; i++) {
599 sb.Append (gen_params [i]);
602 return sb.ToString ();
606 protected bool CheckConstraints (EmitContext ec, int index)
608 Type atype = atypes [index];
609 Type ptype = gen_params [index];
614 Expression aexpr = new EmptyExpression (atype);
616 Type parent = ptype.BaseType;
619 // First, check the `class' and `struct' constraints.
621 if (parent == TypeManager.object_type) {
622 if (!atype.IsClass) {
623 Report.Error (452, loc, "The type `{0}' must be " +
624 "a reference type in order to use it " +
625 "as type parameter `{1}' in the " +
626 "generic type or method `{2}'.",
627 atype, ptype, DeclarationName);
630 } else if (parent == TypeManager.value_type) {
631 if (!atype.IsValueType) {
632 Report.Error (453, loc, "The type `{0}' must be " +
633 "a value type in order to use it " +
634 "as type parameter `{1}' in the " +
635 "generic type or method `{2}'.",
636 atype, ptype, DeclarationName);
642 // The class constraint comes next.
644 if ((parent != null) && (parent != TypeManager.object_type)) {
645 if (!Convert.ImplicitStandardConversionExists (aexpr, parent)) {
646 Report.Error (309, loc, "The type `{0}' must be " +
647 "convertible to `{1}' in order to " +
648 "use it as parameter `{2}' in the " +
649 "generic type or method `{3}'",
650 atype, parent, ptype, DeclarationName);
656 // Now, check the interface constraints.
658 foreach (TypeExpr iface in TypeManager.GetInterfaces (ptype)) {
659 Type itype = iface.ResolveType (ec);
663 if (!Convert.ImplicitStandardConversionExists (aexpr, itype)) {
664 Report.Error (309, loc, "The type `{0}' must be " +
665 "convertible to `{1}' in order to " +
666 "use it as parameter `{2}' in the " +
667 "generic type or method `{3}'",
668 atype, itype, ptype, DeclarationName);
674 // Finally, check the constructor constraint.
677 if (!TypeManager.HasConstructorConstraint (ptype))
680 MethodGroupExpr mg = Expression.MemberLookup (
681 ec, atype, ".ctor", MemberTypes.Constructor,
682 BindingFlags.Public | BindingFlags.Instance |
683 BindingFlags.DeclaredOnly, loc)
686 if (atype.IsAbstract || (mg == null) || !mg.IsInstance) {
687 Report.Error (310, loc, "The type `{0}' must have a public " +
688 "parameterless constructor in order to use it " +
689 "as parameter `{1}' in the generic type or " +
690 "method `{2}'", atype, ptype, DeclarationName);
697 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
703 // First, resolve the generic type.
706 Type nested = ec.DeclSpace.FindNestedType (loc, name, out ds);
707 if (nested != null) {
708 gt = nested.GetGenericTypeDefinition ();
710 TypeArguments new_args = new TypeArguments (loc);
711 foreach (TypeParameter param in ds.TypeParameters)
712 new_args.Add (new TypeParameterExpr (param, loc));
722 SimpleName sn = new SimpleName (name, loc);
723 TypeExpr resolved = sn.ResolveAsTypeTerminal (ec);
724 if ((resolved == null) || (resolved.Type == null)) {
725 Report.Error (246, loc,
726 "The type or namespace name `{0}<...>' "+
727 "could not be found", Basename);
733 Report.Error (246, loc, "Cannot find type `{0}'<...>",
738 num_args = TypeManager.GetNumberOfTypeArguments (t);
740 Report.Error (308, loc,
741 "The non-generic type `{0}' cannot " +
742 "be used with type arguments.",
743 TypeManager.CSharpName (t));
747 gt = t.GetGenericTypeDefinition ();
751 public override Type ResolveType (EmitContext ec)
755 if (DoResolveAsTypeStep (ec) == null)
759 // Resolve the arguments.
761 if (args.Resolve (ec) == false)
764 gen_params = gt.GetGenericArguments ();
765 atypes = args.Arguments;
767 if (atypes.Length != gen_params.Length) {
768 Report.Error (305, loc,
769 "Using the generic type `{0}' " +
770 "requires {1} type arguments",
771 TypeManager.GetFullName (gt),
776 for (int i = 0; i < gen_params.Length; i++) {
777 if (!CheckConstraints (ec, i))
782 // Now bind the parameters.
784 type = gt.BindGenericParameters (atypes);
788 public Expression GetSimpleName (EmitContext ec)
790 return new SimpleName (Basename, args, loc);
793 public override bool CheckAccessLevel (DeclSpace ds)
795 return ds.CheckAccessLevel (gt);
798 public override bool AsAccessible (DeclSpace ds, int flags)
800 return ds.AsAccessible (gt, flags);
803 public override bool IsClass {
804 get { return gt.IsClass; }
807 public override bool IsValueType {
808 get { return gt.IsValueType; }
811 public override bool IsInterface {
812 get { return gt.IsInterface; }
815 public override bool IsSealed {
816 get { return gt.IsSealed; }
819 public override bool IsAttribute {
820 get { return false; }
823 public override TypeExpr[] GetInterfaces ()
825 TypeExpr[] ifaces = TypeManager.GetInterfaces (gt);
829 public override bool Equals (object obj)
831 ConstructedType cobj = obj as ConstructedType;
835 if ((type == null) || (cobj.type == null))
838 return type == cobj.type;
841 public string Basename {
843 int pos = name.LastIndexOf ('!');
845 return name.Substring (0, pos);
851 public override string Name {
858 public class GenericMethod : DeclSpace
860 public GenericMethod (NamespaceEntry ns, TypeContainer parent,
861 MemberName name, Attributes attrs, Location l)
862 : base (ns, parent, name, attrs, l)
865 public override TypeBuilder DefineType ()
867 throw new Exception ();
870 public override bool Define (TypeContainer parent)
872 for (int i = 0; i < TypeParameters.Length; i++)
873 if (!TypeParameters [i].Resolve (parent))
879 public bool Define (TypeContainer parent, MethodBuilder mb)
881 if (!Define (parent))
884 GenericTypeParameterBuilder[] gen_params;
885 gen_params = mb.DefineGenericParameters (MemberName.TypeParameters);
886 for (int i = 0; i < TypeParameters.Length; i++)
887 TypeParameters [i].Define (gen_params [i]);
892 public bool DefineType (EmitContext ec, MethodBuilder mb)
894 for (int i = 0; i < TypeParameters.Length; i++)
895 if (!TypeParameters [i].DefineType (ec))
901 public override bool DefineMembers (TypeContainer parent)
906 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
907 MemberFilter filter, object criteria)
909 throw new Exception ();
912 public override MemberCache MemberCache {
914 throw new Exception ();
918 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
923 protected override void VerifyObsoleteAttribute()
928 public override AttributeTargets AttributeTargets {
930 return AttributeTargets.Method | AttributeTargets.ReturnValue;
935 public class DefaultValueExpression : Expression
938 LocalTemporary temp_storage;
940 public DefaultValueExpression (Expression expr, Location loc)
946 public override Expression DoResolve (EmitContext ec)
948 type = ec.DeclSpace.ResolveType (expr, false, loc);
952 if (type.IsGenericParameter || TypeManager.IsValueType (type))
953 temp_storage = new LocalTemporary (ec, type);
955 eclass = ExprClass.Variable;
959 public override void Emit (EmitContext ec)
961 if (temp_storage != null) {
962 temp_storage.AddressOf (ec, AddressOp.LoadStore);
963 ec.ig.Emit (OpCodes.Initobj, type);
964 temp_storage.Emit (ec);
966 ec.ig.Emit (OpCodes.Ldnull);