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 TypeExpr class_constraint;
52 ArrayList iface_constraints;
53 TypeExpr[] constraint_types;
56 public bool HasConstructorConstraint {
57 get { return has_ctor_constraint; }
60 public bool Resolve (DeclSpace ds)
62 iface_constraints = new ArrayList ();
64 foreach (object obj in constraints) {
65 if (has_ctor_constraint) {
66 Error ("can only use one constructor constraint and " +
67 "it must be the last constraint in the list.");
72 has_ctor_constraint = true;
76 TypeExpr expr = ds.ResolveTypeExpr ((Expression) obj, false, loc);
81 iface_constraints.Add (expr);
82 else if (class_constraint != null) {
83 Error ("can have at most one class constraint.");
86 class_constraint = expr;
91 constraint_types = new TypeExpr [num_constraints];
93 if (class_constraint != null)
94 constraint_types [pos++] = class_constraint;
95 iface_constraints.CopyTo (constraint_types, pos);
100 public Type[] ResolveTypes (EmitContext ec)
102 Type [] types = new Type [constraint_types.Length];
104 for (int i = 0; i < constraint_types.Length; i++)
105 types [i] = constraint_types [i].ResolveType (ec);
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 type = tb.DefineGenericParameter (name);
165 public Type DefineMethod (MethodBuilder mb)
167 type = mb.DefineGenericParameter (name);
171 public void DefineType (EmitContext ec, TypeBuilder tb)
173 int index = type.GenericParameterPosition;
174 if (constraints == null)
175 tb.SetGenericParameterConstraints (index, new Type [0]);
177 tb.SetGenericParameterConstraints (index, constraints.ResolveTypes (ec));
180 public void DefineType (EmitContext ec, MethodBuilder mb)
182 int index = type.GenericParameterPosition;
183 if (constraints == null)
184 mb.SetGenericParameterConstraints (index, new Type [0]);
186 mb.SetGenericParameterConstraints (index, constraints.ResolveTypes (ec));
189 public override string ToString ()
191 return "TypeParameter[" + name + "]";
196 // This type represents a generic type parameter reference.
198 // These expressions are born in a fully resolved state.
200 public class TypeParameterExpr : TypeExpr {
201 TypeParameter type_parameter;
203 public override string Name {
205 return type_parameter.Name;
209 public TypeParameter TypeParameter {
211 return type_parameter;
215 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
217 this.type_parameter = type_parameter;
220 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
222 type = type_parameter.Type;
227 public void Error_CannotUseAsUnmanagedType (Location loc)
229 Report.Error (-203, loc, "Can not use type parameter as unamanged type");
233 public class TypeArguments {
238 public TypeArguments ()
240 args = new ArrayList ();
243 public void Add (Expression type)
248 public Type[] Arguments {
254 public bool HasTypeArguments {
256 return has_type_args;
260 public override string ToString ()
262 StringBuilder s = new StringBuilder ();
264 int count = args.Count;
265 for (int i = 0; i < count; i++){
267 // FIXME: Use TypeManager.CSharpname once we have the type
269 s.Append (args [i].ToString ());
273 return s.ToString ();
276 public bool Resolve (EmitContext ec)
278 int count = args.Count;
281 atypes = new Type [count];
283 for (int i = 0; i < count; i++){
284 TypeExpr e = ((Expression)args [i]).ResolveAsTypeTerminal (ec);
289 if (e is TypeParameterExpr)
290 has_type_args = true;
292 atypes [i] = e.ResolveType (ec);
294 if (atypes [i] == null)
301 public class ConstructedType : TypeExpr {
302 string name, full_name;
304 Type[] gen_params, atypes;
307 public ConstructedType (string name, TypeArguments args, Location l)
313 eclass = ExprClass.Type;
314 full_name = name + "<" + args.ToString () + ">";
317 public ConstructedType (string name, TypeParameter[] type_params, Location l)
322 args = new TypeArguments ();
323 foreach (TypeParameter type_param in type_params)
324 args.Add (new TypeParameterExpr (type_param, l));
326 eclass = ExprClass.Type;
327 full_name = name + "<" + args.ToString () + ">";
330 protected bool CheckConstraints (int index)
332 Type atype = args.Arguments [index];
333 Type ptype = gen_params [index];
339 // First, check parent class.
341 if ((ptype.BaseType != atype.BaseType) &&
342 !atype.BaseType.IsSubclassOf (ptype.BaseType)) {
343 Report.Error (-219, loc, "Cannot create constructed type `{0}': " +
344 "type argument `{1}' must derive from `{2}'.",
345 full_name, atype, ptype.BaseType);
350 // Now, check the interfaces.
352 foreach (Type itype in ptype.GetInterfaces ()) {
353 if (TypeManager.ImplementsInterface (atype, itype))
356 Report.Error (-219, loc, "Cannot create constructed type `{0}: " +
357 "type argument `{1}' must implement interface `{2}'.",
358 full_name, atype, itype);
365 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
371 // First, resolve the generic type.
373 SimpleName sn = new SimpleName (name, loc);
374 TypeExpr resolved = sn.ResolveAsTypeTerminal (ec);
375 if (resolved == null)
378 if (resolved.Type == null) {
379 Report.Error (-220, loc, "Failed to resolve constructed type `{0}'",
384 gt = resolved.Type.GetGenericTypeDefinition ();
388 public override Type ResolveType (EmitContext ec)
392 if (DoResolveAsTypeStep (ec) == null)
396 // Resolve the arguments.
398 if (args.Resolve (ec) == false) {
399 Report.Error (-220, loc, "Failed to resolve constructed type `{0}'",
404 gen_params = gt.GetGenericArguments ();
405 atypes = args.Arguments;
407 if (atypes.Length != gen_params.Length) {
408 Report.Error (-217, loc, "Generic type `{0}' takes {1} " +
409 "type parameters, but specified {2}.", gt.Name,
410 gen_params.Length, atypes.Length);
414 for (int i = 0; i < gen_params.Length; i++) {
415 if (!CheckConstraints (i))
420 // Now bind the parameters.
422 type = gt.BindGenericParameters (atypes);
426 public Expression GetMemberAccess (TypeExpr current_type)
428 return new GenericMemberAccess (current_type, name, args, loc);
431 public override bool CheckAccessLevel (DeclSpace ds)
433 return ds.CheckAccessLevel (gt);
436 public override bool AsAccessible (DeclSpace ds, int flags)
438 return ds.AsAccessible (gt, flags);
441 public override bool IsClass {
442 get { return gt.IsClass; }
445 public override bool IsValueType {
446 get { return gt.IsValueType; }
449 public override bool IsInterface {
450 get { return gt.IsInterface; }
453 public override bool IsSealed {
454 get { return gt.IsSealed; }
457 public override TypeExpr[] GetInterfaces ()
459 TypeExpr[] ifaces = TypeManager.GetInterfaces (gt);
463 public override string Name {
470 public class GenericMethod : DeclSpace
472 public GenericMethod (NamespaceEntry ns, TypeContainer parent, string name,
473 Attributes attrs, Location l)
474 : base (ns, parent, name, attrs, l)
477 public override TypeBuilder DefineType ()
479 throw new Exception ();
482 public override bool Define (TypeContainer parent)
487 public bool Define (MethodBuilder mb)
489 Type[] gen_params = new Type [TypeParameters.Length];
490 for (int i = 0; i < TypeParameters.Length; i++)
491 gen_params [i] = TypeParameters [i].DefineMethod (mb);
496 public override bool DefineMembers (TypeContainer parent)
501 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
502 MemberFilter filter, object criteria)
504 throw new Exception ();
507 public override MemberCache MemberCache {
509 throw new Exception ();
514 public class GenericMemberAccess : MemberAccess
518 public GenericMemberAccess (Expression expr, string id, TypeArguments args, Location loc)
519 : base (expr, id, loc)
524 public override Expression DoResolve (EmitContext ec, Expression right_side,
527 Expression expr = base.DoResolve (ec, right_side, flags);
531 MethodGroupExpr mg = expr as MethodGroupExpr;
533 Report.Error (-220, loc, "Member `{0}' has type arguments, but did " +
534 "not resolve as a method group.", Identifier);
538 if (args.Resolve (ec) == false)
541 Type[] atypes = args.Arguments;
543 ArrayList list = new ArrayList ();
545 foreach (MethodBase method in mg.Methods) {
546 MethodInfo mi = method as MethodInfo;
550 Type[] gen_params = mi.GetGenericArguments ();
552 if (atypes.Length != gen_params.Length) {
553 Report.Error (-217, loc, "Generic method `{0}' takes {1} " +
554 "type parameters, but specified {2}.", mi.Name,
555 gen_params.Length, atypes.Length);
559 list.Add (mi.BindGenericParameters (args.Arguments));
562 MethodInfo[] methods = new MethodInfo [list.Count];
563 list.CopyTo (methods, 0);
565 MethodGroupExpr new_mg = new MethodGroupExpr (methods, mg.Location);
566 new_mg.InstanceExpression = mg.InstanceExpression;
571 public class DefaultValueExpression : Expression
574 LocalTemporary temp_storage;
576 public DefaultValueExpression (Expression expr, Location loc)
582 public override Expression DoResolve (EmitContext ec)
584 type = ec.DeclSpace.ResolveType (expr, false, loc);
588 if (type.IsGenericParameter || TypeManager.IsValueType (type))
589 temp_storage = new LocalTemporary (ec, type);
591 eclass = ExprClass.Variable;
595 public override void Emit (EmitContext ec)
597 if (temp_storage != null) {
598 temp_storage.AddressOf (ec, AddressOp.LoadStore);
599 ec.ig.Emit (OpCodes.Initobj, type);
600 temp_storage.Emit (ec);
602 ec.ig.Emit (OpCodes.Ldnull);