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;
221 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
223 type = type_parameter.Type;
228 public void Error_CannotUseAsUnmanagedType (Location loc)
230 Report.Error (-203, loc, "Can not use type parameter as unamanged type");
234 public class TypeArguments {
235 public readonly Location Location;
241 public TypeArguments (Location loc)
243 args = new ArrayList ();
247 public void Add (Expression type)
250 throw new InvalidOperationException ();
255 public void Add (TypeArguments new_args)
258 throw new InvalidOperationException ();
260 args.AddRange (new_args.args);
263 public Type[] Arguments {
269 public bool HasTypeArguments {
271 return has_type_args;
281 public override string ToString ()
283 StringBuilder s = new StringBuilder ();
285 int count = args.Count;
286 for (int i = 0; i < count; i++){
288 // FIXME: Use TypeManager.CSharpname once we have the type
290 s.Append (args [i].ToString ());
294 return s.ToString ();
297 public bool Resolve (EmitContext ec)
299 DeclSpace ds = ec.DeclSpace;
300 int count = args.Count;
303 atypes = new Type [count];
305 for (int i = 0; i < count; i++){
306 TypeExpr te = ds.ResolveTypeExpr (
307 (Expression) args [i], false, Location);
312 if (te is TypeParameterExpr)
313 has_type_args = true;
314 atypes [i] = te.ResolveType (ec);
316 if (atypes [i] == null) {
317 Report.Error (246, Location, "Cannot find type `{0}'",
326 public class ConstructedType : TypeExpr {
327 string name, full_name;
329 Type[] gen_params, atypes;
332 public ConstructedType (string name, TypeArguments args, Location l)
338 eclass = ExprClass.Type;
339 full_name = name + "<" + args.ToString () + ">";
342 public ConstructedType (string name, TypeParameter[] type_params, Location l)
347 args = new TypeArguments (l);
348 foreach (TypeParameter type_param in type_params)
349 args.Add (new TypeParameterExpr (type_param, l));
351 eclass = ExprClass.Type;
352 full_name = name + "<" + args.ToString () + ">";
355 public ConstructedType (Type t, TypeParameter[] type_params, Location l)
356 : this (t.Name, type_params, l)
358 gt = t.GetGenericTypeDefinition ();
361 public ConstructedType (Type t, TypeArguments args, Location l)
362 : this (t.Name, args, l)
364 gt = t.GetGenericTypeDefinition ();
367 public TypeArguments TypeArguments {
371 protected bool CheckConstraints (int index)
373 Type atype = atypes [index];
374 Type ptype = gen_params [index];
380 // First, check parent class.
382 if ((ptype.BaseType != atype.BaseType) &&
383 !atype.BaseType.IsSubclassOf (ptype.BaseType)) {
384 Report.Error (-219, loc, "Cannot create constructed type `{0}': " +
385 "type argument `{1}' must derive from `{2}'.",
386 full_name, atype, ptype.BaseType);
391 // Now, check the interfaces.
393 foreach (Type itype in ptype.GetInterfaces ()) {
394 if (TypeManager.ImplementsInterface (atype, itype))
397 Report.Error (-219, loc, "Cannot create constructed type `{0}: " +
398 "type argument `{1}' must implement interface `{2}'.",
399 full_name, atype, itype);
406 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
412 // First, resolve the generic type.
415 Type nested = ec.DeclSpace.FindNestedType (loc, name, out ds);
416 if (nested != null) {
417 gt = nested.GetGenericTypeDefinition ();
419 TypeArguments new_args = new TypeArguments (loc);
420 foreach (TypeParameter param in ds.TypeParameters)
421 new_args.Add (new TypeParameterExpr (param, loc));
428 SimpleName sn = new SimpleName (name, args.Count, loc);
429 TypeExpr resolved = sn.ResolveAsTypeTerminal (ec);
430 if (resolved == null) {
431 sn = new SimpleName (name, -1, loc);
432 resolved = sn.ResolveAsTypeTerminal (ec);
433 if ((resolved == null) || (resolved.Type == null)) {
434 Report.Error (246, loc,
435 "The type or namespace name `{0}<...>' "+
436 "could not be found", name);
440 Type t = resolved.Type;
441 int num_args = TypeManager.GetNumberOfTypeArguments (t);
444 Report.Error (308, loc,
445 "The non-generic type `{0}' cannot " +
446 "be used with type arguments.",
447 TypeManager.CSharpName (t));
451 Report.Error (305, loc,
452 "Using the generic type `{0}' " +
453 "requires {1} type arguments",
454 TypeManager.GetFullName (t), num_args);
458 if (resolved.Type == null)
459 throw new InternalErrorException (
460 "Failed to resolve constructed type `{0}'",
463 gt = resolved.Type.GetGenericTypeDefinition ();
467 public override Type ResolveType (EmitContext ec)
471 if (DoResolveAsTypeStep (ec) == null)
475 // Resolve the arguments.
477 if (args.Resolve (ec) == false)
480 gen_params = gt.GetGenericArguments ();
481 atypes = args.Arguments;
483 if (atypes.Length != gen_params.Length) {
484 Report.Error (-217, loc, "Generic type `{0}' takes {1} " +
485 "type parameters, but specified {2}.", gt.Name,
486 gen_params.Length, atypes.Length);
490 for (int i = 0; i < gen_params.Length; i++) {
491 if (!CheckConstraints (i))
496 // Now bind the parameters.
498 type = gt.BindGenericParameters (atypes);
502 public Expression GetMemberAccess (TypeExpr current_type)
504 return new GenericMemberAccess (current_type, name, args, loc);
507 public override bool CheckAccessLevel (DeclSpace ds)
509 return ds.CheckAccessLevel (gt);
512 public override bool AsAccessible (DeclSpace ds, int flags)
514 return ds.AsAccessible (gt, flags);
517 public override bool IsClass {
518 get { return gt.IsClass; }
521 public override bool IsValueType {
522 get { return gt.IsValueType; }
525 public override bool IsInterface {
526 get { return gt.IsInterface; }
529 public override bool IsSealed {
530 get { return gt.IsSealed; }
533 public override TypeExpr[] GetInterfaces ()
535 TypeExpr[] ifaces = TypeManager.GetInterfaces (gt);
539 public override string Name {
546 public class GenericMethod : DeclSpace
548 public GenericMethod (NamespaceEntry ns, TypeContainer parent, string name,
549 Attributes attrs, Location l)
550 : base (ns, parent, name, attrs, l)
553 public override TypeBuilder DefineType ()
555 throw new Exception ();
558 public override bool Define (TypeContainer parent)
563 public bool Define (MethodBuilder mb)
565 Type[] gen_params = new Type [TypeParameters.Length];
566 for (int i = 0; i < TypeParameters.Length; i++)
567 gen_params [i] = TypeParameters [i].DefineMethod (mb);
572 public bool DefineType (EmitContext ec, MethodBuilder mb)
574 for (int i = 0; i < TypeParameters.Length; i++)
575 TypeParameters [i].DefineType (ec, mb);
580 public override bool DefineMembers (TypeContainer parent)
585 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
586 MemberFilter filter, object criteria)
588 throw new Exception ();
591 public override MemberCache MemberCache {
593 throw new Exception ();
598 public class GenericMemberAccess : MemberAccess
602 public GenericMemberAccess (Expression expr, string id, TypeArguments args, Location loc)
603 : base (expr, id, args.Count, loc)
608 public override Expression DoResolve (EmitContext ec, Expression right_side,
611 Expression expr = base.DoResolve (ec, right_side, flags);
615 MethodGroupExpr mg = expr as MethodGroupExpr;
617 Report.Error (-220, loc, "Member `{0}' has type arguments, but did " +
618 "not resolve as a method group.", Identifier);
622 if (args.Resolve (ec) == false)
625 Type[] atypes = args.Arguments;
627 ArrayList list = new ArrayList ();
629 foreach (MethodBase method in mg.Methods) {
630 MethodInfo mi = method as MethodInfo;
634 Type[] gen_params = mi.GetGenericArguments ();
636 if (atypes.Length != gen_params.Length) {
637 Report.Error (-217, loc, "Generic method `{0}' takes {1} " +
638 "type parameters, but specified {2}.", mi.Name,
639 gen_params.Length, atypes.Length);
643 list.Add (mi.BindGenericParameters (args.Arguments));
646 MethodInfo[] methods = new MethodInfo [list.Count];
647 list.CopyTo (methods, 0);
649 MethodGroupExpr new_mg = new MethodGroupExpr (methods, mg.Location);
650 new_mg.InstanceExpression = mg.InstanceExpression;
654 public override Expression ResolveAsTypeStep (EmitContext ec)
656 ConstructedType cexpr = expr as ConstructedType;
658 TypeArguments new_args = new TypeArguments (loc);
659 new_args.Add (cexpr.TypeArguments);
665 expr = base.ResolveAsTypeStep (ec);
669 Type t = ((TypeExpr) expr).ResolveType (ec);
673 ConstructedType ctype = new ConstructedType (t, args, loc);
674 return ctype.ResolveAsTypeStep (ec);
678 public class DefaultValueExpression : Expression
681 LocalTemporary temp_storage;
683 public DefaultValueExpression (Expression expr, Location loc)
689 public override Expression DoResolve (EmitContext ec)
691 type = ec.DeclSpace.ResolveType (expr, false, loc);
695 if (type.IsGenericParameter || TypeManager.IsValueType (type))
696 temp_storage = new LocalTemporary (ec, type);
698 eclass = ExprClass.Variable;
702 public override void Emit (EmitContext ec)
704 if (temp_storage != null) {
705 temp_storage.AddressOf (ec, AddressOp.LoadStore);
706 ec.ig.Emit (OpCodes.Initobj, type);
707 temp_storage.Emit (ec);
709 ec.ig.Emit (OpCodes.Ldnull);