2003-11-15 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / gmcs / generic.cs
1 //
2 // generic.cs: Support classes for generics
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2003 Ximian, Inc.
8 //
9 using System;
10 using System.Reflection;
11 using System.Reflection.Emit;
12 using System.Globalization;
13 using System.Collections;
14 using System.Text;
15         
16 namespace Mono.CSharp {
17
18         //
19         // Tracks the constraints for a type parameter
20         //
21         public class Constraints {
22                 string type_parameter;
23                 ArrayList constraints;
24                 Location loc;
25                 
26                 //
27                 // type_parameter is the identifier, constraints is an arraylist of
28                 // Expressions (with types) or `true' for the constructor constraint.
29                 // 
30                 public Constraints (string type_parameter, ArrayList constraints,
31                                     Location loc)
32                 {
33                         this.type_parameter = type_parameter;
34                         this.constraints = constraints;
35                         this.loc = loc;
36                 }
37
38                 public string TypeParameter {
39                         get {
40                                 return type_parameter;
41                         }
42                 }
43
44                 protected void Error (string message)
45                 {
46                         Report.Error (-218, "Invalid constraints clause for type " +
47                                       "parameter `{0}': {1}", type_parameter, message);
48                 }
49
50                 bool has_ctor_constraint;
51                 Type class_constraint;
52                 ArrayList iface_constraints;
53                 Type[] constraint_types;
54                 int num_constraints;
55
56                 public bool HasConstructorConstraint {
57                         get { return has_ctor_constraint; }
58                 }
59
60                 public Type[] Types {
61                         get { return constraint_types; }
62                 }
63
64                 public bool Resolve (DeclSpace ds)
65                 {
66                         iface_constraints = new ArrayList ();
67
68                         if (constraints == null) {
69                                 constraint_types = new Type [0];
70                                 return true;
71                         }
72
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.");
77                                         return false;
78                                 }
79
80                                 if (obj is bool) {
81                                         has_ctor_constraint = true;
82                                         continue;
83                                 }
84
85                                 Expression expr = ds.ResolveTypeExpr ((Expression) obj, false, loc);
86                                 if (expr == null)
87                                         return false;
88
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.");
94                                         return false;
95                                 } else
96                                         class_constraint = etype;
97
98                                 num_constraints++;
99                         }
100
101                         constraint_types = new Type [num_constraints];
102                         int pos = 0;
103                         if (class_constraint != null)
104                                 constraint_types [pos++] = class_constraint;
105                         iface_constraints.CopyTo (constraint_types, pos);
106
107                         return true;
108                 }
109         }
110
111         //
112         // This type represents a generic type parameter
113         //
114         public class TypeParameter {
115                 string name;
116                 Constraints constraints;
117                 Location loc;
118                 Type type;
119
120                 public TypeParameter (string name, Constraints constraints, Location loc)
121                 {
122                         this.name = name;
123                         this.constraints = constraints;
124                         this.loc = loc;
125                 }
126
127                 public string Name {
128                         get {
129                                 return name;
130                         }
131                 }
132
133                 public Location Location {
134                         get {
135                                 return loc;
136                         }
137                 }
138
139                 public Constraints Constraints {
140                         get {
141                                 return constraints;
142                         }
143                 }
144
145                 public Type Type {
146                         get {
147                                 return type;
148                         }
149                 }
150
151                 public bool Resolve (DeclSpace ds)
152                 {
153                         if (constraints != null)
154                                 return constraints.Resolve (ds);
155
156                         return true;
157                 }
158
159                 public Type Define (TypeBuilder tb)
160                 {
161                         if (constraints != null)
162                                 type = tb.DefineGenericParameter (name, constraints.Types);
163                         else
164                                 type = tb.DefineGenericParameter (name, new Type [0]);
165
166                         return type;
167                 }
168
169                 public Type DefineMethod (MethodBuilder mb)
170                 {
171                         if (constraints != null)
172                                 type = mb.DefineGenericParameter (name, constraints.Types);
173                         else
174                                 type = mb.DefineGenericParameter (name, new Type [0]);
175
176                         return type;
177                 }
178
179                 public override string ToString ()
180                 {
181                         return "TypeParameter[" + name + "]";
182                 }
183         }
184
185         //
186         // This type represents a generic type parameter reference.
187         //
188         // These expressions are born in a fully resolved state.
189         //
190         public class TypeParameterExpr : TypeExpr {
191                 TypeParameter type_parameter;
192
193                 public override string Name {
194                         get {
195                                 return type_parameter.Name;
196                         }
197                 }
198
199                 public TypeParameter TypeParameter {
200                         get {
201                                 return type_parameter;
202                         }
203                 }
204                 
205                 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
206                 {
207                         this.type_parameter = type_parameter;
208                 }
209
210                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
211                 {
212                         type = type_parameter.Type;
213
214                         return this;
215                 }
216
217                 public void Error_CannotUseAsUnmanagedType (Location loc)
218                 {
219                         Report.Error (-203, loc, "Can not use type parameter as unamanged type");
220                 }
221         }
222
223         public class TypeArguments {
224                 ArrayList args;
225                 Type[] atypes;
226                 bool has_type_args;
227                 
228                 public TypeArguments ()
229                 {
230                         args = new ArrayList ();
231                 }
232
233                 public void Add (Expression type)
234                 {
235                         args.Add (type);
236                 }
237
238                 public Type[] Arguments {
239                         get {
240                                 return atypes;
241                         }
242                 }
243
244                 public bool HasTypeArguments {
245                         get {
246                                 return has_type_args;
247                         }
248                 }
249
250                 public override string ToString ()
251                 {
252                         StringBuilder s = new StringBuilder ();
253
254                         int count = args.Count;
255                         for (int i = 0; i < count; i++){
256                                 //
257                                 // FIXME: Use TypeManager.CSharpname once we have the type
258                                 //
259                                 s.Append (args [i].ToString ());
260                                 if (i+1 < count)
261                                         s.Append (", ");
262                         }
263                         return s.ToString ();
264                 }
265
266                 public bool Resolve (EmitContext ec)
267                 {
268                         int count = args.Count;
269                         bool ok = true;
270
271                         atypes = new Type [count];
272                         
273                         for (int i = 0; i < count; i++){
274                                 Expression e = ((Expression)args [i]).ResolveAsTypeTerminal (ec);
275                                 if (e == null) {
276                                         ok = false;
277                                         continue;
278                                 }
279                                 if (e is TypeParameterExpr)
280                                         has_type_args = true;
281                                 args [i] = e;
282                                 atypes [i] = e.Type;
283                         }
284                         return ok;
285                 }
286         }
287         
288         public class ConstructedType : TypeExpr {
289                 string name, full_name;
290                 TypeArguments args;
291                 Type[] gen_params, atypes;
292                 Type gt;
293                 
294                 public ConstructedType (string name, TypeArguments args, Location l)
295                 {
296                         loc = l;
297                         this.name = name;
298                         this.args = args;
299                         eclass = ExprClass.Type;
300
301                         full_name = name + "<" + args.ToString () + ">";
302                 }
303
304                 protected bool CheckConstraints (int index)
305                 {
306                         Type atype = args.Arguments [index];
307                         Type ptype = gen_params [index];
308
309                         //// FIXME
310                         return true;
311
312                         //
313                         // First, check parent class.
314                         //
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);
320                                 return false;
321                         }
322
323                         //
324                         // Now, check the interfaces.
325                         //
326                         foreach (Type itype in ptype.GetInterfaces ()) {
327                                 if (TypeManager.ImplementsInterface (atype, itype))
328                                         continue;
329
330                                 Report.Error (-219, loc, "Cannot create constructed type `{0}: " +
331                                               "type argument `{1}' must implement interface `{2}'.",
332                                               full_name, atype, itype);
333                                 return false;
334                         }
335
336                         return true;
337                 }
338
339                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
340                 {
341                         //
342                         // First, resolve the generic type.
343                         //
344                         SimpleName sn = new SimpleName (name, loc);
345                         TypeExpr resolved = sn.ResolveAsTypeTerminal (ec);
346                         if (resolved == null)
347                                 return null;
348
349                         if (resolved.Type == null) {
350                                 Report.Error (-220, loc, "Failed to resolve constructed type `{0}'",
351                                               full_name);
352                                 return null;
353                         }
354
355                         gt = resolved.Type.GetGenericTypeDefinition ();
356                         return this;
357                 }
358
359                 public override Type ResolveType (EmitContext ec)
360                 {
361                         //
362                         // Resolve the arguments.
363                         //
364                         if (args.Resolve (ec) == false)
365                                 return null;
366
367                         gen_params = gt.GetGenericArguments ();
368                         atypes = args.Arguments;
369
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);
374                                 return null;
375                         }
376
377                         for (int i = 0; i < gen_params.Length; i++) {
378                                 if (!CheckConstraints (i))
379                                         return null;
380                         }
381
382                         //
383                         // Now bind the parameters.
384                         //
385                         type = gt.BindGenericParameters (atypes);
386                         return type;
387                 }
388
389                 public override bool CheckAccessLevel (DeclSpace ds)
390                 {
391                         return ds.CheckAccessLevel (gt);
392                 }
393
394                 public override bool AsAccessible (DeclSpace ds, int flags)
395                 {
396                         return ds.AsAccessible (gt, flags);
397                 }
398
399                 public override bool IsClass {
400                         get { return gt.IsClass; }
401                 }
402
403                 public override bool IsValueType {
404                         get { return gt.IsValueType; }
405                 }
406
407                 public override bool IsInterface {
408                         get { return gt.IsInterface; }
409                 }
410
411                 public override bool IsSealed {
412                         get { return gt.IsSealed; }
413                 }
414
415                 public override TypeExpr[] GetInterfaces ()
416                 {
417                         TypeExpr[] ifaces = TypeManager.GetInterfaces (gt);
418                         return ifaces;
419                 }
420
421                 public override string Name {
422                         get {
423                                 return full_name;
424                         }
425                 }
426         }
427
428         public class GenericMethod : DeclSpace
429         {
430                 public GenericMethod (NamespaceEntry ns, TypeContainer parent, string name, Location l)
431                         : base (ns, parent, name, l)
432                 { }
433
434                 public override TypeBuilder DefineType ()
435                 {
436                         throw new Exception ();
437                 }
438
439                 public override bool Define (TypeContainer parent)
440                 {
441                         return true;
442                 }
443
444                 public bool Define (MethodBuilder mb)
445                 {
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);
449
450                         return true;
451                 }
452
453                 public override bool DefineMembers (TypeContainer parent)
454                 {
455                         return true;
456                 }
457
458                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
459                                                         MemberFilter filter, object criteria)
460                 {
461                         throw new Exception ();
462                 }               
463
464                 public override MemberCache MemberCache {
465                         get {
466                                 throw new Exception ();
467                         }
468                 }
469         }
470
471         public class GenericMemberAccess : MemberAccess
472         {
473                 TypeArguments args;
474
475                 public GenericMemberAccess (Expression expr, string id, TypeArguments args, Location loc)
476                         : base (expr, id, loc)
477                 {
478                         this.args = args;
479                 }
480
481                 public override Expression DoResolve (EmitContext ec, Expression right_side,
482                                                       ResolveFlags flags)
483                 {
484                         Expression expr = base.DoResolve (ec, right_side, flags);
485                         if (expr == null)
486                                 return null;
487
488                         MethodGroupExpr mg = expr as MethodGroupExpr;
489                         if (mg == null) {
490                                 Report.Error (-220, loc, "Member `{0}' has type arguments, but did " +
491                                               "not resolve as a method group.", Identifier);
492                                 return null;
493                         }
494
495                         if (args.Resolve (ec) == false)
496                                 return null;
497
498                         Type[] atypes = args.Arguments;
499
500                         ArrayList list = new ArrayList ();
501
502                         foreach (MethodBase method in mg.Methods) {
503                                 MethodInfo mi = method as MethodInfo;
504                                 if (mi == null)
505                                         continue;
506
507                                 Type[] gen_params = mi.GetGenericArguments ();
508                         
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);
513                                         continue;
514                                 }
515
516                                 list.Add (mi.BindGenericParameters (args.Arguments));
517                         }
518
519                         MethodInfo[] methods = new MethodInfo [list.Count];
520                         list.CopyTo (methods, 0);
521
522                         MethodGroupExpr new_mg = new MethodGroupExpr (methods, mg.Location);
523                         new_mg.InstanceExpression = mg.InstanceExpression;
524                         return new_mg;
525                 }
526         }
527
528         public class DefaultValueExpression : Expression
529         {
530                 Expression expr;
531                 LocalTemporary temp_storage;
532
533                 public DefaultValueExpression (Expression expr, Location loc)
534                 {
535                         this.expr = expr;
536                         this.loc = loc;
537                 }
538
539                 public override Expression DoResolve (EmitContext ec)
540                 {
541                         type = ec.DeclSpace.ResolveType (expr, false, loc);
542                         if (type == null)
543                                 return null;
544
545                         if (type.IsGenericParameter || TypeManager.IsValueType (type))
546                                 temp_storage = new LocalTemporary (ec, type);
547
548                         eclass = ExprClass.Variable;
549                         return this;
550                 }
551
552                 public override void Emit (EmitContext ec)
553                 {
554                         if (temp_storage != null) {
555                                 temp_storage.AddressOf (ec, AddressOp.LoadStore);
556                                 ec.ig.Emit (OpCodes.Initobj, type);
557                                 temp_storage.Emit (ec);
558                         } else
559                                 ec.ig.Emit (OpCodes.Ldnull);
560                 }
561         }
562 }