2004-03-16 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                         this.loc = loc;
219                 }
220
221                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
222                 {
223                         type = type_parameter.Type;
224
225                         return this;
226                 }
227
228                 public void Error_CannotUseAsUnmanagedType (Location loc)
229                 {
230                         Report.Error (-203, loc, "Can not use type parameter as unamanged type");
231                 }
232         }
233
234         public class TypeArguments {
235                 public readonly Location Location;
236                 ArrayList args;
237                 Type[] atypes;
238                 bool has_type_args;
239                 bool created;
240                 
241                 public TypeArguments (Location loc)
242                 {
243                         args = new ArrayList ();
244                         this.Location = loc;
245                 }
246
247                 public void Add (Expression type)
248                 {
249                         if (created)
250                                 throw new InvalidOperationException ();
251
252                         args.Add (type);
253                 }
254
255                 public void Add (TypeArguments new_args)
256                 {
257                         if (created)
258                                 throw new InvalidOperationException ();
259
260                         args.AddRange (new_args.args);
261                 }
262
263                 public Type[] Arguments {
264                         get {
265                                 return atypes;
266                         }
267                 }
268
269                 public bool HasTypeArguments {
270                         get {
271                                 return has_type_args;
272                         }
273                 }
274
275                 public int Count {
276                         get {
277                                 return args.Count;
278                         }
279                 }
280
281                 public override string ToString ()
282                 {
283                         StringBuilder s = new StringBuilder ();
284
285                         int count = args.Count;
286                         for (int i = 0; i < count; i++){
287                                 //
288                                 // FIXME: Use TypeManager.CSharpname once we have the type
289                                 //
290                                 s.Append (args [i].ToString ());
291                                 if (i+1 < count)
292                                         s.Append (", ");
293                         }
294                         return s.ToString ();
295                 }
296
297                 public bool Resolve (EmitContext ec)
298                 {
299                         DeclSpace ds = ec.DeclSpace;
300                         int count = args.Count;
301                         bool ok = true;
302
303                         atypes = new Type [count];
304                         
305                         for (int i = 0; i < count; i++){
306                                 TypeExpr te = ds.ResolveTypeExpr (
307                                         (Expression) args [i], false, Location);
308                                 if (te == null) {
309                                         ok = false;
310                                         continue;
311                                 }
312                                 if (te is TypeParameterExpr)
313                                         has_type_args = true;
314                                 atypes [i] = te.ResolveType (ec);
315
316                                 if (atypes [i] == null) {
317                                         Report.Error (246, Location, "Cannot find type `{0}'",
318                                                       te.Name);
319                                         ok = false;
320                                 }
321                         }
322                         return ok;
323                 }
324         }
325         
326         public class ConstructedType : TypeExpr {
327                 string name, full_name;
328                 TypeArguments args;
329                 Type[] gen_params, atypes;
330                 Type gt;
331                 
332                 public ConstructedType (string name, TypeArguments args, Location l)
333                 {
334                         loc = l;
335                         this.name = name;
336                         this.args = args;
337
338                         eclass = ExprClass.Type;
339                         full_name = name + "<" + args.ToString () + ">";
340                 }
341
342                 public ConstructedType (string name, TypeParameter[] type_params, Location l)
343                 {
344                         loc = l;
345                         this.name = name;
346
347                         args = new TypeArguments (l);
348                         foreach (TypeParameter type_param in type_params)
349                                 args.Add (new TypeParameterExpr (type_param, l));
350
351                         eclass = ExprClass.Type;
352                         full_name = name + "<" + args.ToString () + ">";
353                 }
354
355                 public ConstructedType (Type t, TypeParameter[] type_params, Location l)
356                         : this (t.Name, type_params, l)
357                 {
358                         gt = t.GetGenericTypeDefinition ();
359                 }
360
361                 public ConstructedType (Type t, TypeArguments args, Location l)
362                         : this (t.Name, args, l)
363                 {
364                         gt = t.GetGenericTypeDefinition ();
365                 }
366
367                 public TypeArguments TypeArguments {
368                         get { return args; }
369                 }
370
371                 protected bool CheckConstraints (int index)
372                 {
373                         Type atype = atypes [index];
374                         Type ptype = gen_params [index];
375
376                         //// FIXME
377                         return true;
378
379                         //
380                         // First, check parent class.
381                         //
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);
387                                 return false;
388                         }
389
390                         //
391                         // Now, check the interfaces.
392                         //
393                         foreach (Type itype in ptype.GetInterfaces ()) {
394                                 if (TypeManager.ImplementsInterface (atype, itype))
395                                         continue;
396
397                                 Report.Error (-219, loc, "Cannot create constructed type `{0}: " +
398                                               "type argument `{1}' must implement interface `{2}'.",
399                                               full_name, atype, itype);
400                                 return false;
401                         }
402
403                         return true;
404                 }
405
406                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
407                 {
408                         if (gt != null)
409                                 return this;
410
411                         //
412                         // First, resolve the generic type.
413                         //
414                         DeclSpace ds;
415                         Type nested = ec.DeclSpace.FindNestedType (loc, name, out ds);
416                         if (nested != null) {
417                                 gt = nested.GetGenericTypeDefinition ();
418
419                                 TypeArguments new_args = new TypeArguments (loc);
420                                 foreach (TypeParameter param in ds.TypeParameters)
421                                         new_args.Add (new TypeParameterExpr (param, loc));
422                                 new_args.Add (args);
423
424                                 args = new_args;
425                                 return this;
426                         }
427
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);
437                                         return null;
438                                 }
439
440                                 Type t = resolved.Type;
441                                 int num_args = TypeManager.GetNumberOfTypeArguments (t);
442
443                                 if (num_args == 0) {
444                                         Report.Error (308, loc,
445                                                       "The non-generic type `{0}' cannot " +
446                                                       "be used with type arguments.",
447                                                       TypeManager.CSharpName (t));
448                                         return null;
449                                 }
450
451                                 Report.Error (305, loc,
452                                               "Using the generic type `{0}' " +
453                                               "requires {1} type arguments",
454                                               TypeManager.GetFullName (t), num_args);
455                                 return null;
456                         }
457
458                         if (resolved.Type == null)
459                                 throw new InternalErrorException (
460                                         "Failed to resolve constructed type `{0}'",
461                                         full_name);
462
463                         gt = resolved.Type.GetGenericTypeDefinition ();
464                         return this;
465                 }
466
467                 public override Type ResolveType (EmitContext ec)
468                 {
469                         if (type != null)
470                                 return type;
471                         if (DoResolveAsTypeStep (ec) == null)
472                                 return null;
473
474                         //
475                         // Resolve the arguments.
476                         //
477                         if (args.Resolve (ec) == false)
478                                 return null;
479
480                         gen_params = gt.GetGenericArguments ();
481                         atypes = args.Arguments;
482
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);
487                                 return null;
488                         }
489
490                         for (int i = 0; i < gen_params.Length; i++) {
491                                 if (!CheckConstraints (i))
492                                         return null;
493                         }
494
495                         //
496                         // Now bind the parameters.
497                         //
498                         type = gt.BindGenericParameters (atypes);
499                         return type;
500                 }
501
502                 public Expression GetMemberAccess (TypeExpr current_type)
503                 {
504                         return new GenericMemberAccess (current_type, name, args, loc);
505                 }
506
507                 public override bool CheckAccessLevel (DeclSpace ds)
508                 {
509                         return ds.CheckAccessLevel (gt);
510                 }
511
512                 public override bool AsAccessible (DeclSpace ds, int flags)
513                 {
514                         return ds.AsAccessible (gt, flags);
515                 }
516
517                 public override bool IsClass {
518                         get { return gt.IsClass; }
519                 }
520
521                 public override bool IsValueType {
522                         get { return gt.IsValueType; }
523                 }
524
525                 public override bool IsInterface {
526                         get { return gt.IsInterface; }
527                 }
528
529                 public override bool IsSealed {
530                         get { return gt.IsSealed; }
531                 }
532
533                 public override TypeExpr[] GetInterfaces ()
534                 {
535                         TypeExpr[] ifaces = TypeManager.GetInterfaces (gt);
536                         return ifaces;
537                 }
538
539                 public override string Name {
540                         get {
541                                 return full_name;
542                         }
543                 }
544         }
545
546         public class GenericMethod : DeclSpace
547         {
548                 public GenericMethod (NamespaceEntry ns, TypeContainer parent, string name,
549                                       Attributes attrs, Location l)
550                         : base (ns, parent, name, attrs, l)
551                 { }
552
553                 public override TypeBuilder DefineType ()
554                 {
555                         throw new Exception ();
556                 }
557
558                 public override bool Define (TypeContainer parent)
559                 {
560                         return true;
561                 }
562
563                 public bool Define (MethodBuilder mb)
564                 {
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);
568
569                         return true;
570                 }
571
572                 public bool DefineType (EmitContext ec, MethodBuilder mb)
573                 {
574                         for (int i = 0; i < TypeParameters.Length; i++)
575                                 TypeParameters [i].DefineType (ec, mb);
576
577                         return true;
578                 }
579
580                 public override bool DefineMembers (TypeContainer parent)
581                 {
582                         return true;
583                 }
584
585                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
586                                                         MemberFilter filter, object criteria)
587                 {
588                         throw new Exception ();
589                 }               
590
591                 public override MemberCache MemberCache {
592                         get {
593                                 throw new Exception ();
594                         }
595                 }
596         }
597
598         public class GenericMemberAccess : MemberAccess
599         {
600                 TypeArguments args;
601
602                 public GenericMemberAccess (Expression expr, string id, TypeArguments args, Location loc)
603                         : base (expr, id, args.Count, loc)
604                 {
605                         this.args = args;
606                 }
607
608                 public override Expression DoResolve (EmitContext ec, Expression right_side,
609                                                       ResolveFlags flags)
610                 {
611                         Expression expr = base.DoResolve (ec, right_side, flags);
612                         if (expr == null)
613                                 return null;
614
615                         MethodGroupExpr mg = expr as MethodGroupExpr;
616                         if (mg == null) {
617                                 Report.Error (-220, loc, "Member `{0}' has type arguments, but did " +
618                                               "not resolve as a method group.", Identifier);
619                                 return null;
620                         }
621
622                         if (args.Resolve (ec) == false)
623                                 return null;
624
625                         Type[] atypes = args.Arguments;
626
627                         ArrayList list = new ArrayList ();
628
629                         foreach (MethodBase method in mg.Methods) {
630                                 MethodInfo mi = method as MethodInfo;
631                                 if (mi == null)
632                                         continue;
633
634                                 Type[] gen_params = mi.GetGenericArguments ();
635                         
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);
640                                         continue;
641                                 }
642
643                                 list.Add (mi.BindGenericParameters (args.Arguments));
644                         }
645
646                         MethodInfo[] methods = new MethodInfo [list.Count];
647                         list.CopyTo (methods, 0);
648
649                         MethodGroupExpr new_mg = new MethodGroupExpr (methods, mg.Location);
650                         new_mg.InstanceExpression = mg.InstanceExpression;
651                         return new_mg;
652                 }
653
654                 public override Expression ResolveAsTypeStep (EmitContext ec)
655                 {
656                         ConstructedType cexpr = expr as ConstructedType;
657                         if (cexpr != null) {
658                                 TypeArguments new_args = new TypeArguments (loc);
659                                 new_args.Add (cexpr.TypeArguments);
660                                 new_args.Add (args);
661
662                                 args = new_args;
663                         }
664
665                         expr = base.ResolveAsTypeStep (ec);
666                         if (expr == null)
667                                 return null;
668
669                         Type t = ((TypeExpr) expr).ResolveType (ec);
670                         if (t == null)
671                                 return null;
672
673                         ConstructedType ctype = new ConstructedType (t, args, loc);
674                         return ctype.ResolveAsTypeStep (ec);
675                 }
676         }
677
678         public class DefaultValueExpression : Expression
679         {
680                 Expression expr;
681                 LocalTemporary temp_storage;
682
683                 public DefaultValueExpression (Expression expr, Location loc)
684                 {
685                         this.expr = expr;
686                         this.loc = loc;
687                 }
688
689                 public override Expression DoResolve (EmitContext ec)
690                 {
691                         type = ec.DeclSpace.ResolveType (expr, false, loc);
692                         if (type == null)
693                                 return null;
694
695                         if (type.IsGenericParameter || TypeManager.IsValueType (type))
696                                 temp_storage = new LocalTemporary (ec, type);
697
698                         eclass = ExprClass.Variable;
699                         return this;
700                 }
701
702                 public override void Emit (EmitContext ec)
703                 {
704                         if (temp_storage != null) {
705                                 temp_storage.AddressOf (ec, AddressOp.LoadStore);
706                                 ec.ig.Emit (OpCodes.Initobj, type);
707                                 temp_storage.Emit (ec);
708                         } else
709                                 ec.ig.Emit (OpCodes.Ldnull);
710                 }
711         }
712 }