2004-03-30 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 : GenericConstraints {
22                 string name;
23                 ArrayList constraints;
24                 Location loc;
25                 
26                 //
27                 // name is the identifier, constraints is an arraylist of
28                 // Expressions (with types) or `true' for the constructor constraint.
29                 // 
30                 public Constraints (string name, ArrayList constraints,
31                                     Location loc)
32                 {
33                         this.name = name;
34                         this.constraints = constraints;
35                         this.loc = loc;
36                 }
37
38                 public string TypeParameter {
39                         get {
40                                 return name;
41                         }
42                 }
43
44                 bool has_ctor_constraint;
45                 TypeExpr class_constraint;
46                 ArrayList iface_constraints;
47                 TypeExpr[] constraint_types;
48                 int num_constraints, first_constraint;
49                 Type[] types;
50
51                 public bool HasConstructorConstraint {
52                         get { return has_ctor_constraint; }
53                 }
54
55                 public bool Resolve (DeclSpace ds)
56                 {
57                         iface_constraints = new ArrayList ();
58
59                         foreach (object obj in constraints) {
60                                 if (has_ctor_constraint) {
61                                         Report.Error (401, loc,
62                                                       "The new() constraint must be last.");
63                                         return false;
64                                 }
65
66                                 if (obj is bool) {
67                                         has_ctor_constraint = true;
68                                         continue;
69                                 }
70
71                                 TypeExpr expr = ds.ResolveTypeExpr ((Expression) obj, false, loc);
72                                 if (expr == null)
73                                         return false;
74
75                                 if (expr is TypeParameterExpr) {
76                                         Report.Error (700, loc,
77                                                       "`{0}': naked type parameters cannot " +
78                                                       "be used as bounds", expr.Name);
79                                         return false;
80                                 }
81
82                                 if (expr.IsInterface)
83                                         iface_constraints.Add (expr);
84                                 else if (class_constraint != null) {
85                                         Report.Error (406, loc,
86                                                       "`{0}': the class constraint for `{1}' " +
87                                                       "must come before any other constraints.",
88                                                       expr.Name, name);
89                                         return false;
90                                 } else
91                                         class_constraint = expr;
92
93                                 num_constraints++;
94                         }
95
96                         constraint_types = new TypeExpr [num_constraints];
97                         if (class_constraint != null)
98                                 constraint_types [first_constraint++] = class_constraint;
99                         iface_constraints.CopyTo (constraint_types, first_constraint);
100
101                         return true;
102                 }
103
104                 public Type[] ResolveTypes (EmitContext ec)
105                 {
106                         types = new Type [constraint_types.Length];
107
108                         for (int i = 0; i < constraint_types.Length; i++) {
109                                 types [i] = constraint_types [i].ResolveType (ec);
110                                 if (types [i] == null)
111                                         return null;
112
113                                 for (int j = first_constraint; j < i; j++) {
114                                         if (!types [j].Equals (types [i]))
115                                                 continue;
116
117                                         Report.Error (405, loc,
118                                                       "Duplicate constraint `{0}' for type " +
119                                                       "parameter `{1}'.", types [i], name);
120                                         return null;
121                                 }
122                         }
123
124                         if (class_constraint != null) {
125                                 if (types [0].IsSealed) {
126                                         Report.Error (701, loc,
127                                                       "`{0}' is not a valid bound.  Bounds " +
128                                                       "must be interfaces or non sealed " +
129                                                       "classes", types [0]);
130                                         return null;
131                                 }
132
133                                 if ((types [0] == TypeManager.array_type) ||
134                                     (types [0] == TypeManager.delegate_type) ||
135                                     (types [0] == TypeManager.enum_type) ||
136                                     (types [0] == TypeManager.value_type) ||
137                                     (types [0] == TypeManager.object_type)) {
138                                         Report.Error (702, loc,
139                                                       "Bound cannot be special class `{0}'",
140                                                       types [0]);
141                                         return null;
142                                 }
143                         }
144
145                         return types;
146                 }
147
148                 bool GenericConstraints.HasConstructor {
149                         get {
150                                 return has_ctor_constraint;
151                         }
152                 }
153
154                 Type[] GenericConstraints.Types {
155                         get {
156                                 if (types == null)
157                                         throw new InvalidOperationException ();
158
159                                 return types;
160                         }
161                 }
162         }
163
164         //
165         // This type represents a generic type parameter
166         //
167         public class TypeParameter {
168                 string name;
169                 Constraints constraints;
170                 Location loc;
171                 Type type;
172
173                 public TypeParameter (string name, Constraints constraints, Location loc)
174                 {
175                         this.name = name;
176                         this.constraints = constraints;
177                         this.loc = loc;
178                 }
179
180                 public string Name {
181                         get {
182                                 return name;
183                         }
184                 }
185
186                 public Location Location {
187                         get {
188                                 return loc;
189                         }
190                 }
191
192                 public Constraints Constraints {
193                         get {
194                                 return constraints;
195                         }
196                 }
197
198                 public Type Type {
199                         get {
200                                 return type;
201                         }
202                 }
203
204                 public bool Resolve (DeclSpace ds)
205                 {
206                         if (constraints != null)
207                                 return constraints.Resolve (ds);
208
209                         return true;
210                 }
211
212                 public Type Define (TypeBuilder tb)
213                 {
214                         type = tb.DefineGenericParameter (name);
215                         return type;
216                 }
217
218                 public Type DefineMethod (MethodBuilder mb)
219                 {
220                         type = mb.DefineGenericParameter (name);
221                         return type;
222                 }
223
224                 public bool DefineType (EmitContext ec, TypeBuilder tb)
225                 {
226                         int index = type.GenericParameterPosition;
227                         if (constraints == null)
228                                 tb.SetGenericParameterConstraints (index, new Type [0], false);
229                         else {
230                                 Type[] types = constraints.ResolveTypes (ec);
231                                 if (types == null)
232                                         return false;
233
234                                 tb.SetGenericParameterConstraints (
235                                         index, types, constraints.HasConstructorConstraint);
236                         }
237
238                         return true;
239                 }
240
241                 public bool DefineType (EmitContext ec, MethodBuilder mb)
242                 {
243                         int index = type.GenericParameterPosition;
244                         if (constraints == null)
245                                 mb.SetGenericParameterConstraints (index, new Type [0], false);
246                         else {
247                                 Type[] types = constraints.ResolveTypes (ec);
248                                 if (types == null)
249                                         return false;
250
251                                 mb.SetGenericParameterConstraints (
252                                         index, types, constraints.HasConstructorConstraint);
253                         }
254
255                         return true;
256                 }
257
258                 public override string ToString ()
259                 {
260                         return "TypeParameter[" + name + "]";
261                 }
262         }
263
264         //
265         // This type represents a generic type parameter reference.
266         //
267         // These expressions are born in a fully resolved state.
268         //
269         public class TypeParameterExpr : TypeExpr {
270                 TypeParameter type_parameter;
271
272                 public override string Name {
273                         get {
274                                 return type_parameter.Name;
275                         }
276                 }
277
278                 public TypeParameter TypeParameter {
279                         get {
280                                 return type_parameter;
281                         }
282                 }
283                 
284                 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
285                 {
286                         this.type_parameter = type_parameter;
287                         this.loc = loc;
288                 }
289
290                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
291                 {
292                         type = type_parameter.Type;
293
294                         return this;
295                 }
296
297                 public void Error_CannotUseAsUnmanagedType (Location loc)
298                 {
299                         Report.Error (-203, loc, "Can not use type parameter as unamanged type");
300                 }
301         }
302
303         public class TypeArguments {
304                 public readonly Location Location;
305                 ArrayList args;
306                 Type[] atypes;
307                 bool has_type_args;
308                 bool created;
309                 
310                 public TypeArguments (Location loc)
311                 {
312                         args = new ArrayList ();
313                         this.Location = loc;
314                 }
315
316                 public void Add (Expression type)
317                 {
318                         if (created)
319                                 throw new InvalidOperationException ();
320
321                         args.Add (type);
322                 }
323
324                 public void Add (TypeArguments new_args)
325                 {
326                         if (created)
327                                 throw new InvalidOperationException ();
328
329                         args.AddRange (new_args.args);
330                 }
331
332                 public string[] GetDeclarations ()
333                 {
334                         string[] ret = new string [args.Count];
335                         for (int i = 0; i < args.Count; i++) {
336                                 SimpleName sn = args [i] as SimpleName;
337                                 if (sn != null) {
338                                         ret [i] = sn.Name;
339                                         continue;
340                                 }
341
342                                 Report.Error (81, Location, "Type parameter declaration " +
343                                               "must be an identifier not a type");
344                                 return null;
345                         }
346                         return ret;
347                 }
348
349                 public Type[] Arguments {
350                         get {
351                                 return atypes;
352                         }
353                 }
354
355                 public bool HasTypeArguments {
356                         get {
357                                 return has_type_args;
358                         }
359                 }
360
361                 public int Count {
362                         get {
363                                 return args.Count;
364                         }
365                 }
366
367                 public override string ToString ()
368                 {
369                         StringBuilder s = new StringBuilder ();
370
371                         int count = args.Count;
372                         for (int i = 0; i < count; i++){
373                                 //
374                                 // FIXME: Use TypeManager.CSharpname once we have the type
375                                 //
376                                 s.Append (args [i].ToString ());
377                                 if (i+1 < count)
378                                         s.Append (",");
379                         }
380                         return s.ToString ();
381                 }
382
383                 public bool Resolve (EmitContext ec)
384                 {
385                         DeclSpace ds = ec.DeclSpace;
386                         int count = args.Count;
387                         bool ok = true;
388
389                         atypes = new Type [count];
390                         
391                         for (int i = 0; i < count; i++){
392                                 TypeExpr te = ds.ResolveTypeExpr (
393                                         (Expression) args [i], false, Location);
394                                 if (te == null) {
395                                         ok = false;
396                                         continue;
397                                 }
398                                 if (te is TypeParameterExpr)
399                                         has_type_args = true;
400                                 atypes [i] = te.ResolveType (ec);
401
402                                 if (atypes [i] == null) {
403                                         Report.Error (246, Location, "Cannot find type `{0}'",
404                                                       te.Name);
405                                         ok = false;
406                                 }
407                         }
408                         return ok;
409                 }
410         }
411         
412         public class ConstructedType : TypeExpr {
413                 string name, full_name;
414                 TypeArguments args;
415                 Type[] gen_params, atypes;
416                 Type gt;
417                 
418                 public ConstructedType (string name, TypeArguments args, Location l)
419                 {
420                         loc = l;
421                         this.name = name;
422                         this.args = args;
423
424                         eclass = ExprClass.Type;
425                         full_name = name + "<" + args.ToString () + ">";
426                 }
427
428                 public ConstructedType (string name, TypeParameter[] type_params, Location l)
429                         : this (type_params, l)
430                 {
431                         loc = l;
432
433                         this.name = name;
434                         full_name = name + "<" + args.ToString () + ">";
435                 }
436
437                 protected ConstructedType (TypeArguments args, Location l)
438                 {
439                         loc = l;
440                         this.args = args;
441
442                         eclass = ExprClass.Type;
443                 }
444
445                 protected ConstructedType (TypeParameter[] type_params, Location l)
446                 {
447                         loc = l;
448
449                         args = new TypeArguments (l);
450                         foreach (TypeParameter type_param in type_params)
451                                 args.Add (new TypeParameterExpr (type_param, l));
452
453                         eclass = ExprClass.Type;
454                 }
455
456                 public ConstructedType (Type t, TypeParameter[] type_params, Location l)
457                         : this (type_params, l)
458                 {
459                         gt = t.GetGenericTypeDefinition ();
460
461                         this.name = gt.FullName;
462                         full_name = gt.FullName + "<" + args.ToString () + ">";
463                 }
464
465                 public ConstructedType (Type t, TypeArguments args, Location l)
466                         : this (args, l)
467                 {
468                         gt = t.GetGenericTypeDefinition ();
469
470                         this.name = gt.FullName;
471                         full_name = gt.FullName + "<" + args.ToString () + ">";
472                 }
473
474                 public TypeArguments TypeArguments {
475                         get { return args; }
476                 }
477
478                 protected bool CheckConstraints (int index)
479                 {
480                         Type atype = atypes [index];
481                         Type ptype = gen_params [index];
482
483                         //// FIXME
484                         return true;
485
486                         //
487                         // First, check parent class.
488                         //
489                         if ((ptype.BaseType != atype.BaseType) &&
490                             !atype.BaseType.IsSubclassOf (ptype.BaseType)) {
491                                 Report.Error (-219, loc, "Cannot create constructed type `{0}': " +
492                                               "type argument `{1}' must derive from `{2}'.",
493                                               full_name, atype, ptype.BaseType);
494                                 return false;
495                         }
496
497                         //
498                         // Now, check the interfaces.
499                         //
500                         foreach (Type itype in ptype.GetInterfaces ()) {
501                                 if (TypeManager.ImplementsInterface (atype, itype))
502                                         continue;
503
504                                 Report.Error (-219, loc, "Cannot create constructed type `{0}: " +
505                                               "type argument `{1}' must implement interface `{2}'.",
506                                               full_name, atype, itype);
507                                 return false;
508                         }
509
510                         return true;
511                 }
512
513                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
514                 {
515                         if (gt != null)
516                                 return this;
517
518                         //
519                         // First, resolve the generic type.
520                         //
521                         DeclSpace ds;
522                         Type nested = ec.DeclSpace.FindNestedType (loc, name, out ds);
523                         if (nested != null) {
524                                 gt = nested.GetGenericTypeDefinition ();
525
526                                 TypeArguments new_args = new TypeArguments (loc);
527                                 foreach (TypeParameter param in ds.TypeParameters)
528                                         new_args.Add (new TypeParameterExpr (param, loc));
529                                 new_args.Add (args);
530
531                                 args = new_args;
532                                 return this;
533                         }
534
535                         SimpleName sn = new SimpleName (name, args.Count, loc);
536                         TypeExpr resolved = sn.ResolveAsTypeTerminal (ec);
537                         if (resolved == null) {
538                                 sn = new SimpleName (name, -1, loc);
539                                 resolved = sn.ResolveAsTypeTerminal (ec);
540                                 if ((resolved == null) || (resolved.Type == null)) {
541                                         Report.Error (246, loc,
542                                                       "The type or namespace name `{0}<...>' "+
543                                                       "could not be found", name);
544                                         return null;
545                                 }
546
547                                 Type t = resolved.Type;
548                                 int num_args = TypeManager.GetNumberOfTypeArguments (t);
549
550                                 if (num_args == 0) {
551                                         Report.Error (308, loc,
552                                                       "The non-generic type `{0}' cannot " +
553                                                       "be used with type arguments.",
554                                                       TypeManager.CSharpName (t));
555                                         return null;
556                                 }
557
558                                 Report.Error (305, loc,
559                                               "Using the generic type `{0}' " +
560                                               "requires {1} type arguments",
561                                               TypeManager.GetFullName (t), num_args);
562                                 return null;
563                         }
564
565                         if (resolved.Type == null)
566                                 throw new InternalErrorException (
567                                         "Failed to resolve constructed type `{0}'",
568                                         full_name);
569
570                         gt = resolved.Type.GetGenericTypeDefinition ();
571                         return this;
572                 }
573
574                 public override Type ResolveType (EmitContext ec)
575                 {
576                         if (type != null)
577                                 return type;
578                         if (DoResolveAsTypeStep (ec) == null)
579                                 return null;
580
581                         //
582                         // Resolve the arguments.
583                         //
584                         if (args.Resolve (ec) == false)
585                                 return null;
586
587                         gen_params = gt.GetGenericArguments ();
588                         atypes = args.Arguments;
589
590                         if (atypes.Length != gen_params.Length) {
591                                 Report.Error (-217, loc, "Generic type `{0}' takes {1} " +
592                                               "type parameters, but specified {2}.", gt.Name,
593                                               gen_params.Length, atypes.Length);
594                                 return null;
595                         }
596
597                         for (int i = 0; i < gen_params.Length; i++) {
598                                 if (!CheckConstraints (i))
599                                         return null;
600                         }
601
602                         //
603                         // Now bind the parameters.
604                         //
605                         type = gt.BindGenericParameters (atypes);
606                         return type;
607                 }
608
609                 public Expression GetMemberAccess (EmitContext ec)
610                 {
611                         TypeExpr current;
612                         if (ec.TypeContainer.CurrentType != null)
613                                 current = ec.TypeContainer.CurrentType;
614                         else
615                                 current = new TypeExpression (ec.ContainerType, loc);
616
617                         return new GenericMemberAccess (current, name, args, loc);
618                 }
619
620                 public override bool CheckAccessLevel (DeclSpace ds)
621                 {
622                         return ds.CheckAccessLevel (gt);
623                 }
624
625                 public override bool AsAccessible (DeclSpace ds, int flags)
626                 {
627                         return ds.AsAccessible (gt, flags);
628                 }
629
630                 public override bool IsClass {
631                         get { return gt.IsClass; }
632                 }
633
634                 public override bool IsValueType {
635                         get { return gt.IsValueType; }
636                 }
637
638                 public override bool IsInterface {
639                         get { return gt.IsInterface; }
640                 }
641
642                 public override bool IsSealed {
643                         get { return gt.IsSealed; }
644                 }
645
646                 public override bool IsAttribute {
647                         get { return false; }
648                 }
649
650                 public override TypeExpr[] GetInterfaces ()
651                 {
652                         TypeExpr[] ifaces = TypeManager.GetInterfaces (gt);
653                         return ifaces;
654                 }
655
656                 public override bool Equals (object obj)
657                 {
658                         ConstructedType cobj = obj as ConstructedType;
659                         if (cobj == null)
660                                 return false;
661
662                         if ((type == null) || (cobj.type == null))
663                                 return false;
664
665                         return type == cobj.type;
666                 }
667
668                 public override string Name {
669                         get {
670                                 return full_name;
671                         }
672                 }
673         }
674
675         public class GenericMethod : DeclSpace
676         {
677                 public GenericMethod (NamespaceEntry ns, TypeContainer parent, string name,
678                                       Attributes attrs, Location l)
679                         : base (ns, parent, name, attrs, l)
680                 { }
681
682                 public override TypeBuilder DefineType ()
683                 {
684                         throw new Exception ();
685                 }
686
687                 public override bool Define (TypeContainer parent)
688                 {
689                         for (int i = 0; i < TypeParameters.Length; i++)
690                                 if (!TypeParameters [i].Resolve (parent))
691                                         return false;
692
693                         return true;
694                 }
695
696                 public bool Define (TypeContainer parent, MethodBuilder mb)
697                 {
698                         if (!Define (parent))
699                                 return false;
700
701                         Type[] gen_params = new Type [TypeParameters.Length];
702                         for (int i = 0; i < TypeParameters.Length; i++)
703                                 gen_params [i] = TypeParameters [i].DefineMethod (mb);
704
705                         return true;
706                 }
707
708                 public bool DefineType (EmitContext ec, MethodBuilder mb)
709                 {
710                         for (int i = 0; i < TypeParameters.Length; i++)
711                                 if (!TypeParameters [i].DefineType (ec, mb))
712                                         return false;
713
714                         return true;
715                 }
716
717                 public override bool DefineMembers (TypeContainer parent)
718                 {
719                         return true;
720                 }
721
722                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
723                                                         MemberFilter filter, object criteria)
724                 {
725                         throw new Exception ();
726                 }               
727
728                 public override MemberCache MemberCache {
729                         get {
730                                 throw new Exception ();
731                         }
732                 }
733         }
734
735         public class GenericMemberAccess : MemberAccess
736         {
737                 TypeArguments args;
738
739                 public GenericMemberAccess (Expression expr, string id, TypeArguments args, Location loc)
740                         : base (expr, id, args.Count, loc)
741                 {
742                         this.args = args;
743                 }
744
745                 private bool DoResolveBase (EmitContext ec)
746                 {
747                         ConstructedType cexpr = expr as ConstructedType;
748                         if (cexpr != null) {
749                                 TypeArguments new_args = new TypeArguments (loc);
750                                 new_args.Add (cexpr.TypeArguments);
751                                 new_args.Add (args);
752
753                                 args = new_args;
754                         }
755
756                         return true;
757                 }
758
759                 public override Expression DoResolve (EmitContext ec, Expression right_side,
760                                                       ResolveFlags flags)
761                 {
762                         if (!DoResolveBase (ec))
763                                 return null;
764
765                         Expression expr = base.DoResolve (ec, right_side, flags);
766                         if (expr == null)
767                                 return null;
768
769                         TypeExpr texpr = expr as TypeExpr;
770                         if (texpr != null) {
771                                 Type t = texpr.ResolveType (ec);
772                                 if (t == null)
773                                         return null;
774
775                                 ConstructedType ctype = new ConstructedType (t, args, loc);
776                                 return ctype.DoResolve (ec);
777                         }
778
779                         MethodGroupExpr mg = expr as MethodGroupExpr;
780                         if (mg == null) {
781                                 return expr;
782                                 Report.Error (-220, loc, "Member `{0}' has type arguments, but did " +
783                                               "not resolve as a method group.", Identifier);
784                                 return null;
785                         }
786
787                         if (args.Resolve (ec) == false)
788                                 return null;
789
790                         Type[] atypes = args.Arguments;
791
792                         ArrayList list = new ArrayList ();
793
794                         foreach (MethodBase method in mg.Methods) {
795                                 MethodInfo mi = method as MethodInfo;
796                                 if (mi == null)
797                                         continue;
798
799                                 Type[] gen_params = mi.GetGenericParameters ();
800                         
801                                 if (atypes.Length != gen_params.Length) {
802                                         Report.Error (-217, loc, "Generic method `{0}' takes {1} " +
803                                                       "type parameters, but specified {2}.", mi.Name,
804                                                       gen_params.Length, atypes.Length);
805                                         continue;
806                                 }
807
808                                 list.Add (mi.BindGenericParameters (args.Arguments));
809                         }
810
811                         MethodInfo[] methods = new MethodInfo [list.Count];
812                         list.CopyTo (methods, 0);
813
814                         MethodGroupExpr new_mg = new MethodGroupExpr (methods, mg.Location);
815                         new_mg.InstanceExpression = mg.InstanceExpression;
816                         new_mg.HasTypeArguments = true;
817                         return new_mg;
818                 }
819
820                 public override Expression ResolveAsTypeStep (EmitContext ec)
821                 {
822                         if (!DoResolveBase (ec))
823                                 return null;
824
825                         expr = base.ResolveAsTypeStep (ec);
826                         if (expr == null)
827                                 return null;
828
829                         Type t = ((TypeExpr) expr).ResolveType (ec);
830                         if (t == null)
831                                 return null;
832
833                         ConstructedType ctype = new ConstructedType (t, args, loc);
834                         return ctype.ResolveAsTypeStep (ec);
835                 }
836         }
837
838         public class DefaultValueExpression : Expression
839         {
840                 Expression expr;
841                 LocalTemporary temp_storage;
842
843                 public DefaultValueExpression (Expression expr, Location loc)
844                 {
845                         this.expr = expr;
846                         this.loc = loc;
847                 }
848
849                 public override Expression DoResolve (EmitContext ec)
850                 {
851                         type = ec.DeclSpace.ResolveType (expr, false, loc);
852                         if (type == null)
853                                 return null;
854
855                         if (type.IsGenericParameter || TypeManager.IsValueType (type))
856                                 temp_storage = new LocalTemporary (ec, type);
857
858                         eclass = ExprClass.Variable;
859                         return this;
860                 }
861
862                 public override void Emit (EmitContext ec)
863                 {
864                         if (temp_storage != null) {
865                                 temp_storage.AddressOf (ec, AddressOp.LoadStore);
866                                 ec.ig.Emit (OpCodes.Initobj, type);
867                                 temp_storage.Emit (ec);
868                         } else
869                                 ec.ig.Emit (OpCodes.Ldnull);
870                 }
871         }
872 }