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 {
19 // Tracks the constraints for a type parameter
21 public class Constraints {
22 string type_parameter;
23 ArrayList constraints;
27 // type_parameter is the identifier, constraints is an arraylist of
28 // Expressions (with types) or `true' for the constructor constraint.
30 public Constraints (string type_parameter, ArrayList constraints,
33 this.type_parameter = type_parameter;
34 this.constraints = constraints;
38 public string TypeParameter {
40 return type_parameter;
44 protected void Error (string message)
46 Report.Error (-218, "Invalid constraints clause for type " +
47 "parameter `{0}': {1}", type_parameter, message);
50 bool has_ctor_constraint;
51 Type class_constraint;
52 ArrayList iface_constraints;
53 Type[] constraint_types;
56 public bool HasConstructorConstraint {
57 get { return has_ctor_constraint; }
61 get { return constraint_types; }
64 public bool Resolve (TypeContainer tc)
66 iface_constraints = new ArrayList ();
68 if (constraints == null) {
69 constraint_types = new Type [0];
73 foreach (object obj in constraints) {
74 if (has_ctor_constraint) {
75 Error ("can only use one constructor constraint and " +
76 "it must be the last constraint in the list.");
81 has_ctor_constraint = true;
85 Expression expr = tc.ResolveTypeExpr ((Expression) obj, false, loc);
89 Type etype = expr.Type;
90 if (etype.IsInterface)
91 iface_constraints.Add (etype);
92 else if (class_constraint != null) {
93 Error ("can have at most one class constraint.");
96 class_constraint = etype;
101 constraint_types = new Type [num_constraints];
103 if (class_constraint != null)
104 constraint_types [pos++] = class_constraint;
105 iface_constraints.CopyTo (constraint_types, pos);
112 // This type represents a generic type parameter
114 public class TypeParameter {
116 Constraints constraints;
120 public TypeParameter (string name, Constraints constraints, Location loc)
123 this.constraints = constraints;
133 public Location Location {
139 public Constraints Constraints {
151 public bool Resolve (TypeContainer tc)
153 if (constraints != null)
154 return constraints.Resolve (tc);
159 public Type Define (TypeBuilder tb)
161 if (constraints != null)
162 type = tb.DefineGenericParameter (name, constraints.Types);
164 type = tb.DefineGenericParameter (name, new Type [0]);
169 public Type DefineMethod (MethodBuilder mb)
171 if (constraints != null)
172 type = mb.DefineGenericParameter (name, constraints.Types);
174 type = mb.DefineGenericParameter (name, new Type [0]);
179 public override string ToString ()
181 return "TypeParameter[" + name + "]";
186 // This type represents a generic type parameter reference.
188 // These expressions are born in a fully resolved state.
190 public class TypeParameterExpr : TypeExpr {
191 TypeParameter type_parameter;
195 return type_parameter.Name;
199 public TypeParameter TypeParameter {
201 return type_parameter;
205 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
206 : base (type_parameter.Type, loc)
208 this.type_parameter = type_parameter;
211 public override Expression ResolveAsTypeStep (EmitContext ec)
213 type = type_parameter.Type;
218 public override string ToString ()
220 return "TypeParameterExpr[" + type_parameter.Name + "]";
223 public void Error_CannotUseAsUnmanagedType (Location loc)
225 Report.Error (-203, loc, "Can not use type parameter as unamanged type");
229 public class TypeArguments {
234 public TypeArguments ()
236 args = new ArrayList ();
239 public void Add (Expression type)
244 public Type[] Arguments {
250 public bool HasTypeArguments {
252 return has_type_args;
256 public override string ToString ()
258 StringBuilder s = new StringBuilder ();
260 int count = args.Count;
261 for (int i = 0; i < count; i++){
263 // FIXME: Use TypeManager.CSharpname once we have the type
265 s.Append (args [i].ToString ());
269 return s.ToString ();
272 public bool Resolve (EmitContext ec)
274 int count = args.Count;
277 atypes = new Type [count];
279 for (int i = 0; i < count; i++){
280 Expression e = ((Expression)args [i]).ResolveAsTypeTerminal (ec);
283 if (e is TypeParameterExpr)
284 has_type_args = true;
292 public class ConstructedType : Expression {
293 Expression container_type;
294 string name, full_name;
296 Type[] gen_params, atypes;
298 public ConstructedType (string name, TypeArguments args, Location l)
301 this.container_type = container_type;
304 eclass = ExprClass.Type;
306 full_name = name + "<" + args.ToString () + ">";
309 public override Expression DoResolve (EmitContext ec)
311 if (args.Resolve (ec) == false)
315 // Pretend there are not type parameters, until we get GetType support
317 return new SimpleName (name, loc).DoResolve (ec);
320 protected bool CheckConstraints (int index)
322 Type atype = args.Arguments [index];
323 Type ptype = gen_params [index];
329 // First, check parent class.
331 if ((ptype.BaseType != atype.BaseType) &&
332 !atype.BaseType.IsSubclassOf (ptype.BaseType)) {
333 Report.Error (-219, loc, "Cannot create constructed type `{0}': " +
334 "type argument `{1}' must derive from `{2}'.",
335 full_name, atype, ptype.BaseType);
340 // Now, check the interfaces.
342 foreach (Type itype in ptype.GetInterfaces ()) {
343 if (TypeManager.ImplementsInterface (atype, itype))
346 Report.Error (-219, loc, "Cannot create constructed type `{0}: " +
347 "type argument `{1}' must implement interface `{2}'.",
348 full_name, atype, itype);
355 public override Expression ResolveAsTypeStep (EmitContext ec)
357 if (args.Resolve (ec) == false)
361 // First, resolve the generic type.
363 SimpleName sn = new SimpleName (name, loc);
364 Expression resolved = sn.ResolveAsTypeStep (ec);
365 if (resolved == null)
368 Type gt = resolved.Type.GetGenericTypeDefinition ();
369 gen_params = gt.GetGenericArguments ();
370 atypes = args.Arguments;
372 if (atypes.Length != gen_params.Length) {
373 Report.Error (-217, loc, "Generic type `{0}' takes {1} " +
374 "type parameters, but specified {2}.", gt.Name,
375 gen_params.Length, atypes.Length);
379 if (args.HasTypeArguments)
380 return new TypeExpr (gt, loc);
382 for (int i = 0; i < gen_params.Length; i++) {
383 if (!CheckConstraints (i))
388 // Now bind the parameters.
390 Type ntype = gt.BindGenericParameters (args.Arguments);
391 return new TypeExpr (ntype, loc);
394 public override void Emit (EmitContext ec)
397 // Never reached for now
399 throw new Exception ("IMPLEMENT ME");
402 public override string ToString ()
408 public class GenericMethod : DeclSpace
410 public GenericMethod (NamespaceEntry ns, TypeContainer parent, string name, Location l)
411 : base (ns, parent, name, l)
414 public override TypeBuilder DefineType ()
416 throw new Exception ();
419 public override bool Define (TypeContainer parent)
424 public bool Define (MethodBuilder mb)
426 Type[] gen_params = new Type [TypeParameters.Length];
427 for (int i = 0; i < TypeParameters.Length; i++)
428 gen_params [i] = TypeParameters [i].DefineMethod (mb);
433 public override bool DefineMembers (TypeContainer parent)
438 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
439 MemberFilter filter, object criteria)
441 throw new Exception ();
444 public override MemberCache MemberCache {
446 throw new Exception ();
451 public class GenericMemberAccess : MemberAccess
455 public GenericMemberAccess (Expression expr, string id, TypeArguments args, Location loc)
456 : base (expr, id, loc)
461 public override Expression DoResolve (EmitContext ec, Expression right_side,
464 Expression expr = base.DoResolve (ec, right_side, flags);
468 MethodGroupExpr mg = expr as MethodGroupExpr;
470 Report.Error (-220, loc, "Member `{0}' has type arguments, but did " +
471 "not resolve as a method group.", Identifier);
475 Report.Debug (64, "RESOLVE GENERIC MEMBER ACCESS", expr, expr.GetType ());