renamed
[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         public abstract class GenericConstraints {
19                 public abstract GenericParameterAttributes Attributes {
20                         get;
21                 }
22
23                 public bool HasConstructorConstraint {
24                         get { return (Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0; }
25                 }
26
27                 public bool HasReferenceTypeConstraint {
28                         get { return (Attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0; }
29                 }
30
31                 public bool HasValueTypeConstraint {
32                         get { return (Attributes & GenericParameterAttributes.ValueTypeConstraint) != 0; }
33                 }
34
35                 public virtual bool HasClassConstraint {
36                         get { return ClassConstraint != null; }
37                 }
38
39                 public abstract Type ClassConstraint {
40                         get;
41                 }
42
43                 public abstract Type[] InterfaceConstraints {
44                         get;
45                 }
46
47                 public abstract Type EffectiveBaseClass {
48                         get;
49                 }
50
51                 // <summary>
52                 //   Returns whether the type parameter is "known to be a reference type".
53                 // </summary>
54                 public virtual bool IsReferenceType {
55                         get {
56                                 if (HasReferenceTypeConstraint)
57                                         return true;
58                                 if (HasValueTypeConstraint)
59                                         return false;
60
61                                 if (ClassConstraint != null) {
62                                         if (ClassConstraint.IsValueType)
63                                                 return false;
64
65                                         if (ClassConstraint != TypeManager.object_type)
66                                                 return true;
67                                 }
68
69                                 foreach (Type t in InterfaceConstraints) {
70                                         if (!t.IsGenericParameter)
71                                                 continue;
72
73                                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
74                                         if ((gc != null) && gc.IsReferenceType)
75                                                 return true;
76                                 }
77
78                                 return false;
79                         }
80                 }
81
82                 // <summary>
83                 //   Returns whether the type parameter is "known to be a value type".
84                 // </summary>
85                 public virtual bool IsValueType {
86                         get {
87                                 if (HasValueTypeConstraint)
88                                         return true;
89                                 if (HasReferenceTypeConstraint)
90                                         return false;
91
92                                 if (ClassConstraint != null) {
93                                         if (!ClassConstraint.IsValueType)
94                                                 return false;
95
96                                         if (ClassConstraint != TypeManager.value_type)
97                                                 return true;
98                                 }
99
100                                 foreach (Type t in InterfaceConstraints) {
101                                         if (!t.IsGenericParameter)
102                                                 continue;
103
104                                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
105                                         if ((gc != null) && gc.IsValueType)
106                                                 return true;
107                                 }
108
109                                 return false;
110                         }
111                 }
112         }
113
114         public enum SpecialConstraint
115         {
116                 Constructor,
117                 ReferenceType,
118                 ValueType
119         }
120
121         //
122         // Tracks the constraints for a type parameter
123         //
124         public class Constraints : GenericConstraints {
125                 string name;
126                 ArrayList constraints;
127                 Location loc;
128                 
129                 //
130                 // name is the identifier, constraints is an arraylist of
131                 // Expressions (with types) or `true' for the constructor constraint.
132                 // 
133                 public Constraints (string name, ArrayList constraints,
134                                     Location loc)
135                 {
136                         this.name = name;
137                         this.constraints = constraints;
138                         this.loc = loc;
139                 }
140
141                 public string TypeParameter {
142                         get {
143                                 return name;
144                         }
145                 }
146
147                 GenericParameterAttributes attrs;
148                 TypeExpr class_constraint;
149                 ArrayList iface_constraints;
150                 ArrayList type_param_constraints;
151                 int num_constraints, first_constraint;
152                 Type class_constraint_type;
153                 Type[] iface_constraint_types;
154                 Type effective_base_type;
155
156                 public bool Resolve (EmitContext ec)
157                 {
158                         DeclSpace ds = ec.DeclSpace;
159
160                         iface_constraints = new ArrayList ();
161                         type_param_constraints = new ArrayList ();
162
163                         foreach (object obj in constraints) {
164                                 if (HasConstructorConstraint) {
165                                         Report.Error (401, loc,
166                                                       "The new() constraint must be last.");
167                                         return false;
168                                 }
169
170                                 if (obj is SpecialConstraint) {
171                                         SpecialConstraint sc = (SpecialConstraint) obj;
172
173                                         if (sc == SpecialConstraint.Constructor) {
174                                                 if (!HasValueTypeConstraint) {
175                                                         attrs |= GenericParameterAttributes.DefaultConstructorConstraint;
176                                                         continue;
177                                                 }
178
179                                                 Report.Error (
180                                                         451, loc, "The new () constraint " +
181                                                         "cannot be used with the `struct' " +
182                                                         "constraint.");
183                                                 return false;
184                                         }
185
186                                         if ((num_constraints > 0) || HasReferenceTypeConstraint || HasValueTypeConstraint) {
187                                                 Report.Error (449, loc,
188                                                               "The `class' or `struct' " +
189                                                               "constraint must be first");
190                                                 return false;
191                                         }
192
193                                         if (sc == SpecialConstraint.ReferenceType)
194                                                 attrs |= GenericParameterAttributes.ReferenceTypeConstraint;
195                                         else
196                                                 attrs |= GenericParameterAttributes.ValueTypeConstraint;
197                                         continue;
198                                 }
199
200                                 TypeExpr expr;
201                                 if (obj is ConstructedType) {
202                                         ConstructedType cexpr = (ConstructedType) obj;
203                                         if (!cexpr.ResolveConstructedType (ec))
204                                                 return false;
205                                         expr = cexpr;
206                                 } else
207                                         expr = ((Expression) obj).ResolveAsTypeTerminal (ec);
208
209                                 if (expr == null)
210                                         return false;
211
212                                 TypeParameterExpr texpr = expr as TypeParameterExpr;
213                                 if (texpr != null)
214                                         type_param_constraints.Add (expr);
215                                 else if (expr.IsInterface)
216                                         iface_constraints.Add (expr);
217                                 else if (class_constraint != null) {
218                                         Report.Error (406, loc,
219                                                       "`{0}': the class constraint for `{1}' " +
220                                                       "must come before any other constraints.",
221                                                       expr.Name, name);
222                                         return false;
223                                 } else if (HasReferenceTypeConstraint || HasValueTypeConstraint) {
224                                         Report.Error (450, loc, "`{0}': cannot specify both " +
225                                                       "a constraint class and the `class' " +
226                                                       "or `struct' constraint.", expr.Name);
227                                         return false;
228                                 } else
229                                         class_constraint = expr;
230
231                                 num_constraints++;
232                         }
233
234                         return true;
235                 }
236
237                 bool CheckTypeParameterConstraints (TypeParameter tparam, Hashtable seen)
238                 {
239                         seen.Add (tparam, true);
240
241                         Constraints constraints = tparam.Constraints;
242                         if (constraints == null)
243                                 return true;
244
245                         if (constraints.HasValueTypeConstraint) {
246                                 Report.Error (456, loc, "Type parameter `{0}' has " +
247                                               "the `struct' constraint, so it cannot " +
248                                               "be used as a constraint for `{1}'",
249                                               tparam.Name, name);
250                                 return false;
251                         }
252
253                         if (constraints.type_param_constraints == null)
254                                 return true;
255
256                         foreach (TypeParameterExpr expr in constraints.type_param_constraints) {
257                                 if (seen.Contains (expr.TypeParameter)) {
258                                         Report.Error (454, loc, "Circular constraint " +
259                                                       "dependency involving `{0}' and `{1}'",
260                                                       tparam.Name, expr.Name);
261                                         return false;
262                                 }
263
264                                 if (!CheckTypeParameterConstraints (expr.TypeParameter, seen))
265                                         return false;
266                         }
267
268                         return true;
269                 }
270
271                 public bool ResolveTypes (EmitContext ec)
272                 {
273                         foreach (object obj in constraints) {
274                                 ConstructedType cexpr = obj as ConstructedType;
275                                 if (cexpr == null)
276                                         continue;
277
278                                 if (!cexpr.CheckConstraints (ec))
279                                         return false;
280                         }
281
282                         foreach (TypeParameterExpr expr in type_param_constraints) {
283                                 Hashtable seen = new Hashtable ();
284                                 if (!CheckTypeParameterConstraints (expr.TypeParameter, seen))
285                                         return false;
286                         }
287
288                         ArrayList list = new ArrayList ();
289
290                         foreach (TypeExpr iface_constraint in iface_constraints) {
291                                 foreach (Type type in list) {
292                                         if (!type.Equals (iface_constraint.Type))
293                                                 continue;
294
295                                         Report.Error (405, loc,
296                                                       "Duplicate constraint `{0}' for type " +
297                                                       "parameter `{1}'.", iface_constraint.Type,
298                                                       name);
299                                         return false;
300                                 }
301
302                                 list.Add (iface_constraint.Type);
303                         }
304
305                         foreach (TypeParameterExpr expr in type_param_constraints) {
306                                 foreach (Type type in list) {
307                                         if (!type.Equals (expr.Type))
308                                                 continue;
309
310                                         Report.Error (405, loc,
311                                                       "Duplicate constraint `{0}' for type " +
312                                                       "parameter `{1}'.", expr.Type, name);
313                                         return false;
314                                 }
315
316                                 list.Add (expr.Type);
317                         }
318
319                         iface_constraint_types = new Type [list.Count];
320                         list.CopyTo (iface_constraint_types, 0);
321
322                         if (class_constraint != null) {
323                                 class_constraint_type = class_constraint.Type;
324                                 if (class_constraint_type == null)
325                                         return false;
326
327                                 if (class_constraint_type.IsSealed) {
328                                         Report.Error (701, loc,
329                                                       "`{0}' is not a valid bound.  Bounds " +
330                                                       "must be interfaces or non sealed " +
331                                                       "classes", class_constraint_type);
332                                         return false;
333                                 }
334
335                                 if ((class_constraint_type == TypeManager.array_type) ||
336                                     (class_constraint_type == TypeManager.delegate_type) ||
337                                     (class_constraint_type == TypeManager.enum_type) ||
338                                     (class_constraint_type == TypeManager.value_type) ||
339                                     (class_constraint_type == TypeManager.object_type)) {
340                                         Report.Error (702, loc,
341                                                       "Bound cannot be special class `{0}'",
342                                                       class_constraint_type);
343                                         return false;
344                                 }
345                         }
346
347                         if (class_constraint_type != null)
348                                 effective_base_type = class_constraint_type;
349                         else if (HasValueTypeConstraint)
350                                 effective_base_type = TypeManager.value_type;
351                         else
352                                 effective_base_type = TypeManager.object_type;
353
354                         return true;
355                 }
356
357                 public bool CheckDependencies (EmitContext ec)
358                 {
359                         foreach (TypeParameterExpr expr in type_param_constraints) {
360                                 if (!CheckDependencies (expr.TypeParameter, ec))
361                                         return false;
362                         }
363
364                         return true;
365                 }
366
367                 bool CheckDependencies (TypeParameter tparam, EmitContext ec)
368                 {
369                         Constraints constraints = tparam.Constraints;
370                         if (constraints == null)
371                                 return true;
372
373                         if (HasValueTypeConstraint && constraints.HasClassConstraint) {
374                                 Report.Error (455, loc, "Type parameter `{0}' inherits " +
375                                               "conflicting constraints `{1}' and `{2}'",
376                                               name, constraints.ClassConstraint,
377                                               "System.ValueType");
378                                 return false;
379                         }
380
381                         if (HasClassConstraint && constraints.HasClassConstraint) {
382                                 Type t1 = ClassConstraint;
383                                 TypeExpr e1 = class_constraint;
384                                 Type t2 = constraints.ClassConstraint;
385                                 TypeExpr e2 = constraints.class_constraint;
386
387                                 if (!Convert.ImplicitReferenceConversionExists (ec, e1, t2) &&
388                                     !Convert.ImplicitReferenceConversionExists (ec, e2, t1)) {
389                                         Report.Error (455, loc,
390                                                       "Type parameter `{0}' inherits " +
391                                                       "conflicting constraints `{1}' and `{2}'",
392                                                       name, t1, t2);
393                                         return false;
394                                 }
395                         }
396
397                         if (constraints.type_param_constraints == null)
398                                 return true;
399
400                         foreach (TypeParameterExpr expr in constraints.type_param_constraints) {
401                                 if (!CheckDependencies (expr.TypeParameter, ec))
402                                         return false;
403                         }
404
405                         return true;
406                 }
407
408                 public void Define (GenericTypeParameterBuilder type)
409                 {
410                         type.SetGenericParameterAttributes (attrs);
411                 }
412
413                 public override GenericParameterAttributes Attributes {
414                         get { return attrs; }
415                 }
416
417                 public override bool HasClassConstraint {
418                         get { return class_constraint != null; }
419                 }
420
421                 public override Type ClassConstraint {
422                         get { return class_constraint_type; }
423                 }
424
425                 public override Type[] InterfaceConstraints {
426                         get { return iface_constraint_types; }
427                 }
428
429                 public override Type EffectiveBaseClass {
430                         get { return effective_base_type; }
431                 }
432
433                 internal bool IsSubclassOf (Type t)
434                 {
435                         if ((class_constraint_type != null) &&
436                             class_constraint_type.IsSubclassOf (t))
437                                 return true;
438
439                         if (iface_constraint_types == null)
440                                 return false;
441
442                         foreach (Type iface in iface_constraint_types) {
443                                 if (TypeManager.IsSubclassOf (iface, t))
444                                         return true;
445                         }
446
447                         return false;
448                 }
449
450                 public bool CheckInterfaceMethod (EmitContext ec, GenericConstraints gc)
451                 {
452                         if (!ResolveTypes (ec))
453                                 return false;
454
455                         if (gc.Attributes != attrs)
456                                 return false;
457
458                         if (HasClassConstraint != gc.HasClassConstraint)
459                                 return false;
460                         if (HasClassConstraint && !TypeManager.IsEqual (gc.ClassConstraint, ClassConstraint))
461                                 return false;
462
463                         int gc_icount = gc.InterfaceConstraints != null ?
464                                 gc.InterfaceConstraints.Length : 0;
465                         int icount = InterfaceConstraints != null ?
466                                 InterfaceConstraints.Length : 0;
467
468                         if (gc_icount != icount)
469                                 return false;
470
471                         foreach (Type iface in gc.InterfaceConstraints) {
472                                 bool ok = false;
473                                 foreach (Type check in InterfaceConstraints) {
474                                         if (TypeManager.IsEqual (iface, check)) {
475                                                 ok = true;
476                                                 break;
477                                         }
478                                 }
479
480                                 if (!ok)
481                                         return false;
482                         }
483
484                         return true;
485                 }
486         }
487
488         //
489         // This type represents a generic type parameter
490         //
491         public class TypeParameter : MemberCore, IMemberContainer {
492                 string name;
493                 GenericConstraints gc;
494                 Constraints constraints;
495                 Location loc;
496                 GenericTypeParameterBuilder type;
497
498                 public TypeParameter (TypeContainer parent, string name,
499                                       Constraints constraints, Location loc)
500                         : base (parent, new MemberName (name), null, loc)
501                 {
502                         this.name = name;
503                         this.constraints = constraints;
504                         this.loc = loc;
505                 }
506
507                 public GenericConstraints GenericConstraints {
508                         get {
509                                 return gc != null ? gc : constraints;
510                         }
511                 }
512
513                 public Constraints Constraints {
514                         get {
515                                 return constraints;
516                         }
517                 }
518
519                 public bool HasConstructorConstraint {
520                         get {
521                                 if (constraints != null)
522                                         return constraints.HasConstructorConstraint;
523
524                                 return false;
525                         }
526                 }
527
528                 public Type Type {
529                         get {
530                                 return type;
531                         }
532                 }
533
534                 public bool Resolve (DeclSpace ds)
535                 {
536                         if (constraints != null)
537                                 return constraints.Resolve (ds.EmitContext);
538
539                         return true;
540                 }
541
542                 public void Define (GenericTypeParameterBuilder type)
543                 {
544                         if (this.type != null)
545                                 throw new InvalidOperationException ();
546
547                         this.type = type;
548                         TypeManager.AddTypeParameter (type, this);
549                 }
550
551                 public void DefineConstraints ()
552                 {
553                         if (constraints != null)
554                                 constraints.Define (type);
555                 }
556
557                 public bool DefineType (EmitContext ec)
558                 {
559                         return DefineType (ec, null, null, false);
560                 }
561
562                 public bool DefineType (EmitContext ec, MethodBuilder builder,
563                                         MethodInfo implementing, bool is_override)
564                 {
565                         if (implementing != null) {
566                                 if (is_override && (constraints != null)) {
567                                         Report.Error (
568                                                 460, loc, "Constraints for override and " +
569                                                 "explicit interface implementation methods " +
570                                                 "are inherited from the base method so they " +
571                                                 "cannot be specified directly");
572                                         return false;
573                                 }
574
575                                 MethodBase mb = implementing;
576                                 if (mb.Mono_IsInflatedMethod)
577                                         mb = mb.GetGenericMethodDefinition ();
578
579                                 int pos = type.GenericParameterPosition;
580                                 ParameterData pd = Invocation.GetParameterData (mb);
581                                 GenericConstraints temp_gc = pd.GenericConstraints (pos);
582                                 Type mparam = mb.GetGenericArguments () [pos];
583
584                                 if (temp_gc != null)
585                                         gc = new InflatedConstraints (temp_gc, implementing.DeclaringType);
586                                 else if (constraints != null)
587                                         gc = new InflatedConstraints (constraints, implementing.DeclaringType);
588
589                                 bool ok = true;
590                                 if (constraints != null) {
591                                         if (temp_gc == null)
592                                                 ok = false;
593                                         else if (!constraints.CheckInterfaceMethod (ec, gc))
594                                                 ok = false;
595                                 } else {
596                                         if (!is_override && (temp_gc != null))
597                                                 ok = false;
598                                 }
599
600                                 if (!ok) {
601                                         Report.SymbolRelatedToPreviousError (implementing);
602
603                                         Report.Error (
604                                                 425, loc, "The constraints for type " +
605                                                 "parameter `{0}' of method `{1}' must match " +
606                                                 "the constraints for type parameter `{2}' " +
607                                                 "of interface method `{3}'.  Consider using " +
608                                                 "an explicit interface implementation instead",
609                                                 Name, TypeManager.CSharpSignature (builder),
610                                                 mparam, TypeManager.CSharpSignature (mb));
611                                         return false;
612                                 }
613                         } else {
614                                 if (constraints != null) {
615                                         if (!constraints.ResolveTypes (ec))
616                                                 return false;
617                                 }
618
619                                 gc = (GenericConstraints) constraints;
620                         }
621
622                         if (gc == null)
623                                 return true;
624
625                         if (gc.HasClassConstraint)
626                                 type.SetBaseTypeConstraint (gc.ClassConstraint);
627
628                         type.SetInterfaceConstraints (gc.InterfaceConstraints);
629                         TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
630
631                         return true;
632                 }
633
634                 public bool CheckDependencies (EmitContext ec)
635                 {
636                         if (constraints != null)
637                                 return constraints.CheckDependencies (ec);
638
639                         return true;
640                 }
641
642                 //
643                 // MemberContainer
644                 //
645
646                 public override bool Define ()
647                 {
648                         return true;
649                 }
650
651                 protected override void VerifyObsoleteAttribute ()
652                 { }
653
654                 public override void ApplyAttributeBuilder (Attribute a,
655                                                             CustomAttributeBuilder cb)
656                 { }
657
658                 public override AttributeTargets AttributeTargets {
659                         get {
660                                 return (AttributeTargets) 0;
661                         }
662                 }
663
664                 public override string[] ValidAttributeTargets {
665                         get {
666                                 return new string [0];
667                         }
668                 }
669
670                 //
671                 // IMemberContainer
672                 //
673
674                 string IMemberContainer.Name {
675                         get { return Name; }
676                 }
677
678                 MemberCache IMemberContainer.ParentCache {
679                         get { return null; }
680                 }
681
682                 bool IMemberContainer.IsInterface {
683                         get { return true; }
684                 }
685
686                 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
687                 {
688                         return FindMembers (mt, bf, null, null);
689                 }
690
691                 MemberCache IMemberContainer.MemberCache {
692                         get { return null; }
693                 }
694
695                 public MemberList FindMembers (MemberTypes mt, BindingFlags bf,
696                                                MemberFilter filter, object criteria)
697                 {
698                         if (constraints == null)
699                                 return MemberList.Empty;
700
701                         ArrayList members = new ArrayList ();
702
703                         GenericConstraints gc = (GenericConstraints) constraints;
704
705                         if (gc.HasClassConstraint) {
706                                 MemberList list = TypeManager.FindMembers (
707                                         gc.ClassConstraint, mt, bf, filter, criteria);
708
709                                 members.AddRange (list);
710                         }
711
712                         foreach (Type t in gc.InterfaceConstraints) {
713                                 MemberList list = TypeManager.FindMembers (
714                                         t, mt, bf, filter, criteria);
715
716                                 members.AddRange (list);
717                         }
718
719                         return new MemberList (members);
720                 }
721
722                 public bool IsSubclassOf (Type t)
723                 {
724                         if (type.Equals (t))
725                                 return true;
726
727                         if (constraints != null)
728                                 return constraints.IsSubclassOf (t);
729
730                         return false;
731                 }
732
733                 public override string ToString ()
734                 {
735                         return "TypeParameter[" + name + "]";
736                 }
737
738                 protected class InflatedConstraints : GenericConstraints
739                 {
740                         GenericConstraints gc;
741                         Type base_type;
742                         Type class_constraint;
743                         Type[] iface_constraints;
744                         Type[] dargs;
745                         Type declaring;
746
747                         public InflatedConstraints (GenericConstraints gc, Type declaring)
748                         {
749                                 this.gc = gc;
750                                 this.declaring = declaring;
751
752                                 dargs = TypeManager.GetTypeArguments (declaring);
753
754                                 ArrayList list = new ArrayList ();
755                                 if (gc.HasClassConstraint)
756                                         list.Add (inflate (gc.ClassConstraint));
757                                 foreach (Type iface in gc.InterfaceConstraints)
758                                         list.Add (inflate (iface));
759
760                                 bool has_class_constr = false;
761                                 if (list.Count > 0) {
762                                         Type first = (Type) list [0];
763                                         has_class_constr = !first.IsInterface && !first.IsGenericParameter;
764                                 }
765
766                                 if ((list.Count > 0) && has_class_constr) {
767                                         class_constraint = (Type) list [0];
768                                         iface_constraints = new Type [list.Count - 1];
769                                         list.CopyTo (1, iface_constraints, 0, list.Count - 1);
770                                 } else {
771                                         iface_constraints = new Type [list.Count];
772                                         list.CopyTo (iface_constraints, 0);
773                                 }
774
775                                 if (HasValueTypeConstraint)
776                                         base_type = TypeManager.value_type;
777                                 else if (class_constraint != null)
778                                         base_type = class_constraint;
779                                 else
780                                         base_type = TypeManager.object_type;
781                         }
782
783                         Type inflate (Type t)
784                         {
785                                 if (t == null)
786                                         return null;
787                                 if (t.IsGenericParameter)
788                                         return dargs [t.GenericParameterPosition];
789                                 if (t.IsGenericInstance) {
790                                         t = t.GetGenericTypeDefinition ();
791                                         t = t.BindGenericParameters (dargs);
792                                 }
793
794                                 return t;
795                         }
796
797                         public override GenericParameterAttributes Attributes {
798                                 get { return gc.Attributes; }
799                         }
800
801                         public override Type ClassConstraint {
802                                 get { return class_constraint; }
803                         }
804
805                         public override Type EffectiveBaseClass {
806                                 get { return base_type; }
807                         }
808
809                         public override Type[] InterfaceConstraints {
810                                 get { return iface_constraints; }
811                         }
812                 }
813         }
814
815         //
816         // This type represents a generic type parameter reference.
817         //
818         // These expressions are born in a fully resolved state.
819         //
820         public class TypeParameterExpr : TypeExpr {
821                 TypeParameter type_parameter;
822
823                 public override string Name {
824                         get {
825                                 return type_parameter.Name;
826                         }
827                 }
828
829                 public TypeParameter TypeParameter {
830                         get {
831                                 return type_parameter;
832                         }
833                 }
834                 
835                 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
836                 {
837                         this.type_parameter = type_parameter;
838                         this.loc = loc;
839                 }
840
841                 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
842                 {
843                         type = type_parameter.Type;
844
845                         return this;
846                 }
847
848                 public override bool IsInterface {
849                         get { return false; }
850                 }
851
852                 public override bool CheckAccessLevel (DeclSpace ds)
853                 {
854                         return true;
855                 }
856
857                 public void Error_CannotUseAsUnmanagedType (Location loc)
858                 {
859                         Report.Error (-203, loc, "Can not use type parameter as unamanged type");
860                 }
861         }
862
863         public class TypeArguments {
864                 public readonly Location Location;
865                 ArrayList args;
866                 Type[] atypes;
867                 int dimension;
868                 bool has_type_args;
869                 bool created;
870                 
871                 public TypeArguments (Location loc)
872                 {
873                         args = new ArrayList ();
874                         this.Location = loc;
875                 }
876
877                 public TypeArguments (int dimension, Location loc)
878                 {
879                         this.dimension = dimension;
880                         this.Location = loc;
881                 }
882
883                 public void Add (Expression type)
884                 {
885                         if (created)
886                                 throw new InvalidOperationException ();
887
888                         args.Add (type);
889                 }
890
891                 public void Add (TypeArguments new_args)
892                 {
893                         if (created)
894                                 throw new InvalidOperationException ();
895
896                         args.AddRange (new_args.args);
897                 }
898
899                 public string[] GetDeclarations ()
900                 {
901                         string[] ret = new string [args.Count];
902                         for (int i = 0; i < args.Count; i++) {
903                                 SimpleName sn = args [i] as SimpleName;
904                                 if (sn != null) {
905                                         ret [i] = sn.Name;
906                                         continue;
907                                 }
908
909                                 Report.Error (81, Location, "Type parameter declaration " +
910                                               "must be an identifier not a type");
911                                 return null;
912                         }
913                         return ret;
914                 }
915
916                 public Type[] Arguments {
917                         get {
918                                 return atypes;
919                         }
920                 }
921
922                 public bool HasTypeArguments {
923                         get {
924                                 return has_type_args;
925                         }
926                 }
927
928                 public int Count {
929                         get {
930                                 if (dimension > 0)
931                                         return dimension;
932                                 else
933                                         return args.Count;
934                         }
935                 }
936
937                 public bool IsUnbound {
938                         get {
939                                 return dimension > 0;
940                         }
941                 }
942
943                 public override string ToString ()
944                 {
945                         StringBuilder s = new StringBuilder ();
946
947                         int count = Count;
948                         for (int i = 0; i < count; i++){
949                                 //
950                                 // FIXME: Use TypeManager.CSharpname once we have the type
951                                 //
952                                 if (args != null)
953                                         s.Append (args [i].ToString ());
954                                 if (i+1 < count)
955                                         s.Append (",");
956                         }
957                         return s.ToString ();
958                 }
959
960                 public bool Resolve (EmitContext ec)
961                 {
962                         DeclSpace ds = ec.DeclSpace;
963                         int count = args.Count;
964                         bool ok = true;
965
966                         atypes = new Type [count];
967
968                         for (int i = 0; i < count; i++){
969                                 TypeExpr te = ((Expression) args [i]).ResolveAsTypeTerminal (ec);
970                                 if (te == null) {
971                                         ok = false;
972                                         continue;
973                                 }
974                                 if (te is TypeParameterExpr)
975                                         has_type_args = true;
976
977                                 atypes [i] = te.Type;
978                         }
979                         return ok;
980                 }
981         }
982         
983         public class ConstructedType : TypeExpr {
984                 string name, full_name;
985                 TypeArguments args;
986                 Type[] gen_params, atypes;
987                 Type gt;
988                 
989                 public ConstructedType (string name, TypeArguments args, Location l)
990                 {
991                         loc = l;
992                         this.name = MemberName.MakeName (name, args.Count);
993                         this.args = args;
994
995                         eclass = ExprClass.Type;
996                         full_name = name + "<" + args.ToString () + ">";
997                 }
998
999                 public ConstructedType (string name, TypeParameter[] type_params, Location l)
1000                         : this (type_params, l)
1001                 {
1002                         loc = l;
1003
1004                         this.name = name;
1005                         full_name = name + "<" + args.ToString () + ">";
1006                 }
1007
1008                 protected ConstructedType (TypeArguments args, Location l)
1009                 {
1010                         loc = l;
1011                         this.args = args;
1012
1013                         eclass = ExprClass.Type;
1014                 }
1015
1016                 protected ConstructedType (TypeParameter[] type_params, Location l)
1017                 {
1018                         loc = l;
1019
1020                         args = new TypeArguments (l);
1021                         foreach (TypeParameter type_param in type_params)
1022                                 args.Add (new TypeParameterExpr (type_param, l));
1023
1024                         eclass = ExprClass.Type;
1025                 }
1026
1027                 public ConstructedType (Type t, TypeParameter[] type_params, Location l)
1028                         : this (type_params, l)
1029                 {
1030                         gt = t.GetGenericTypeDefinition ();
1031
1032                         this.name = gt.FullName;
1033                         full_name = gt.FullName + "<" + args.ToString () + ">";
1034                 }
1035
1036                 public ConstructedType (Type t, TypeArguments args, Location l)
1037                         : this (args, l)
1038                 {
1039                         gt = t.GetGenericTypeDefinition ();
1040
1041                         this.name = gt.FullName;
1042                         full_name = gt.FullName + "<" + args.ToString () + ">";
1043                 }
1044
1045                 public TypeArguments TypeArguments {
1046                         get { return args; }
1047                 }
1048
1049                 protected string DeclarationName {
1050                         get {
1051                                 StringBuilder sb = new StringBuilder ();
1052                                 sb.Append (gt.FullName);
1053                                 sb.Append ("<");
1054                                 for (int i = 0; i < gen_params.Length; i++) {
1055                                         if (i > 0)
1056                                                 sb.Append (",");
1057                                         sb.Append (gen_params [i]);
1058                                 }
1059                                 sb.Append (">");
1060                                 return sb.ToString ();
1061                         }
1062                 }
1063
1064                 protected bool CheckConstraint (EmitContext ec, Type ptype, Expression expr,
1065                                                 Type ctype)
1066                 {
1067                         if (TypeManager.HasGenericArguments (ctype)) {
1068                                 Type[] types = TypeManager.GetTypeArguments (ctype);
1069
1070                                 TypeArguments new_args = new TypeArguments (loc);
1071
1072                                 for (int i = 0; i < types.Length; i++) {
1073                                         Type t = types [i];
1074
1075                                         if (t.IsGenericParameter) {
1076                                                 int pos = t.GenericParameterPosition;
1077                                                 t = args.Arguments [pos];
1078                                         }
1079                                         new_args.Add (new TypeExpression (t, loc));
1080                                 }
1081
1082                                 TypeExpr ct = new ConstructedType (ctype, new_args, loc);
1083                                 if (ct.ResolveAsTypeTerminal (ec) == null)
1084                                         return false;
1085                                 ctype = ct.Type;
1086                         }
1087
1088                         return Convert.ImplicitStandardConversionExists (ec, expr, ctype);
1089                 }
1090
1091                 protected bool CheckConstraints (EmitContext ec, int index)
1092                 {
1093                         Type atype = atypes [index];
1094                         Type ptype = gen_params [index];
1095
1096                         if (atype == ptype)
1097                                 return true;
1098
1099                         Expression aexpr = new EmptyExpression (atype);
1100
1101                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (ptype);
1102                         if (gc == null)
1103                                 return true;
1104
1105                         //
1106                         // First, check the `class' and `struct' constraints.
1107                         //
1108                         if (gc.HasReferenceTypeConstraint && !atype.IsClass) {
1109                                 Report.Error (452, loc, "The type `{0}' must be " +
1110                                               "a reference type in order to use it " +
1111                                               "as type parameter `{1}' in the " +
1112                                               "generic type or method `{2}'.",
1113                                               atype, ptype, DeclarationName);
1114                                 return false;
1115                         } else if (gc.HasValueTypeConstraint && !atype.IsValueType) {
1116                                 Report.Error (453, loc, "The type `{0}' must be " +
1117                                               "a value type in order to use it " +
1118                                               "as type parameter `{1}' in the " +
1119                                               "generic type or method `{2}'.",
1120                                               atype, ptype, DeclarationName);
1121                                 return false;
1122                         }
1123
1124                         //
1125                         // The class constraint comes next.
1126                         //
1127                         if (gc.HasClassConstraint) {
1128                                 if (!CheckConstraint (ec, ptype, aexpr, gc.ClassConstraint)) {
1129                                         Report.Error (309, loc, "The type `{0}' must be " +
1130                                                       "convertible to `{1}' in order to " +
1131                                                       "use it as parameter `{2}' in the " +
1132                                                       "generic type or method `{3}'",
1133                                                       atype, gc.ClassConstraint, ptype, DeclarationName);
1134                                         return false;
1135                                 }
1136                         }
1137
1138                         //
1139                         // Now, check the interface constraints.
1140                         //
1141                         foreach (Type it in gc.InterfaceConstraints) {
1142                                 Type itype;
1143                                 if (it.IsGenericParameter)
1144                                         itype = atypes [it.GenericParameterPosition];
1145                                 else
1146                                         itype = it;
1147
1148                                 if (!CheckConstraint (ec, ptype, aexpr, itype)) {
1149                                         Report.Error (309, loc, "The type `{0}' must be " +
1150                                                       "convertible to `{1}' in order to " +
1151                                                       "use it as parameter `{2}' in the " +
1152                                                       "generic type or method `{3}'",
1153                                                       atype, itype, ptype, DeclarationName);
1154                                         return false;
1155                                 }
1156                         }
1157
1158                         //
1159                         // Finally, check the constructor constraint.
1160                         //
1161
1162                         if (!gc.HasConstructorConstraint)
1163                                 return true;
1164
1165                         if (TypeManager.IsBuiltinType (atype))
1166                                 return true;
1167
1168                         MethodGroupExpr mg = Expression.MemberLookup (
1169                                 ec, atype, ".ctor", MemberTypes.Constructor,
1170                                 BindingFlags.Public | BindingFlags.Instance |
1171                                 BindingFlags.DeclaredOnly, loc)
1172                                 as MethodGroupExpr;
1173
1174                         if (atype.IsAbstract || (mg == null) || !mg.IsInstance) {
1175                                 Report.Error (310, loc, "The type `{0}' must have a public " +
1176                                               "parameterless constructor in order to use it " +
1177                                               "as parameter `{1}' in the generic type or " +
1178                                               "method `{2}'", atype, ptype, DeclarationName);
1179                                 return false;
1180                         }
1181
1182                         return true;
1183                 }
1184
1185                 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
1186                 {
1187                         if (!ResolveConstructedType (ec))
1188                                 return null;
1189
1190                         return this;
1191                 }
1192
1193                 public bool CheckConstraints (EmitContext ec)
1194                 {
1195                         for (int i = 0; i < gen_params.Length; i++) {
1196                                 if (!CheckConstraints (ec, i))
1197                                         return false;
1198                         }
1199
1200                         return true;
1201                 }
1202
1203                 public override TypeExpr ResolveAsTypeTerminal (EmitContext ec)
1204                 {
1205                         if (base.ResolveAsTypeTerminal (ec) == null)
1206                                 return null;
1207
1208                         if (!CheckConstraints (ec))
1209                                 return null;
1210
1211                         return this;
1212                 }
1213
1214                 public bool ResolveConstructedType (EmitContext ec)
1215                 {
1216                         if (type != null)
1217                                 return true;
1218                         if (gt != null)
1219                                 return DoResolveType (ec);
1220
1221                         //
1222                         // First, resolve the generic type.
1223                         //
1224                         DeclSpace ds;
1225                         Type nested = ec.DeclSpace.FindNestedType (loc, name, out ds);
1226                         if (nested != null) {
1227                                 gt = nested.GetGenericTypeDefinition ();
1228
1229                                 TypeArguments new_args = new TypeArguments (loc);
1230                                 if (ds.IsGeneric) {
1231                                         foreach (TypeParameter param in ds.TypeParameters)
1232                                                 new_args.Add (new TypeParameterExpr (param, loc));
1233                                 }
1234                                 new_args.Add (args);
1235
1236                                 args = new_args;
1237                                 return DoResolveType (ec);
1238                         }
1239
1240                         Type t;
1241                         int num_args;
1242
1243                         SimpleName sn = new SimpleName (name, loc);
1244                         TypeExpr resolved = sn.ResolveAsTypeTerminal (ec);
1245                         if (resolved == null)
1246                                 return false;
1247
1248                         t = resolved.Type;
1249                         if (t == null) {
1250                                 Report.Error (246, loc, "Cannot find type `{0}'<...>",
1251                                               Basename);
1252                                 return false;
1253                         }
1254
1255                         num_args = TypeManager.GetNumberOfTypeArguments (t);
1256                         if (num_args == 0) {
1257                                 Report.Error (308, loc,
1258                                               "The non-generic type `{0}' cannot " +
1259                                               "be used with type arguments.",
1260                                               TypeManager.CSharpName (t));
1261                                 return false;
1262                         }
1263
1264                         gt = t.GetGenericTypeDefinition ();
1265                         return DoResolveType (ec);
1266                 }
1267
1268                 bool DoResolveType (EmitContext ec)
1269                 {
1270                         //
1271                         // Resolve the arguments.
1272                         //
1273                         if (args.Resolve (ec) == false)
1274                                 return false;
1275
1276                         gen_params = gt.GetGenericArguments ();
1277                         atypes = args.Arguments;
1278
1279                         if (atypes.Length != gen_params.Length) {
1280                                 Report.Error (305, loc,
1281                                               "Using the generic type `{0}' " +
1282                                               "requires {1} type arguments",
1283                                               TypeManager.GetFullName (gt),
1284                                               gen_params.Length);
1285                                 return false;
1286                         }
1287
1288                         //
1289                         // Now bind the parameters.
1290                         //
1291                         type = gt.BindGenericParameters (atypes);
1292                         return true;
1293                 }
1294
1295                 public Expression GetSimpleName (EmitContext ec)
1296                 {
1297                         return new SimpleName (Basename, args, loc);
1298                 }
1299
1300                 public override bool CheckAccessLevel (DeclSpace ds)
1301                 {
1302                         return ds.CheckAccessLevel (gt);
1303                 }
1304
1305                 public override bool AsAccessible (DeclSpace ds, int flags)
1306                 {
1307                         return ds.AsAccessible (gt, flags);
1308                 }
1309
1310                 public override bool IsClass {
1311                         get { return gt.IsClass; }
1312                 }
1313
1314                 public override bool IsValueType {
1315                         get { return gt.IsValueType; }
1316                 }
1317
1318                 public override bool IsInterface {
1319                         get { return gt.IsInterface; }
1320                 }
1321
1322                 public override bool IsSealed {
1323                         get { return gt.IsSealed; }
1324                 }
1325
1326                 public override bool IsAttribute {
1327                         get { return false; }
1328                 }
1329
1330                 public override bool Equals (object obj)
1331                 {
1332                         ConstructedType cobj = obj as ConstructedType;
1333                         if (cobj == null)
1334                                 return false;
1335
1336                         if ((type == null) || (cobj.type == null))
1337                                 return false;
1338
1339                         return type == cobj.type;
1340                 }
1341
1342                 public string Basename {
1343                         get {
1344                                 int pos = name.LastIndexOf ('`');
1345                                 if (pos >= 0)
1346                                         return name.Substring (0, pos);
1347                                 else
1348                                         return name;
1349                         }
1350                 }
1351
1352                 public override string Name {
1353                         get {
1354                                 return full_name;
1355                         }
1356                 }
1357         }
1358
1359         public class GenericMethod : DeclSpace
1360         {
1361                 public GenericMethod (NamespaceEntry ns, TypeContainer parent,
1362                                       MemberName name, Location l)
1363                         : base (ns, parent, name, null, l)
1364                 { }
1365
1366                 public override TypeBuilder DefineType ()
1367                 {
1368                         throw new Exception ();
1369                 }
1370
1371                 public override bool Define ()
1372                 {
1373                         for (int i = 0; i < TypeParameters.Length; i++)
1374                                 if (!TypeParameters [i].Resolve (Parent))
1375                                         return false;
1376
1377                         return true;
1378                 }
1379
1380                 public bool Define (MethodBuilder mb, Type return_type)
1381                 {
1382                         if (!Define ())
1383                                 return false;
1384
1385                         GenericTypeParameterBuilder[] gen_params;
1386                         string[] names = MemberName.TypeArguments.GetDeclarations ();
1387                         gen_params = mb.DefineGenericParameters (names);
1388                         for (int i = 0; i < TypeParameters.Length; i++)
1389                                 TypeParameters [i].Define (gen_params [i]);
1390
1391                         ec = new EmitContext (
1392                                 this, this, Location, null, return_type, ModFlags, false);
1393
1394                         return true;
1395                 }
1396
1397                 public bool DefineType (EmitContext ec, MethodBuilder mb,
1398                                         MethodInfo implementing, bool is_override)
1399                 {
1400                         for (int i = 0; i < TypeParameters.Length; i++)
1401                                 if (!TypeParameters [i].DefineType (
1402                                             ec, mb, implementing, is_override))
1403                                         return false;
1404
1405                         return true;
1406                 }
1407
1408                 public override bool DefineMembers (TypeContainer parent)
1409                 {
1410                         return true;
1411                 }
1412
1413                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
1414                                                         MemberFilter filter, object criteria)
1415                 {
1416                         throw new Exception ();
1417                 }               
1418
1419                 public override MemberCache MemberCache {
1420                         get {
1421                                 throw new Exception ();
1422                         }
1423                 }
1424
1425                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
1426                 {
1427                         // FIXME
1428                 }
1429
1430                 protected override void VerifyObsoleteAttribute()
1431                 {
1432                         // FIXME
1433                 }
1434
1435                 public override AttributeTargets AttributeTargets {
1436                         get {
1437                                 return AttributeTargets.Method | AttributeTargets.ReturnValue;
1438                         }
1439                 }
1440         }
1441
1442         public class DefaultValueExpression : Expression
1443         {
1444                 Expression expr;
1445                 LocalTemporary temp_storage;
1446
1447                 public DefaultValueExpression (Expression expr, Location loc)
1448                 {
1449                         this.expr = expr;
1450                         this.loc = loc;
1451                 }
1452
1453                 public override Expression DoResolve (EmitContext ec)
1454                 {
1455                         TypeExpr texpr = expr.ResolveAsTypeTerminal (ec);
1456                         if (texpr == null)
1457                                 return null;
1458
1459                         type = texpr.Type;
1460                         if (type.IsGenericParameter || TypeManager.IsValueType (type))
1461                                 temp_storage = new LocalTemporary (ec, type);
1462
1463                         eclass = ExprClass.Variable;
1464                         return this;
1465                 }
1466
1467                 public override void Emit (EmitContext ec)
1468                 {
1469                         if (temp_storage != null) {
1470                                 temp_storage.AddressOf (ec, AddressOp.LoadStore);
1471                                 ec.ig.Emit (OpCodes.Initobj, type);
1472                                 temp_storage.Emit (ec);
1473                         } else
1474                                 ec.ig.Emit (OpCodes.Ldnull);
1475                 }
1476         }
1477 }