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.HasClassConstraint {
218 get { return class_constraint_type != null; }
221 Type GenericConstraints.ClassConstraint {
222 get { return class_constraint_type; }
225 Type[] GenericConstraints.InterfaceConstraints {
226 get { return iface_constraint_types; }
231 // This type represents a generic type parameter
233 public class TypeParameter : IMemberContainer {
235 Constraints constraints;
237 GenericTypeParameterBuilder type;
239 public TypeParameter (string name, Constraints constraints, Location loc)
242 this.constraints = constraints;
252 public Location Location {
258 public Constraints Constraints {
264 public bool HasConstructorConstraint {
266 if (constraints != null)
267 return constraints.HasConstructorConstraint;
279 public bool Resolve (DeclSpace ds)
281 if (constraints != null)
282 return constraints.Resolve (ds);
287 public void Define (GenericTypeParameterBuilder type)
290 TypeExpr[] ifaces = null;
291 if (constraints != null) {
292 ifaces = constraints.InterfaceConstraints;
293 constraints.Define (type);
295 TypeManager.AddTypeParameter (type, this, ifaces);
298 public bool DefineType (EmitContext ec)
300 if (constraints != null) {
301 if (!constraints.ResolveTypes (ec))
304 GenericConstraints gc = (GenericConstraints) constraints;
306 if (gc.HasClassConstraint)
307 type.SetBaseTypeConstraint (gc.ClassConstraint);
309 type.SetInterfaceConstraints (gc.InterfaceConstraints);
319 IMemberContainer IMemberContainer.Parent {
323 bool IMemberContainer.IsInterface {
327 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
329 return FindMembers (mt, bf, null, null);
332 MemberCache IMemberContainer.MemberCache {
336 public MemberList FindMembers (MemberTypes mt, BindingFlags bf,
337 MemberFilter filter, object criteria)
339 if (constraints == null)
340 return MemberList.Empty;
342 ArrayList members = new ArrayList ();
344 GenericConstraints gc = (GenericConstraints) constraints;
346 if (gc.HasClassConstraint) {
347 MemberList list = TypeManager.FindMembers (
348 gc.ClassConstraint, mt, bf, filter, criteria);
350 members.AddRange (list);
353 foreach (Type t in gc.InterfaceConstraints) {
354 MemberList list = TypeManager.FindMembers (
355 t, mt, bf, filter, criteria);
357 members.AddRange (list);
360 return new MemberList (members);
363 public override string ToString ()
365 return "TypeParameter[" + name + "]";
370 // This type represents a generic type parameter reference.
372 // These expressions are born in a fully resolved state.
374 public class TypeParameterExpr : TypeExpr {
375 TypeParameter type_parameter;
377 public override string Name {
379 return type_parameter.Name;
383 public TypeParameter TypeParameter {
385 return type_parameter;
389 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
391 this.type_parameter = type_parameter;
395 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
397 type = type_parameter.Type;
402 public void Error_CannotUseAsUnmanagedType (Location loc)
404 Report.Error (-203, loc, "Can not use type parameter as unamanged type");
408 public class TypeArguments {
409 public readonly Location Location;
415 public TypeArguments (Location loc)
417 args = new ArrayList ();
421 public void Add (Expression type)
424 throw new InvalidOperationException ();
429 public void Add (TypeArguments new_args)
432 throw new InvalidOperationException ();
434 args.AddRange (new_args.args);
437 public string[] GetDeclarations ()
439 string[] ret = new string [args.Count];
440 for (int i = 0; i < args.Count; i++) {
441 SimpleName sn = args [i] as SimpleName;
447 Report.Error (81, Location, "Type parameter declaration " +
448 "must be an identifier not a type");
454 public Type[] Arguments {
460 public bool HasTypeArguments {
462 return has_type_args;
472 public override string ToString ()
474 StringBuilder s = new StringBuilder ();
476 int count = args.Count;
477 for (int i = 0; i < count; i++){
479 // FIXME: Use TypeManager.CSharpname once we have the type
481 s.Append (args [i].ToString ());
485 return s.ToString ();
488 public bool Resolve (EmitContext ec)
490 DeclSpace ds = ec.DeclSpace;
491 int count = args.Count;
494 atypes = new Type [count];
496 for (int i = 0; i < count; i++){
497 TypeExpr te = ds.ResolveTypeExpr (
498 (Expression) args [i], false, Location);
503 if (te is TypeParameterExpr)
504 has_type_args = true;
505 atypes [i] = te.ResolveType (ec);
507 if (atypes [i] == null) {
508 Report.Error (246, Location, "Cannot find type `{0}'",
517 public class ConstructedType : TypeExpr {
518 string name, full_name;
520 Type[] gen_params, atypes;
523 public ConstructedType (string name, TypeArguments args, Location l)
526 this.name = name + "!" + args.Count;
529 eclass = ExprClass.Type;
530 full_name = name + "<" + args.ToString () + ">";
533 public ConstructedType (string name, TypeParameter[] type_params, Location l)
534 : this (type_params, l)
539 full_name = name + "<" + args.ToString () + ">";
542 protected ConstructedType (TypeArguments args, Location l)
547 eclass = ExprClass.Type;
550 protected ConstructedType (TypeParameter[] type_params, Location l)
554 args = new TypeArguments (l);
555 foreach (TypeParameter type_param in type_params)
556 args.Add (new TypeParameterExpr (type_param, l));
558 eclass = ExprClass.Type;
561 public ConstructedType (Type t, TypeParameter[] type_params, Location l)
562 : this (type_params, l)
564 gt = t.GetGenericTypeDefinition ();
566 this.name = gt.FullName;
567 full_name = gt.FullName + "<" + args.ToString () + ">";
570 public ConstructedType (Type t, TypeArguments args, Location l)
573 gt = t.GetGenericTypeDefinition ();
575 this.name = gt.FullName;
576 full_name = gt.FullName + "<" + args.ToString () + ">";
579 public TypeArguments TypeArguments {
583 protected string DeclarationName {
585 StringBuilder sb = new StringBuilder ();
586 sb.Append (gt.FullName);
588 for (int i = 0; i < gen_params.Length; i++) {
591 sb.Append (gen_params [i]);
594 return sb.ToString ();
598 protected bool CheckConstraints (EmitContext ec, int index)
600 Type atype = atypes [index];
601 Type ptype = gen_params [index];
606 Expression aexpr = new EmptyExpression (atype);
609 // First, check the class constraint.
612 Type parent = ptype.BaseType;
613 if ((parent != null) && (parent != TypeManager.object_type)) {
614 if (!Convert.ImplicitStandardConversionExists (aexpr, parent)) {
615 Report.Error (309, loc, "The type `{0}' must be " +
616 "convertible to `{1}' in order to " +
617 "use it as parameter `{2}' in the " +
618 "generic type or method `{3}'",
619 atype, parent, ptype, DeclarationName);
625 // Now, check the interface constraints.
627 foreach (Type itype in ptype.GetInterfaces ()) {
628 if (!Convert.ImplicitStandardConversionExists (aexpr, itype)) {
629 Report.Error (309, loc, "The type `{0}' must be " +
630 "convertible to `{1}' in order to " +
631 "use it as parameter `{2}' in the " +
632 "generic type or method `{3}'",
633 atype, itype, ptype, DeclarationName);
639 // Finally, check the constructor constraint.
642 if (!TypeManager.HasConstructorConstraint (ptype))
645 MethodGroupExpr mg = Expression.MemberLookup (
646 ec, atype, ".ctor", MemberTypes.Constructor,
647 BindingFlags.Public | BindingFlags.Instance |
648 BindingFlags.DeclaredOnly, loc)
651 if (atype.IsAbstract || (mg == null) || !mg.IsInstance) {
652 Report.Error (310, loc, "The type `{0}' must have a public " +
653 "parameterless constructor in order to use it " +
654 "as parameter `{1}' in the generic type or " +
655 "method `{2}'", atype, ptype, DeclarationName);
662 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
668 // First, resolve the generic type.
671 Type nested = ec.DeclSpace.FindNestedType (loc, name, out ds);
672 if (nested != null) {
673 gt = nested.GetGenericTypeDefinition ();
675 TypeArguments new_args = new TypeArguments (loc);
676 foreach (TypeParameter param in ds.TypeParameters)
677 new_args.Add (new TypeParameterExpr (param, loc));
687 SimpleName sn = new SimpleName (name, loc);
688 TypeExpr resolved = sn.ResolveAsTypeTerminal (ec);
689 if ((resolved == null) || (resolved.Type == null)) {
690 Report.Error (246, loc,
691 "The type or namespace name `{0}<...>' "+
692 "could not be found", Basename);
698 Report.Error (246, loc, "Cannot find type `{0}'<...>",
703 num_args = TypeManager.GetNumberOfTypeArguments (t);
705 Report.Error (308, loc,
706 "The non-generic type `{0}' cannot " +
707 "be used with type arguments.",
708 TypeManager.CSharpName (t));
712 gt = t.GetGenericTypeDefinition ();
716 public override Type ResolveType (EmitContext ec)
720 if (DoResolveAsTypeStep (ec) == null)
724 // Resolve the arguments.
726 if (args.Resolve (ec) == false)
729 gen_params = gt.GetGenericArguments ();
730 atypes = args.Arguments;
732 if (atypes.Length != gen_params.Length) {
733 Report.Error (305, loc,
734 "Using the generic type `{0}' " +
735 "requires {1} type arguments",
736 TypeManager.GetFullName (gt),
741 for (int i = 0; i < gen_params.Length; i++) {
742 if (!CheckConstraints (ec, i))
747 // Now bind the parameters.
749 type = gt.BindGenericParameters (atypes);
753 public Expression GetMemberAccess (EmitContext ec)
756 if (ec.TypeContainer.CurrentType != null)
757 current = ec.TypeContainer.CurrentType;
759 current = new TypeExpression (ec.ContainerType, loc);
761 return new MemberAccess (current, Basename, args, loc);
764 public override bool CheckAccessLevel (DeclSpace ds)
766 return ds.CheckAccessLevel (gt);
769 public override bool AsAccessible (DeclSpace ds, int flags)
771 return ds.AsAccessible (gt, flags);
774 public override bool IsClass {
775 get { return gt.IsClass; }
778 public override bool IsValueType {
779 get { return gt.IsValueType; }
782 public override bool IsInterface {
783 get { return gt.IsInterface; }
786 public override bool IsSealed {
787 get { return gt.IsSealed; }
790 public override bool IsAttribute {
791 get { return false; }
794 public override TypeExpr[] GetInterfaces ()
796 TypeExpr[] ifaces = TypeManager.GetInterfaces (gt);
800 public override bool Equals (object obj)
802 ConstructedType cobj = obj as ConstructedType;
806 if ((type == null) || (cobj.type == null))
809 return type == cobj.type;
812 public string Basename {
814 int pos = name.LastIndexOf ('!');
816 return name.Substring (0, pos);
822 public override string Name {
829 public class GenericMethod : DeclSpace
831 public GenericMethod (NamespaceEntry ns, TypeContainer parent,
832 MemberName name, Attributes attrs, Location l)
833 : base (ns, parent, name, attrs, l)
836 public override TypeBuilder DefineType ()
838 throw new Exception ();
841 public override bool Define (TypeContainer parent)
843 for (int i = 0; i < TypeParameters.Length; i++)
844 if (!TypeParameters [i].Resolve (parent))
850 public bool Define (TypeContainer parent, MethodBuilder mb)
852 if (!Define (parent))
855 GenericTypeParameterBuilder[] gen_params;
856 gen_params = mb.DefineGenericParameters (MemberName.TypeParameters);
857 for (int i = 0; i < TypeParameters.Length; i++)
858 TypeParameters [i].Define (gen_params [i]);
863 public bool DefineType (EmitContext ec, MethodBuilder mb)
865 for (int i = 0; i < TypeParameters.Length; i++)
866 if (!TypeParameters [i].DefineType (ec))
872 public override bool DefineMembers (TypeContainer parent)
877 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
878 MemberFilter filter, object criteria)
880 throw new Exception ();
883 public override MemberCache MemberCache {
885 throw new Exception ();
890 public class DefaultValueExpression : Expression
893 LocalTemporary temp_storage;
895 public DefaultValueExpression (Expression expr, Location loc)
901 public override Expression DoResolve (EmitContext ec)
903 type = ec.DeclSpace.ResolveType (expr, false, loc);
907 if (type.IsGenericParameter || TypeManager.IsValueType (type))
908 temp_storage = new LocalTemporary (ec, type);
910 eclass = ExprClass.Variable;
914 public override void Emit (EmitContext ec)
916 if (temp_storage != null) {
917 temp_storage.AddressOf (ec, AddressOp.LoadStore);
918 ec.ig.Emit (OpCodes.Initobj, type);
919 temp_storage.Emit (ec);
921 ec.ig.Emit (OpCodes.Ldnull);