2004-03-13 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                 TypeExpr class_constraint;
52                 ArrayList iface_constraints;
53                 TypeExpr[] constraint_types;
54                 int num_constraints;
55
56                 public bool HasConstructorConstraint {
57                         get { return has_ctor_constraint; }
58                 }
59
60                 public bool Resolve (DeclSpace ds)
61                 {
62                         iface_constraints = new ArrayList ();
63
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.");
68                                         return false;
69                                 }
70
71                                 if (obj is bool) {
72                                         has_ctor_constraint = true;
73                                         continue;
74                                 }
75
76                                 TypeExpr expr = ds.ResolveTypeExpr ((Expression) obj, false, loc);
77                                 if (expr == null)
78                                         return false;
79
80                                 if (expr.IsInterface)
81                                         iface_constraints.Add (expr);
82                                 else if (class_constraint != null) {
83                                         Error ("can have at most one class constraint.");
84                                         return false;
85                                 } else
86                                         class_constraint = expr;
87
88                                 num_constraints++;
89                         }
90
91                         constraint_types = new TypeExpr [num_constraints];
92                         int pos = 0;
93                         if (class_constraint != null)
94                                 constraint_types [pos++] = class_constraint;
95                         iface_constraints.CopyTo (constraint_types, pos);
96
97                         return true;
98                 }
99
100                 public Type[] ResolveTypes (EmitContext ec)
101                 {
102                         Type [] types = new Type [constraint_types.Length];
103
104                         for (int i = 0; i < constraint_types.Length; i++)
105                                 types [i] = constraint_types [i].ResolveType (ec);
106
107                         return types;
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                         type = tb.DefineGenericParameter (name);
162                         return type;
163                 }
164
165                 public Type DefineMethod (MethodBuilder mb)
166                 {
167                         type = mb.DefineGenericParameter (name);
168                         return type;
169                 }
170
171                 public void DefineType (EmitContext ec, TypeBuilder tb)
172                 {
173                         int index = type.GenericParameterPosition;
174                         if (constraints == null)
175                                 tb.SetGenericParameterConstraints (index, new Type [0]);
176                         else
177                                 tb.SetGenericParameterConstraints (index, constraints.ResolveTypes (ec));
178                 }
179
180                 public void DefineType (EmitContext ec, MethodBuilder mb)
181                 {
182                         int index = type.GenericParameterPosition;
183                         if (constraints == null)
184                                 mb.SetGenericParameterConstraints (index, new Type [0]);
185                         else
186                                 mb.SetGenericParameterConstraints (index, constraints.ResolveTypes (ec));
187                 }
188
189                 public override string ToString ()
190                 {
191                         return "TypeParameter[" + name + "]";
192                 }
193         }
194
195         //
196         // This type represents a generic type parameter reference.
197         //
198         // These expressions are born in a fully resolved state.
199         //
200         public class TypeParameterExpr : TypeExpr {
201                 TypeParameter type_parameter;
202
203                 public override string Name {
204                         get {
205                                 return type_parameter.Name;
206                         }
207                 }
208
209                 public TypeParameter TypeParameter {
210                         get {
211                                 return type_parameter;
212                         }
213                 }
214                 
215                 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
216                 {
217                         this.type_parameter = type_parameter;
218                 }
219
220                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
221                 {
222                         type = type_parameter.Type;
223
224                         return this;
225                 }
226
227                 public void Error_CannotUseAsUnmanagedType (Location loc)
228                 {
229                         Report.Error (-203, loc, "Can not use type parameter as unamanged type");
230                 }
231         }
232
233         public class TypeArguments {
234                 ArrayList args;
235                 Type[] atypes;
236                 bool has_type_args;
237                 
238                 public TypeArguments ()
239                 {
240                         args = new ArrayList ();
241                 }
242
243                 public void Add (Expression type)
244                 {
245                         args.Add (type);
246                 }
247
248                 public void Add (TypeArguments new_args)
249                 {
250                         args.AddRange (new_args.args);
251                 }
252
253                 public Type[] Arguments {
254                         get {
255                                 return atypes;
256                         }
257                 }
258
259                 public bool HasTypeArguments {
260                         get {
261                                 return has_type_args;
262                         }
263                 }
264
265                 public override string ToString ()
266                 {
267                         StringBuilder s = new StringBuilder ();
268
269                         int count = args.Count;
270                         for (int i = 0; i < count; i++){
271                                 //
272                                 // FIXME: Use TypeManager.CSharpname once we have the type
273                                 //
274                                 s.Append (args [i].ToString ());
275                                 if (i+1 < count)
276                                         s.Append (", ");
277                         }
278                         return s.ToString ();
279                 }
280
281                 public bool Resolve (EmitContext ec)
282                 {
283                         int count = args.Count;
284                         bool ok = true;
285
286                         atypes = new Type [count];
287                         
288                         for (int i = 0; i < count; i++){
289                                 TypeExpr e = ((Expression)args [i]).ResolveAsTypeTerminal (ec);
290                                 if (e == null) {
291                                         ok = false;
292                                         continue;
293                                 }
294                                 if (e is TypeParameterExpr)
295                                         has_type_args = true;
296                                 args [i] = e;
297                                 atypes [i] = e.ResolveType (ec);
298
299                                 if (atypes [i] == null)
300                                         ok = false;
301                         }
302                         return ok;
303                 }
304         }
305         
306         public class ConstructedType : TypeExpr {
307                 string name, full_name;
308                 TypeArguments args;
309                 Type[] gen_params, atypes;
310                 Type gt;
311                 
312                 public ConstructedType (string name, TypeArguments args, Location l)
313                 {
314                         loc = l;
315                         this.name = name;
316                         this.args = args;
317
318                         eclass = ExprClass.Type;
319                         full_name = name + "<" + args.ToString () + ">";
320                 }
321
322                 public ConstructedType (string name, TypeParameter[] type_params, Location l)
323                 {
324                         loc = l;
325                         this.name = name;
326
327                         args = new TypeArguments ();
328                         foreach (TypeParameter type_param in type_params)
329                                 args.Add (new TypeParameterExpr (type_param, l));
330
331                         eclass = ExprClass.Type;
332                         full_name = name + "<" + args.ToString () + ">";
333                 }
334
335                 public ConstructedType (Type t, TypeParameter[] type_params, Location l)
336                         : this (t.Name, type_params, l)
337                 {
338                         gt = t.GetGenericTypeDefinition ();
339                 }
340
341                 public ConstructedType (Type t, TypeArguments args, Location l)
342                         : this (t.Name, args, l)
343                 {
344                         gt = t.GetGenericTypeDefinition ();
345                 }
346
347                 public TypeArguments TypeArguments {
348                         get { return args; }
349                 }
350
351                 protected bool CheckConstraints (int index)
352                 {
353                         Type atype = atypes [index];
354                         Type ptype = gen_params [index];
355
356                         //// FIXME
357                         return true;
358
359                         //
360                         // First, check parent class.
361                         //
362                         if ((ptype.BaseType != atype.BaseType) &&
363                             !atype.BaseType.IsSubclassOf (ptype.BaseType)) {
364                                 Report.Error (-219, loc, "Cannot create constructed type `{0}': " +
365                                               "type argument `{1}' must derive from `{2}'.",
366                                               full_name, atype, ptype.BaseType);
367                                 return false;
368                         }
369
370                         //
371                         // Now, check the interfaces.
372                         //
373                         foreach (Type itype in ptype.GetInterfaces ()) {
374                                 if (TypeManager.ImplementsInterface (atype, itype))
375                                         continue;
376
377                                 Report.Error (-219, loc, "Cannot create constructed type `{0}: " +
378                                               "type argument `{1}' must implement interface `{2}'.",
379                                               full_name, atype, itype);
380                                 return false;
381                         }
382
383                         return true;
384                 }
385
386                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
387                 {
388                         if (gt != null)
389                                 return this;
390
391                         //
392                         // First, resolve the generic type.
393                         //
394                         SimpleName sn = new SimpleName (name, loc);
395                         TypeExpr resolved = sn.ResolveAsTypeTerminal (ec);
396                         if (resolved == null)
397                                 return null;
398
399                         if (resolved.Type == null) {
400                                 Report.Error (-220, loc, "Failed to resolve constructed type `{0}'",
401                                               full_name);
402                                 return null;
403                         }
404
405                         gt = resolved.Type.GetGenericTypeDefinition ();
406                         return this;
407                 }
408
409                 public override Type ResolveType (EmitContext ec)
410                 {
411                         if (type != null)
412                                 return type;
413                         if (DoResolveAsTypeStep (ec) == null)
414                                 return null;
415
416                         //
417                         // Resolve the arguments.
418                         //
419                         if (args.Resolve (ec) == false) {
420                                 Report.Error (-220, loc, "Failed to resolve constructed type `{0}'",
421                                               full_name);
422                                 return null;
423                         }
424
425                         gen_params = gt.GetGenericArguments ();
426
427                         DeclSpace decl = ec.DeclSpace, parent = null;
428                         while (decl != null) {
429                                 if (TypeManager.IsNestedChildOf (gt, decl.TypeBuilder)) {
430                                         parent = decl;
431                                         break;
432                                 }
433                                 decl = decl.Parent;
434                         }
435
436                         if (parent != null) {
437                                 TypeParameter[] pparams = parent.TypeParameters;
438
439                                 atypes = new Type [args.Arguments.Length + pparams.Length];
440                                 for (int i = 0; i < pparams.Length; i++) {
441                                         TypeParameter pparam = pparams [i];
442                                         if (pparam.Type == null)
443                                                 throw new Exception ();
444                                         atypes [i] = pparam.Type;
445                                 }
446                                 args.Arguments.CopyTo (atypes, pparams.Length);
447                         } else
448                                 atypes = args.Arguments;
449
450                         if (atypes.Length != gen_params.Length) {
451                                 Report.Error (-217, loc, "Generic type `{0}' takes {1} " +
452                                               "type parameters, but specified {2}.", gt.Name,
453                                               gen_params.Length, atypes.Length);
454                                 return null;
455                         }
456
457                         for (int i = 0; i < gen_params.Length; i++) {
458                                 if (!CheckConstraints (i))
459                                         return null;
460                         }
461
462                         //
463                         // Now bind the parameters.
464                         //
465                         type = gt.BindGenericParameters (atypes);
466                         return type;
467                 }
468
469                 public Expression GetMemberAccess (TypeExpr current_type)
470                 {
471                         return new GenericMemberAccess (current_type, name, args, loc);
472                 }
473
474                 public override bool CheckAccessLevel (DeclSpace ds)
475                 {
476                         return ds.CheckAccessLevel (gt);
477                 }
478
479                 public override bool AsAccessible (DeclSpace ds, int flags)
480                 {
481                         return ds.AsAccessible (gt, flags);
482                 }
483
484                 public override bool IsClass {
485                         get { return gt.IsClass; }
486                 }
487
488                 public override bool IsValueType {
489                         get { return gt.IsValueType; }
490                 }
491
492                 public override bool IsInterface {
493                         get { return gt.IsInterface; }
494                 }
495
496                 public override bool IsSealed {
497                         get { return gt.IsSealed; }
498                 }
499
500                 public override TypeExpr[] GetInterfaces ()
501                 {
502                         TypeExpr[] ifaces = TypeManager.GetInterfaces (gt);
503                         return ifaces;
504                 }
505
506                 public override string Name {
507                         get {
508                                 return full_name;
509                         }
510                 }
511         }
512
513         public class GenericMethod : DeclSpace
514         {
515                 public GenericMethod (NamespaceEntry ns, TypeContainer parent, string name,
516                                       Attributes attrs, Location l)
517                         : base (ns, parent, name, attrs, l)
518                 { }
519
520                 public override TypeBuilder DefineType ()
521                 {
522                         throw new Exception ();
523                 }
524
525                 public override bool Define (TypeContainer parent)
526                 {
527                         return true;
528                 }
529
530                 public bool Define (MethodBuilder mb)
531                 {
532                         Type[] gen_params = new Type [TypeParameters.Length];
533                         for (int i = 0; i < TypeParameters.Length; i++)
534                                 gen_params [i] = TypeParameters [i].DefineMethod (mb);
535
536                         return true;
537                 }
538
539                 public bool DefineType (EmitContext ec, MethodBuilder mb)
540                 {
541                         for (int i = 0; i < TypeParameters.Length; i++)
542                                 TypeParameters [i].DefineType (ec, mb);
543
544                         return true;
545                 }
546
547                 public override bool DefineMembers (TypeContainer parent)
548                 {
549                         return true;
550                 }
551
552                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
553                                                         MemberFilter filter, object criteria)
554                 {
555                         throw new Exception ();
556                 }               
557
558                 public override MemberCache MemberCache {
559                         get {
560                                 throw new Exception ();
561                         }
562                 }
563         }
564
565         public class GenericMemberAccess : MemberAccess
566         {
567                 TypeArguments args;
568
569                 public GenericMemberAccess (Expression expr, string id, TypeArguments args, Location loc)
570                         : base (expr, id, loc)
571                 {
572                         this.args = args;
573                 }
574
575                 public override Expression DoResolve (EmitContext ec, Expression right_side,
576                                                       ResolveFlags flags)
577                 {
578                         Expression expr = base.DoResolve (ec, right_side, flags);
579                         if (expr == null)
580                                 return null;
581
582                         MethodGroupExpr mg = expr as MethodGroupExpr;
583                         if (mg == null) {
584                                 Report.Error (-220, loc, "Member `{0}' has type arguments, but did " +
585                                               "not resolve as a method group.", Identifier);
586                                 return null;
587                         }
588
589                         if (args.Resolve (ec) == false)
590                                 return null;
591
592                         Type[] atypes = args.Arguments;
593
594                         ArrayList list = new ArrayList ();
595
596                         foreach (MethodBase method in mg.Methods) {
597                                 MethodInfo mi = method as MethodInfo;
598                                 if (mi == null)
599                                         continue;
600
601                                 Type[] gen_params = mi.GetGenericArguments ();
602                         
603                                 if (atypes.Length != gen_params.Length) {
604                                         Report.Error (-217, loc, "Generic method `{0}' takes {1} " +
605                                                       "type parameters, but specified {2}.", mi.Name,
606                                                       gen_params.Length, atypes.Length);
607                                         continue;
608                                 }
609
610                                 list.Add (mi.BindGenericParameters (args.Arguments));
611                         }
612
613                         MethodInfo[] methods = new MethodInfo [list.Count];
614                         list.CopyTo (methods, 0);
615
616                         MethodGroupExpr new_mg = new MethodGroupExpr (methods, mg.Location);
617                         new_mg.InstanceExpression = mg.InstanceExpression;
618                         return new_mg;
619                 }
620
621                 public override Expression ResolveAsTypeStep (EmitContext ec)
622                 {
623                         ConstructedType cexpr = expr as ConstructedType;
624                         if (cexpr == null)
625                                 throw new Exception ();
626
627                         expr = base.ResolveAsTypeStep (ec);
628                         if (expr == null)
629                                 return null;
630
631                         Type t = ((TypeExpr) expr).ResolveType (ec);
632                         if (t == null)
633                                 return null;
634
635                         TypeArguments new_args = new TypeArguments ();
636                         new_args.Add (cexpr.TypeArguments);
637                         new_args.Add (args);
638
639                         ConstructedType ctype = new ConstructedType (t, new_args, loc);
640                         return ctype.ResolveAsTypeStep (ec);
641                 }
642         }
643
644         public class DefaultValueExpression : Expression
645         {
646                 Expression expr;
647                 LocalTemporary temp_storage;
648
649                 public DefaultValueExpression (Expression expr, Location loc)
650                 {
651                         this.expr = expr;
652                         this.loc = loc;
653                 }
654
655                 public override Expression DoResolve (EmitContext ec)
656                 {
657                         type = ec.DeclSpace.ResolveType (expr, false, loc);
658                         if (type == null)
659                                 return null;
660
661                         if (type.IsGenericParameter || TypeManager.IsValueType (type))
662                                 temp_storage = new LocalTemporary (ec, type);
663
664                         eclass = ExprClass.Variable;
665                         return this;
666                 }
667
668                 public override void Emit (EmitContext ec)
669                 {
670                         if (temp_storage != null) {
671                                 temp_storage.AddressOf (ec, AddressOp.LoadStore);
672                                 ec.ig.Emit (OpCodes.Initobj, type);
673                                 temp_storage.Emit (ec);
674                         } else
675                                 ec.ig.Emit (OpCodes.Ldnull);
676                 }
677         }
678 }