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)
207 this.type_parameter = type_parameter;
210 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
212 type = type_parameter.Type;
217 public void Error_CannotUseAsUnmanagedType (Location loc)
219 Report.Error (-203, loc, "Can not use type parameter as unamanged type");
223 public class TypeArguments {
228 public TypeArguments ()
230 args = new ArrayList ();
233 public void Add (Expression type)
238 public Type[] Arguments {
244 public bool HasTypeArguments {
246 return has_type_args;
250 public override string ToString ()
252 StringBuilder s = new StringBuilder ();
254 int count = args.Count;
255 for (int i = 0; i < count; i++){
257 // FIXME: Use TypeManager.CSharpname once we have the type
259 s.Append (args [i].ToString ());
263 return s.ToString ();
266 public bool Resolve (EmitContext ec)
268 int count = args.Count;
271 atypes = new Type [count];
273 for (int i = 0; i < count; i++){
274 Expression e = ((Expression)args [i]).ResolveAsTypeTerminal (ec);
279 if (e is TypeParameterExpr)
280 has_type_args = true;
288 public class ConstructedType : TypeExpr {
289 string name, full_name;
291 Type[] gen_params, atypes;
294 public ConstructedType (string name, TypeArguments args, Location l)
299 eclass = ExprClass.Type;
301 full_name = name + "<" + args.ToString () + ">";
304 protected bool CheckConstraints (int index)
306 Type atype = args.Arguments [index];
307 Type ptype = gen_params [index];
313 // First, check parent class.
315 if ((ptype.BaseType != atype.BaseType) &&
316 !atype.BaseType.IsSubclassOf (ptype.BaseType)) {
317 Report.Error (-219, loc, "Cannot create constructed type `{0}': " +
318 "type argument `{1}' must derive from `{2}'.",
319 full_name, atype, ptype.BaseType);
324 // Now, check the interfaces.
326 foreach (Type itype in ptype.GetInterfaces ()) {
327 if (TypeManager.ImplementsInterface (atype, itype))
330 Report.Error (-219, loc, "Cannot create constructed type `{0}: " +
331 "type argument `{1}' must implement interface `{2}'.",
332 full_name, atype, itype);
339 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
342 // First, resolve the generic type.
344 SimpleName sn = new SimpleName (name, loc);
345 TypeExpr resolved = sn.ResolveAsTypeTerminal (ec);
346 if (resolved == null)
349 if (resolved.Type == null) {
350 Report.Error (-220, loc, "Failed to resolve constructed type `{0}'",
355 gt = resolved.Type.GetGenericTypeDefinition ();
359 public override Type ResolveType (EmitContext ec)
362 // Resolve the arguments.
364 if (args.Resolve (ec) == false)
367 gen_params = gt.GetGenericArguments ();
368 atypes = args.Arguments;
370 if (atypes.Length != gen_params.Length) {
371 Report.Error (-217, loc, "Generic type `{0}' takes {1} " +
372 "type parameters, but specified {2}.", gt.Name,
373 gen_params.Length, atypes.Length);
377 for (int i = 0; i < gen_params.Length; i++) {
378 if (!CheckConstraints (i))
383 // Now bind the parameters.
385 type = gt.BindGenericParameters (atypes);
389 public override bool CheckAccessLevel (DeclSpace ds)
391 return ds.CheckAccessLevel (gt);
394 public override bool AsAccessible (DeclSpace ds, int flags)
396 return ds.AsAccessible (gt, flags);
399 public override bool IsClass {
400 get { return gt.IsClass; }
403 public override bool IsValueType {
404 get { return gt.IsValueType; }
407 public override bool IsInterface {
408 get { return gt.IsInterface; }
411 public override bool IsSealed {
412 get { return gt.IsSealed; }
415 public override TypeExpr[] GetInterfaces ()
417 TypeExpr[] ifaces = TypeManager.GetInterfaces (gt);
421 public override string Name {
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);