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 (DeclSpace ds)
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 = ds.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 (DeclSpace ds)
153 if (constraints != null)
154 return constraints.Resolve (ds);
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;
193 public override string Name {
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);
285 if (e is TypeParameterExpr)
286 has_type_args = true;
294 public class ConstructedType : TypeExpr {
295 Expression container_type;
296 string name, full_name;
298 Type[] gen_params, atypes;
301 public ConstructedType (string name, TypeArguments args, Location l)
305 this.container_type = container_type;
308 eclass = ExprClass.Type;
310 full_name = name + "<" + args.ToString () + ">";
313 public override Expression DoResolve (EmitContext ec)
315 if (args.Resolve (ec) == false)
319 // Pretend there are not type parameters, until we get GetType support
321 return new SimpleName (name, loc).DoResolve (ec);
324 protected bool CheckConstraints (int index)
326 Type atype = args.Arguments [index];
327 Type ptype = gen_params [index];
333 // First, check parent class.
335 if ((ptype.BaseType != atype.BaseType) &&
336 !atype.BaseType.IsSubclassOf (ptype.BaseType)) {
337 Report.Error (-219, loc, "Cannot create constructed type `{0}': " +
338 "type argument `{1}' must derive from `{2}'.",
339 full_name, atype, ptype.BaseType);
344 // Now, check the interfaces.
346 foreach (Type itype in ptype.GetInterfaces ()) {
347 if (TypeManager.ImplementsInterface (atype, itype))
350 Report.Error (-219, loc, "Cannot create constructed type `{0}: " +
351 "type argument `{1}' must implement interface `{2}'.",
352 full_name, atype, itype);
359 public override Expression ResolveAsTypeStep (EmitContext ec)
362 // First, resolve the generic type.
364 SimpleName sn = new SimpleName (name, loc);
365 Expression resolved = sn.ResolveAsTypeStep (ec);
366 if (resolved == null)
369 if (resolved.Type == null) {
370 Report.Error (-220, loc, "Failed to resolve constructed type `{0}'",
375 gt = resolved.Type.GetGenericTypeDefinition ();
379 public Type Resolve (EmitContext ec, TypeBuilder parent)
382 // Resolve the arguments.
384 if (args.Resolve (ec) == false)
387 gen_params = gt.GetGenericArguments ();
388 atypes = args.Arguments;
390 if (atypes.Length != gen_params.Length) {
391 Report.Error (-217, loc, "Generic type `{0}' takes {1} " +
392 "type parameters, but specified {2}.", gt.Name,
393 gen_params.Length, atypes.Length);
397 if (args.HasTypeArguments) {
402 for (int i = 0; i < gen_params.Length; i++) {
403 if (!CheckConstraints (i))
408 // Now bind the parameters.
410 type = gt.BindGenericParameters (args.Arguments);
414 public override void Emit (EmitContext ec)
417 // Never reached for now
419 throw new Exception ("IMPLEMENT ME");
422 public override string ToString ()
428 public class GenericMethod : DeclSpace
430 public GenericMethod (NamespaceEntry ns, TypeContainer parent, string name, Location l)
431 : base (ns, parent, name, l)
434 public override TypeBuilder DefineType ()
436 throw new Exception ();
439 public override bool Define (TypeContainer parent)
444 public bool Define (MethodBuilder mb)
446 Type[] gen_params = new Type [TypeParameters.Length];
447 for (int i = 0; i < TypeParameters.Length; i++)
448 gen_params [i] = TypeParameters [i].DefineMethod (mb);
453 public override bool DefineMembers (TypeContainer parent)
458 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
459 MemberFilter filter, object criteria)
461 throw new Exception ();
464 public override MemberCache MemberCache {
466 throw new Exception ();
471 public class GenericMemberAccess : MemberAccess
475 public GenericMemberAccess (Expression expr, string id, TypeArguments args, Location loc)
476 : base (expr, id, loc)
481 public override Expression DoResolve (EmitContext ec, Expression right_side,
484 Expression expr = base.DoResolve (ec, right_side, flags);
488 MethodGroupExpr mg = expr as MethodGroupExpr;
490 Report.Error (-220, loc, "Member `{0}' has type arguments, but did " +
491 "not resolve as a method group.", Identifier);
495 if (args.Resolve (ec) == false)
498 Type[] atypes = args.Arguments;
500 ArrayList list = new ArrayList ();
502 foreach (MethodBase method in mg.Methods) {
503 MethodInfo mi = method as MethodInfo;
507 Type[] gen_params = mi.GetGenericArguments ();
509 if (atypes.Length != gen_params.Length) {
510 Report.Error (-217, loc, "Generic method `{0}' takes {1} " +
511 "type parameters, but specified {2}.", mi.Name,
512 gen_params.Length, atypes.Length);
516 list.Add (mi.BindGenericParameters (args.Arguments));
519 MethodInfo[] methods = new MethodInfo [list.Count];
520 list.CopyTo (methods, 0);
522 MethodGroupExpr new_mg = new MethodGroupExpr (methods, mg.Location);
523 new_mg.InstanceExpression = mg.InstanceExpression;
528 public class DefaultValueExpression : Expression
531 LocalTemporary temp_storage;
533 public DefaultValueExpression (Expression expr, Location loc)
539 public override Expression DoResolve (EmitContext ec)
541 type = ec.DeclSpace.ResolveType (expr, false, loc);
545 if (type.IsGenericParameter || TypeManager.IsValueType (type))
546 temp_storage = new LocalTemporary (ec, type);
548 eclass = ExprClass.Variable;
552 public override void Emit (EmitContext ec)
554 if (temp_storage != null) {
555 temp_storage.AddressOf (ec, AddressOp.LoadStore);
556 ec.ig.Emit (OpCodes.Initobj, type);
557 temp_storage.Emit (ec);
559 ec.ig.Emit (OpCodes.Ldnull);