2003-10-29 Ben Maurer <bmaurer@users.sourceforge.net>
[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                         : base (type_parameter.Type, loc)
207                 {
208                         this.type_parameter = type_parameter;
209                 }
210
211                 public override Expression ResolveAsTypeStep (EmitContext ec)
212                 {
213                         type = type_parameter.Type;
214
215                         return this;
216                 }
217
218                 public override string ToString ()
219                 {
220                         return "TypeParameterExpr[" + type_parameter.Name + "]";
221                 }
222
223                 public void Error_CannotUseAsUnmanagedType (Location loc)
224                 {
225                         Report.Error (-203, loc, "Can not use type parameter as unamanged type");
226                 }
227         }
228
229         public class TypeArguments {
230                 ArrayList args;
231                 Type[] atypes;
232                 bool has_type_args;
233                 
234                 public TypeArguments ()
235                 {
236                         args = new ArrayList ();
237                 }
238
239                 public void Add (Expression type)
240                 {
241                         args.Add (type);
242                 }
243
244                 public Type[] Arguments {
245                         get {
246                                 return atypes;
247                         }
248                 }
249
250                 public bool HasTypeArguments {
251                         get {
252                                 return has_type_args;
253                         }
254                 }
255
256                 public override string ToString ()
257                 {
258                         StringBuilder s = new StringBuilder ();
259
260                         int count = args.Count;
261                         for (int i = 0; i < count; i++){
262                                 //
263                                 // FIXME: Use TypeManager.CSharpname once we have the type
264                                 //
265                                 s.Append (args [i].ToString ());
266                                 if (i+1 < count)
267                                         s.Append (", ");
268                         }
269                         return s.ToString ();
270                 }
271
272                 public bool Resolve (EmitContext ec)
273                 {
274                         int count = args.Count;
275                         bool ok = true;
276
277                         atypes = new Type [count];
278                         
279                         for (int i = 0; i < count; i++){
280                                 Expression e = ((Expression)args [i]).ResolveAsTypeTerminal (ec);
281                                 if (e == null) {
282                                         ok = false;
283                                         continue;
284                                 }
285                                 if (e is TypeParameterExpr)
286                                         has_type_args = true;
287                                 args [i] = e;
288                                 atypes [i] = e.Type;
289                         }
290                         return ok;
291                 }
292         }
293         
294         public class ConstructedType : TypeExpr {
295                 Expression container_type;
296                 string name, full_name;
297                 TypeArguments args;
298                 Type[] gen_params, atypes;
299                 Type gt;
300                 
301                 public ConstructedType (string name, TypeArguments args, Location l)
302                         : base (null, l)
303                 {
304                         loc = l;
305                         this.container_type = container_type;
306                         this.name = name;
307                         this.args = args;
308                         eclass = ExprClass.Type;
309
310                         full_name = name + "<" + args.ToString () + ">";
311                 }
312
313                 public override Expression DoResolve (EmitContext ec)
314                 {
315                         if (args.Resolve (ec) == false)
316                                 return null;
317
318                         //
319                         // Pretend there are not type parameters, until we get GetType support
320                         //
321                         return new SimpleName (name, loc).DoResolve (ec);
322                 }
323
324                 protected bool CheckConstraints (int index)
325                 {
326                         Type atype = args.Arguments [index];
327                         Type ptype = gen_params [index];
328
329                         //// FIXME
330                         return true;
331
332                         //
333                         // First, check parent class.
334                         //
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);
340                                 return false;
341                         }
342
343                         //
344                         // Now, check the interfaces.
345                         //
346                         foreach (Type itype in ptype.GetInterfaces ()) {
347                                 if (TypeManager.ImplementsInterface (atype, itype))
348                                         continue;
349
350                                 Report.Error (-219, loc, "Cannot create constructed type `{0}: " +
351                                               "type argument `{1}' must implement interface `{2}'.",
352                                               full_name, atype, itype);
353                                 return false;
354                         }
355
356                         return true;
357                 }
358
359                 public override Expression ResolveAsTypeStep (EmitContext ec)
360                 {
361                         //
362                         // First, resolve the generic type.
363                         //
364                         SimpleName sn = new SimpleName (name, loc);
365                         Expression resolved = sn.ResolveAsTypeStep (ec);
366                         if (resolved == null)
367                                 return null;
368
369                         if (resolved.Type == null) {
370                                 Report.Error (-220, loc, "Failed to resolve constructed type `{0}'",
371                                               full_name);
372                                 return null;
373                         }
374
375                         gt = resolved.Type.GetGenericTypeDefinition ();
376                         return this;
377                 }
378
379                 public Type Resolve (EmitContext ec, TypeBuilder parent)
380                 {
381                         //
382                         // Resolve the arguments.
383                         //
384                         if (args.Resolve (ec) == false)
385                                 return null;
386
387                         gen_params = gt.GetGenericArguments ();
388                         atypes = args.Arguments;
389
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);
394                                 return null;
395                         }
396
397                         if (args.HasTypeArguments) {
398                                 type = parent;
399                                 return parent;
400                         }
401
402                         for (int i = 0; i < gen_params.Length; i++) {
403                                 if (!CheckConstraints (i))
404                                         return null;
405                         }
406
407                         //
408                         // Now bind the parameters.
409                         //
410                         type = gt.BindGenericParameters (args.Arguments);
411                         return type;
412                 }
413                 
414                 public override void Emit (EmitContext ec)
415                 {
416                         //
417                         // Never reached for now
418                         //
419                         throw new Exception ("IMPLEMENT ME");
420                 }
421
422                 public override string ToString ()
423                 {
424                         return full_name;
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 }