2005-02-20 Daniel Morgan <danielmorgan@verizon.net>
[mono.git] / mcs / bmcs / generic.cs
1 //
2 // generic.cs: Generics support
3 //
4 // Authors: Martin Baulig (martin@ximian.com)
5 //          Miguel de Icaza (miguel@ximian.com)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
10 // (C) 2004 Novell, Inc
11 //
12 using System;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Globalization;
16 using System.Collections;
17 using System.Text;
18 using System.Text.RegularExpressions;
19         
20 namespace Mono.CSharp {
21
22         public abstract class GenericConstraints {
23                 public abstract GenericParameterAttributes Attributes {
24                         get;
25                 }
26
27                 public bool HasConstructorConstraint {
28                         get { return (Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0; }
29                 }
30
31                 public bool HasReferenceTypeConstraint {
32                         get { return (Attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0; }
33                 }
34
35                 public bool HasValueTypeConstraint {
36                         get { return (Attributes & GenericParameterAttributes.ValueTypeConstraint) != 0; }
37                 }
38
39                 public virtual bool HasClassConstraint {
40                         get { return ClassConstraint != null; }
41                 }
42
43                 public abstract Type ClassConstraint {
44                         get;
45                 }
46
47                 public abstract Type[] InterfaceConstraints {
48                         get;
49                 }
50
51                 public abstract Type EffectiveBaseClass {
52                         get;
53                 }
54
55                 // <summary>
56                 //   Returns whether the type parameter is "known to be a reference type".
57                 // </summary>
58                 public virtual bool IsReferenceType {
59                         get {
60                                 if (HasReferenceTypeConstraint)
61                                         return true;
62                                 if (HasValueTypeConstraint)
63                                         return false;
64
65                                 if (ClassConstraint != null) {
66                                         if (ClassConstraint.IsValueType)
67                                                 return false;
68
69                                         if (ClassConstraint != TypeManager.object_type)
70                                                 return true;
71                                 }
72
73                                 foreach (Type t in InterfaceConstraints) {
74                                         if (!t.IsGenericParameter)
75                                                 continue;
76
77                                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
78                                         if ((gc != null) && gc.IsReferenceType)
79                                                 return true;
80                                 }
81
82                                 return false;
83                         }
84                 }
85
86                 // <summary>
87                 //   Returns whether the type parameter is "known to be a value type".
88                 // </summary>
89                 public virtual bool IsValueType {
90                         get {
91                                 if (HasValueTypeConstraint)
92                                         return true;
93                                 if (HasReferenceTypeConstraint)
94                                         return false;
95
96                                 if (ClassConstraint != null) {
97                                         if (!ClassConstraint.IsValueType)
98                                                 return false;
99
100                                         if (ClassConstraint != TypeManager.value_type)
101                                                 return true;
102                                 }
103
104                                 foreach (Type t in InterfaceConstraints) {
105                                         if (!t.IsGenericParameter)
106                                                 continue;
107
108                                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
109                                         if ((gc != null) && gc.IsValueType)
110                                                 return true;
111                                 }
112
113                                 return false;
114                         }
115                 }
116         }
117
118         public enum SpecialConstraint
119         {
120                 Constructor,
121                 ReferenceType,
122                 ValueType
123         }
124
125         //
126         // Tracks the constraints for a type parameter
127         //
128         public class Constraints : GenericConstraints {
129                 string name;
130                 ArrayList constraints;
131                 Location loc;
132                 
133                 //
134                 // name is the identifier, constraints is an arraylist of
135                 // Expressions (with types) or `true' for the constructor constraint.
136                 // 
137                 public Constraints (string name, ArrayList constraints,
138                                     Location loc)
139                 {
140                         this.name = name;
141                         this.constraints = constraints;
142                         this.loc = loc;
143                 }
144
145                 public string TypeParameter {
146                         get {
147                                 return name;
148                         }
149                 }
150
151                 GenericParameterAttributes attrs;
152                 TypeExpr class_constraint;
153                 ArrayList iface_constraints;
154                 ArrayList type_param_constraints;
155                 int num_constraints, first_constraint;
156                 Type class_constraint_type;
157                 Type[] iface_constraint_types;
158                 Type effective_base_type;
159
160                 public bool Resolve (EmitContext ec)
161                 {
162                         iface_constraints = new ArrayList ();
163                         type_param_constraints = new ArrayList ();
164
165                         foreach (object obj in constraints) {
166                                 if (HasConstructorConstraint) {
167                                         Report.Error (401, loc,
168                                                       "The new() constraint must be last.");
169                                         return false;
170                                 }
171
172                                 if (obj is SpecialConstraint) {
173                                         SpecialConstraint sc = (SpecialConstraint) obj;
174
175                                         if (sc == SpecialConstraint.Constructor) {
176                                                 if (!HasValueTypeConstraint) {
177                                                         attrs |= GenericParameterAttributes.DefaultConstructorConstraint;
178                                                         continue;
179                                                 }
180
181                                                 Report.Error (
182                                                         451, loc, "The new () constraint " +
183                                                         "cannot be used with the `struct' " +
184                                                         "constraint.");
185                                                 return false;
186                                         }
187
188                                         if ((num_constraints > 0) || HasReferenceTypeConstraint || HasValueTypeConstraint) {
189                                                 Report.Error (449, loc,
190                                                               "The `class' or `struct' " +
191                                                               "constraint must be first");
192                                                 return false;
193                                         }
194
195                                         if (sc == SpecialConstraint.ReferenceType)
196                                                 attrs |= GenericParameterAttributes.ReferenceTypeConstraint;
197                                         else
198                                                 attrs |= GenericParameterAttributes.ValueTypeConstraint;
199                                         continue;
200                                 }
201
202                                 TypeExpr expr;
203                                 if (obj is ConstructedType) {
204                                         ConstructedType cexpr = (ConstructedType) obj;
205                                         if (!cexpr.ResolveConstructedType (ec))
206                                                 return false;
207                                         expr = cexpr;
208                                 } else
209                                         expr = ((Expression) obj).ResolveAsTypeTerminal (ec);
210
211                                 if (expr == null)
212                                         return false;
213
214                                 TypeParameterExpr texpr = expr as TypeParameterExpr;
215                                 if (texpr != null)
216                                         type_param_constraints.Add (expr);
217                                 else if (expr.IsInterface)
218                                         iface_constraints.Add (expr);
219                                 else if (class_constraint != null) {
220                                         Report.Error (406, loc,
221                                                       "`{0}': the class constraint for `{1}' " +
222                                                       "must come before any other constraints.",
223                                                       expr.Name, name);
224                                         return false;
225                                 } else if (HasReferenceTypeConstraint || HasValueTypeConstraint) {
226                                         Report.Error (450, loc, "`{0}': cannot specify both " +
227                                                       "a constraint class and the `class' " +
228                                                       "or `struct' constraint.", expr.Name);
229                                         return false;
230                                 } else
231                                         class_constraint = expr;
232
233                                 num_constraints++;
234                         }
235
236                         return true;
237                 }
238
239                 bool CheckTypeParameterConstraints (TypeParameter tparam, Hashtable seen)
240                 {
241                         seen.Add (tparam, true);
242
243                         Constraints constraints = tparam.Constraints;
244                         if (constraints == null)
245                                 return true;
246
247                         if (constraints.HasValueTypeConstraint) {
248                                 Report.Error (456, loc, "Type parameter `{0}' has " +
249                                               "the `struct' constraint, so it cannot " +
250                                               "be used as a constraint for `{1}'",
251                                               tparam.Name, name);
252                                 return false;
253                         }
254
255                         if (constraints.type_param_constraints == null)
256                                 return true;
257
258                         foreach (TypeParameterExpr expr in constraints.type_param_constraints) {
259                                 if (seen.Contains (expr.TypeParameter)) {
260                                         Report.Error (454, loc, "Circular constraint " +
261                                                       "dependency involving `{0}' and `{1}'",
262                                                       tparam.Name, expr.Name);
263                                         return false;
264                                 }
265
266                                 if (!CheckTypeParameterConstraints (expr.TypeParameter, seen))
267                                         return false;
268                         }
269
270                         return true;
271                 }
272
273                 public bool ResolveTypes (EmitContext ec)
274                 {
275                         foreach (object obj in constraints) {
276                                 ConstructedType cexpr = obj as ConstructedType;
277                                 if (cexpr == null)
278                                         continue;
279
280                                 if (!cexpr.CheckConstraints (ec))
281                                         return false;
282                         }
283
284                         foreach (TypeParameterExpr expr in type_param_constraints) {
285                                 Hashtable seen = new Hashtable ();
286                                 if (!CheckTypeParameterConstraints (expr.TypeParameter, seen))
287                                         return false;
288                         }
289
290                         ArrayList list = new ArrayList ();
291
292                         foreach (TypeExpr iface_constraint in iface_constraints) {
293                                 foreach (Type type in list) {
294                                         if (!type.Equals (iface_constraint.Type))
295                                                 continue;
296
297                                         Report.Error (405, loc,
298                                                       "Duplicate constraint `{0}' for type " +
299                                                       "parameter `{1}'.", iface_constraint.Type,
300                                                       name);
301                                         return false;
302                                 }
303
304                                 list.Add (iface_constraint.Type);
305                         }
306
307                         foreach (TypeParameterExpr expr in type_param_constraints) {
308                                 foreach (Type type in list) {
309                                         if (!type.Equals (expr.Type))
310                                                 continue;
311
312                                         Report.Error (405, loc,
313                                                       "Duplicate constraint `{0}' for type " +
314                                                       "parameter `{1}'.", expr.Type, name);
315                                         return false;
316                                 }
317
318                                 list.Add (expr.Type);
319                         }
320
321                         iface_constraint_types = new Type [list.Count];
322                         list.CopyTo (iface_constraint_types, 0);
323
324                         if (class_constraint != null) {
325                                 class_constraint_type = class_constraint.Type;
326                                 if (class_constraint_type == null)
327                                         return false;
328
329                                 if (class_constraint_type.IsSealed) {
330                                         Report.Error (701, loc,
331                                                       "`{0}' is not a valid bound.  Bounds " +
332                                                       "must be interfaces or non sealed " +
333                                                       "classes", class_constraint_type);
334                                         return false;
335                                 }
336
337                                 if ((class_constraint_type == TypeManager.array_type) ||
338                                     (class_constraint_type == TypeManager.delegate_type) ||
339                                     (class_constraint_type == TypeManager.enum_type) ||
340                                     (class_constraint_type == TypeManager.value_type) ||
341                                     (class_constraint_type == TypeManager.object_type)) {
342                                         Report.Error (702, loc,
343                                                       "Bound cannot be special class `{0}'",
344                                                       class_constraint_type);
345                                         return false;
346                                 }
347                         }
348
349                         if (class_constraint_type != null)
350                                 effective_base_type = class_constraint_type;
351                         else if (HasValueTypeConstraint)
352                                 effective_base_type = TypeManager.value_type;
353                         else
354                                 effective_base_type = TypeManager.object_type;
355
356                         return true;
357                 }
358
359                 public bool CheckDependencies (EmitContext ec)
360                 {
361                         foreach (TypeParameterExpr expr in type_param_constraints) {
362                                 if (!CheckDependencies (expr.TypeParameter, ec))
363                                         return false;
364                         }
365
366                         return true;
367                 }
368
369                 bool CheckDependencies (TypeParameter tparam, EmitContext ec)
370                 {
371                         Constraints constraints = tparam.Constraints;
372                         if (constraints == null)
373                                 return true;
374
375                         if (HasValueTypeConstraint && constraints.HasClassConstraint) {
376                                 Report.Error (455, loc, "Type parameter `{0}' inherits " +
377                                               "conflicting constraints `{1}' and `{2}'",
378                                               name, constraints.ClassConstraint,
379                                               "System.ValueType");
380                                 return false;
381                         }
382
383                         if (HasClassConstraint && constraints.HasClassConstraint) {
384                                 Type t1 = ClassConstraint;
385                                 TypeExpr e1 = class_constraint;
386                                 Type t2 = constraints.ClassConstraint;
387                                 TypeExpr e2 = constraints.class_constraint;
388
389                                 if (!Convert.ImplicitReferenceConversionExists (ec, e1, t2) &&
390                                     !Convert.ImplicitReferenceConversionExists (ec, e2, t1)) {
391                                         Report.Error (455, loc,
392                                                       "Type parameter `{0}' inherits " +
393                                                       "conflicting constraints `{1}' and `{2}'",
394                                                       name, t1, t2);
395                                         return false;
396                                 }
397                         }
398
399                         if (constraints.type_param_constraints == null)
400                                 return true;
401
402                         foreach (TypeParameterExpr expr in constraints.type_param_constraints) {
403                                 if (!CheckDependencies (expr.TypeParameter, ec))
404                                         return false;
405                         }
406
407                         return true;
408                 }
409
410                 public void Define (GenericTypeParameterBuilder type)
411                 {
412                         type.SetGenericParameterAttributes (attrs);
413                 }
414
415                 public override GenericParameterAttributes Attributes {
416                         get { return attrs; }
417                 }
418
419                 public override bool HasClassConstraint {
420                         get { return class_constraint != null; }
421                 }
422
423                 public override Type ClassConstraint {
424                         get { return class_constraint_type; }
425                 }
426
427                 public override Type[] InterfaceConstraints {
428                         get { return iface_constraint_types; }
429                 }
430
431                 public override Type EffectiveBaseClass {
432                         get { return effective_base_type; }
433                 }
434
435                 internal bool IsSubclassOf (Type t)
436                 {
437                         if ((class_constraint_type != null) &&
438                             class_constraint_type.IsSubclassOf (t))
439                                 return true;
440
441                         if (iface_constraint_types == null)
442                                 return false;
443
444                         foreach (Type iface in iface_constraint_types) {
445                                 if (TypeManager.IsSubclassOf (iface, t))
446                                         return true;
447                         }
448
449                         return false;
450                 }
451
452                 public bool CheckInterfaceMethod (EmitContext ec, GenericConstraints gc)
453                 {
454                         if (!ResolveTypes (ec))
455                                 return false;
456
457                         if (gc.Attributes != attrs)
458                                 return false;
459
460                         if (HasClassConstraint != gc.HasClassConstraint)
461                                 return false;
462                         if (HasClassConstraint && !TypeManager.IsEqual (gc.ClassConstraint, ClassConstraint))
463                                 return false;
464
465                         int gc_icount = gc.InterfaceConstraints != null ?
466                                 gc.InterfaceConstraints.Length : 0;
467                         int icount = InterfaceConstraints != null ?
468                                 InterfaceConstraints.Length : 0;
469
470                         if (gc_icount != icount)
471                                 return false;
472
473                         foreach (Type iface in gc.InterfaceConstraints) {
474                                 bool ok = false;
475                                 foreach (Type check in InterfaceConstraints) {
476                                         if (TypeManager.IsEqual (iface, check)) {
477                                                 ok = true;
478                                                 break;
479                                         }
480                                 }
481
482                                 if (!ok)
483                                         return false;
484                         }
485
486                         return true;
487                 }
488         }
489
490         //
491         // This type represents a generic type parameter
492         //
493         public class TypeParameter : MemberCore, IMemberContainer {
494                 string name;
495                 GenericConstraints gc;
496                 Constraints constraints;
497                 Location loc;
498                 GenericTypeParameterBuilder type;
499
500                 public TypeParameter (TypeContainer parent, string name,
501                                       Constraints constraints, Location loc)
502                         : base (parent, new MemberName (name), null, loc)
503                 {
504                         this.name = name;
505                         this.constraints = constraints;
506                         this.loc = loc;
507                 }
508
509                 public GenericConstraints GenericConstraints {
510                         get {
511                                 return gc != null ? gc : constraints;
512                         }
513                 }
514
515                 public Constraints Constraints {
516                         get {
517                                 return constraints;
518                         }
519                 }
520
521                 public bool HasConstructorConstraint {
522                         get {
523                                 if (constraints != null)
524                                         return constraints.HasConstructorConstraint;
525
526                                 return false;
527                         }
528                 }
529
530                 public Type Type {
531                         get {
532                                 return type;
533                         }
534                 }
535
536                 public bool Resolve (DeclSpace ds)
537                 {
538                         if (constraints != null)
539                                 return constraints.Resolve (ds.EmitContext);
540
541                         return true;
542                 }
543
544                 public void Define (GenericTypeParameterBuilder type)
545                 {
546                         if (this.type != null)
547                                 throw new InvalidOperationException ();
548
549                         this.type = type;
550                         TypeManager.AddTypeParameter (type, this);
551                 }
552
553                 public void DefineConstraints ()
554                 {
555                         if (constraints != null)
556                                 constraints.Define (type);
557                 }
558
559                 public bool DefineType (EmitContext ec)
560                 {
561                         return DefineType (ec, null, null, false);
562                 }
563
564                 public bool DefineType (EmitContext ec, MethodBuilder builder,
565                                         MethodInfo implementing, bool is_override)
566                 {
567                         if (implementing != null) {
568                                 if (is_override && (constraints != null)) {
569                                         Report.Error (
570                                                 460, loc, "Constraints for override and " +
571                                                 "explicit interface implementation methods " +
572                                                 "are inherited from the base method so they " +
573                                                 "cannot be specified directly");
574                                         return false;
575                                 }
576
577                                 MethodBase mb = implementing;
578                                 if (mb.Mono_IsInflatedMethod)
579                                         mb = mb.GetGenericMethodDefinition ();
580
581                                 int pos = type.GenericParameterPosition;
582                                 ParameterData pd = Invocation.GetParameterData (mb);
583                                 GenericConstraints temp_gc = pd.GenericConstraints (pos);
584                                 Type mparam = mb.GetGenericArguments () [pos];
585
586                                 if (temp_gc != null)
587                                         gc = new InflatedConstraints (temp_gc, implementing.DeclaringType);
588                                 else if (constraints != null)
589                                         gc = new InflatedConstraints (constraints, implementing.DeclaringType);
590
591                                 bool ok = true;
592                                 if (constraints != null) {
593                                         if (temp_gc == null)
594                                                 ok = false;
595                                         else if (!constraints.CheckInterfaceMethod (ec, gc))
596                                                 ok = false;
597                                 } else {
598                                         if (!is_override && (temp_gc != null))
599                                                 ok = false;
600                                 }
601
602                                 if (!ok) {
603                                         Report.SymbolRelatedToPreviousError (implementing);
604
605                                         Report.Error (
606                                                 425, loc, "The constraints for type " +
607                                                 "parameter `{0}' of method `{1}' must match " +
608                                                 "the constraints for type parameter `{2}' " +
609                                                 "of interface method `{3}'.  Consider using " +
610                                                 "an explicit interface implementation instead",
611                                                 Name, TypeManager.CSharpSignature (builder),
612                                                 mparam, TypeManager.CSharpSignature (mb));
613                                         return false;
614                                 }
615                         } else {
616                                 if (constraints != null) {
617                                         if (!constraints.ResolveTypes (ec))
618                                                 return false;
619                                 }
620
621                                 gc = (GenericConstraints) constraints;
622                         }
623
624                         if (gc == null)
625                                 return true;
626
627                         if (gc.HasClassConstraint)
628                                 type.SetBaseTypeConstraint (gc.ClassConstraint);
629
630                         type.SetInterfaceConstraints (gc.InterfaceConstraints);
631                         TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
632
633                         return true;
634                 }
635
636                 public bool CheckDependencies (EmitContext ec)
637                 {
638                         if (constraints != null)
639                                 return constraints.CheckDependencies (ec);
640
641                         return true;
642                 }
643
644                 public override string DocCommentHeader {
645                         get {
646                                 throw new InvalidOperationException (
647                                         "Unexpected attempt to get doc comment from " + this.GetType () + ".");
648                         }
649                 }
650
651                 //
652                 // MemberContainer
653                 //
654
655                 public override bool Define ()
656                 {
657                         return true;
658                 }
659
660                 protected override void VerifyObsoleteAttribute ()
661                 { }
662
663                 public override void ApplyAttributeBuilder (Attribute a,
664                                                             CustomAttributeBuilder cb)
665                 { }
666
667                 public override AttributeTargets AttributeTargets {
668                         get {
669                                 return (AttributeTargets) 0;
670                         }
671                 }
672
673                 public override string[] ValidAttributeTargets {
674                         get {
675                                 return new string [0];
676                         }
677                 }
678
679                 //
680                 // IMemberContainer
681                 //
682
683                 string IMemberContainer.Name {
684                         get { return Name; }
685                 }
686
687                 MemberCache IMemberContainer.BaseCache {
688                         get { return null; }
689                 }
690
691                 bool IMemberContainer.IsInterface {
692                         get { return true; }
693                 }
694
695                 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
696                 {
697                         return FindMembers (mt, bf, null, null);
698                 }
699
700                 MemberCache IMemberContainer.MemberCache {
701                         get { return null; }
702                 }
703
704                 public MemberList FindMembers (MemberTypes mt, BindingFlags bf,
705                                                MemberFilter filter, object criteria)
706                 {
707                         if (constraints == null)
708                                 return MemberList.Empty;
709
710                         ArrayList members = new ArrayList ();
711
712                         GenericConstraints gc = (GenericConstraints) constraints;
713
714                         if (gc.HasClassConstraint) {
715                                 MemberList list = TypeManager.FindMembers (
716                                         gc.ClassConstraint, mt, bf, filter, criteria);
717
718                                 members.AddRange (list);
719                         }
720
721                         foreach (Type t in gc.InterfaceConstraints) {
722                                 MemberList list = TypeManager.FindMembers (
723                                         t, mt, bf, filter, criteria);
724
725                                 members.AddRange (list);
726                         }
727
728                         return new MemberList (members);
729                 }
730
731                 public bool IsSubclassOf (Type t)
732                 {
733                         if (type.Equals (t))
734                                 return true;
735
736                         if (constraints != null)
737                                 return constraints.IsSubclassOf (t);
738
739                         return false;
740                 }
741
742                 public override string ToString ()
743                 {
744                         return "TypeParameter[" + name + "]";
745                 }
746
747                 protected class InflatedConstraints : GenericConstraints
748                 {
749                         GenericConstraints gc;
750                         Type base_type;
751                         Type class_constraint;
752                         Type[] iface_constraints;
753                         Type[] dargs;
754                         Type declaring;
755
756                         public InflatedConstraints (GenericConstraints gc, Type declaring)
757                         {
758                                 this.gc = gc;
759                                 this.declaring = declaring;
760
761                                 dargs = TypeManager.GetTypeArguments (declaring);
762
763                                 ArrayList list = new ArrayList ();
764                                 if (gc.HasClassConstraint)
765                                         list.Add (inflate (gc.ClassConstraint));
766                                 foreach (Type iface in gc.InterfaceConstraints)
767                                         list.Add (inflate (iface));
768
769                                 bool has_class_constr = false;
770                                 if (list.Count > 0) {
771                                         Type first = (Type) list [0];
772                                         has_class_constr = !first.IsInterface && !first.IsGenericParameter;
773                                 }
774
775                                 if ((list.Count > 0) && has_class_constr) {
776                                         class_constraint = (Type) list [0];
777                                         iface_constraints = new Type [list.Count - 1];
778                                         list.CopyTo (1, iface_constraints, 0, list.Count - 1);
779                                 } else {
780                                         iface_constraints = new Type [list.Count];
781                                         list.CopyTo (iface_constraints, 0);
782                                 }
783
784                                 if (HasValueTypeConstraint)
785                                         base_type = TypeManager.value_type;
786                                 else if (class_constraint != null)
787                                         base_type = class_constraint;
788                                 else
789                                         base_type = TypeManager.object_type;
790                         }
791
792                         Type inflate (Type t)
793                         {
794                                 if (t == null)
795                                         return null;
796                                 if (t.IsGenericParameter)
797                                         return dargs [t.GenericParameterPosition];
798                                 if (t.IsGenericInstance) {
799                                         t = t.GetGenericTypeDefinition ();
800                                         t = t.BindGenericParameters (dargs);
801                                 }
802
803                                 return t;
804                         }
805
806                         public override GenericParameterAttributes Attributes {
807                                 get { return gc.Attributes; }
808                         }
809
810                         public override Type ClassConstraint {
811                                 get { return class_constraint; }
812                         }
813
814                         public override Type EffectiveBaseClass {
815                                 get { return base_type; }
816                         }
817
818                         public override Type[] InterfaceConstraints {
819                                 get { return iface_constraints; }
820                         }
821                 }
822         }
823
824         //
825         // This type represents a generic type parameter reference.
826         //
827         // These expressions are born in a fully resolved state.
828         //
829         public class TypeParameterExpr : TypeExpr {
830                 TypeParameter type_parameter;
831
832                 public override string Name {
833                         get {
834                                 return type_parameter.Name;
835                         }
836                 }
837
838                 public override string FullName {
839                         get {
840                                 return type_parameter.Name;
841                         }
842                 }
843
844                 public TypeParameter TypeParameter {
845                         get {
846                                 return type_parameter;
847                         }
848                 }
849                 
850                 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
851                 {
852                         this.type_parameter = type_parameter;
853                         this.loc = loc;
854                 }
855
856                 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
857                 {
858                         type = type_parameter.Type;
859
860                         return this;
861                 }
862
863                 public override bool IsInterface {
864                         get { return false; }
865                 }
866
867                 public override bool CheckAccessLevel (DeclSpace ds)
868                 {
869                         return true;
870                 }
871
872                 public void Error_CannotUseAsUnmanagedType (Location loc)
873                 {
874                         Report.Error (-203, loc, "Can not use type parameter as unamanged type");
875                 }
876         }
877
878         public class TypeArguments {
879                 public readonly Location Location;
880                 ArrayList args;
881                 Type[] atypes;
882                 int dimension;
883                 bool has_type_args;
884                 bool created;
885                 
886                 public TypeArguments (Location loc)
887                 {
888                         args = new ArrayList ();
889                         this.Location = loc;
890                 }
891
892                 public TypeArguments (int dimension, Location loc)
893                 {
894                         this.dimension = dimension;
895                         this.Location = loc;
896                 }
897
898                 public void Add (Expression type)
899                 {
900                         if (created)
901                                 throw new InvalidOperationException ();
902
903                         args.Add (type);
904                 }
905
906                 public void Add (TypeArguments new_args)
907                 {
908                         if (created)
909                                 throw new InvalidOperationException ();
910
911                         args.AddRange (new_args.args);
912                 }
913
914                 public string[] GetDeclarations ()
915                 {
916                         string[] ret = new string [args.Count];
917                         for (int i = 0; i < args.Count; i++) {
918                                 SimpleName sn = args [i] as SimpleName;
919                                 if (sn != null) {
920                                         ret [i] = sn.Name;
921                                         continue;
922                                 }
923
924                                 Report.Error (81, Location, "Type parameter declaration " +
925                                               "must be an identifier not a type");
926                                 return null;
927                         }
928                         return ret;
929                 }
930
931                 public Type[] Arguments {
932                         get {
933                                 return atypes;
934                         }
935                 }
936
937                 public bool HasTypeArguments {
938                         get {
939                                 return has_type_args;
940                         }
941                 }
942
943                 public int Count {
944                         get {
945                                 if (dimension > 0)
946                                         return dimension;
947                                 else
948                                         return args.Count;
949                         }
950                 }
951
952                 public bool IsUnbound {
953                         get {
954                                 return dimension > 0;
955                         }
956                 }
957
958                 public override string ToString ()
959                 {
960                         StringBuilder s = new StringBuilder ();
961
962                         int count = Count;
963                         for (int i = 0; i < count; i++){
964                                 //
965                                 // FIXME: Use TypeManager.CSharpname once we have the type
966                                 //
967                                 if (args != null)
968                                         s.Append (args [i].ToString ());
969                                 if (i+1 < count)
970                                         s.Append (",");
971                         }
972                         return s.ToString ();
973                 }
974
975                 public bool Resolve (EmitContext ec)
976                 {
977                         int count = args.Count;
978                         bool ok = true;
979
980                         atypes = new Type [count];
981
982                         for (int i = 0; i < count; i++){
983                                 TypeExpr te = ((Expression) args [i]).ResolveAsTypeTerminal (ec);
984                                 if (te == null) {
985                                         ok = false;
986                                         continue;
987                                 }
988                                 if (te is TypeParameterExpr)
989                                         has_type_args = true;
990
991                                 atypes [i] = te.Type;
992                         }
993                         return ok;
994                 }
995         }
996         
997         public class ConstructedType : TypeExpr {
998                 string name, full_name;
999                 TypeArguments args;
1000                 Type[] gen_params, atypes;
1001                 Type gt;
1002                 
1003                 public ConstructedType (string name, TypeArguments args, Location l)
1004                 {
1005                         loc = l;
1006                         this.name = MemberName.MakeName (name, args.Count);
1007                         this.args = args;
1008
1009                         eclass = ExprClass.Type;
1010                         full_name = name + "<" + args.ToString () + ">";
1011                 }
1012
1013                 public ConstructedType (string name, TypeParameter[] type_params, Location l)
1014                         : this (type_params, l)
1015                 {
1016                         loc = l;
1017
1018                         this.name = name;
1019                         full_name = name + "<" + args.ToString () + ">";
1020                 }
1021
1022                 public ConstructedType (FullNamedExpression fname, TypeArguments args, Location l)
1023                 {
1024                         loc = l;
1025                         this.name = fname.FullName;
1026                         this.args = args;
1027
1028                         eclass = ExprClass.Type;
1029                         full_name = name + "<" + args.ToString () + ">";
1030                 }
1031
1032                 protected ConstructedType (TypeArguments args, Location l)
1033                 {
1034                         loc = l;
1035                         this.args = args;
1036
1037                         eclass = ExprClass.Type;
1038                 }
1039
1040                 protected ConstructedType (TypeParameter[] type_params, Location l)
1041                 {
1042                         loc = l;
1043
1044                         args = new TypeArguments (l);
1045                         foreach (TypeParameter type_param in type_params)
1046                                 args.Add (new TypeParameterExpr (type_param, l));
1047
1048                         eclass = ExprClass.Type;
1049                 }
1050
1051                 public ConstructedType (Type t, TypeParameter[] type_params, Location l)
1052                         : this (type_params, l)
1053                 {
1054                         gt = t.GetGenericTypeDefinition ();
1055
1056                         this.name = gt.FullName;
1057                         full_name = gt.FullName + "<" + args.ToString () + ">";
1058                 }
1059
1060                 public ConstructedType (Type t, TypeArguments args, Location l)
1061                         : this (args, l)
1062                 {
1063                         gt = t.GetGenericTypeDefinition ();
1064
1065                         this.name = gt.FullName;
1066                         full_name = gt.FullName + "<" + args.ToString () + ">";
1067                 }
1068
1069                 public TypeArguments TypeArguments {
1070                         get { return args; }
1071                 }
1072
1073                 protected string DeclarationName {
1074                         get {
1075                                 StringBuilder sb = new StringBuilder ();
1076                                 sb.Append (gt.FullName);
1077                                 sb.Append ("<");
1078                                 for (int i = 0; i < gen_params.Length; i++) {
1079                                         if (i > 0)
1080                                                 sb.Append (",");
1081                                         sb.Append (gen_params [i]);
1082                                 }
1083                                 sb.Append (">");
1084                                 return sb.ToString ();
1085                         }
1086                 }
1087
1088                 protected bool CheckConstraint (EmitContext ec, Type ptype, Expression expr,
1089                                                 Type ctype)
1090                 {
1091                         if (TypeManager.HasGenericArguments (ctype)) {
1092                                 Type[] types = TypeManager.GetTypeArguments (ctype);
1093
1094                                 TypeArguments new_args = new TypeArguments (loc);
1095
1096                                 for (int i = 0; i < types.Length; i++) {
1097                                         Type t = types [i];
1098
1099                                         if (t.IsGenericParameter) {
1100                                                 int pos = t.GenericParameterPosition;
1101                                                 t = args.Arguments [pos];
1102                                         }
1103                                         new_args.Add (new TypeExpression (t, loc));
1104                                 }
1105
1106                                 TypeExpr ct = new ConstructedType (ctype, new_args, loc);
1107                                 if (ct.ResolveAsTypeTerminal (ec) == null)
1108                                         return false;
1109                                 ctype = ct.Type;
1110                         }
1111
1112                         return Convert.ImplicitStandardConversionExists (ec, expr, ctype);
1113                 }
1114
1115                 protected bool CheckConstraints (EmitContext ec, int index)
1116                 {
1117                         Type atype = atypes [index];
1118                         Type ptype = gen_params [index];
1119
1120                         if (atype == ptype)
1121                                 return true;
1122
1123                         Expression aexpr = new EmptyExpression (atype);
1124
1125                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (ptype);
1126                         if (gc == null)
1127                                 return true;
1128
1129                         //
1130                         // First, check the `class' and `struct' constraints.
1131                         //
1132                         if (gc.HasReferenceTypeConstraint && !atype.IsClass) {
1133                                 Report.Error (452, loc, "The type `{0}' must be " +
1134                                               "a reference type in order to use it " +
1135                                               "as type parameter `{1}' in the " +
1136                                               "generic type or method `{2}'.",
1137                                               atype, ptype, DeclarationName);
1138                                 return false;
1139                         } else if (gc.HasValueTypeConstraint && !atype.IsValueType) {
1140                                 Report.Error (453, loc, "The type `{0}' must be " +
1141                                               "a value type in order to use it " +
1142                                               "as type parameter `{1}' in the " +
1143                                               "generic type or method `{2}'.",
1144                                               atype, ptype, DeclarationName);
1145                                 return false;
1146                         }
1147
1148                         //
1149                         // The class constraint comes next.
1150                         //
1151                         if (gc.HasClassConstraint) {
1152                                 if (!CheckConstraint (ec, ptype, aexpr, gc.ClassConstraint)) {
1153                                         Report.Error (309, loc, "The type `{0}' must be " +
1154                                                       "convertible to `{1}' in order to " +
1155                                                       "use it as parameter `{2}' in the " +
1156                                                       "generic type or method `{3}'",
1157                                                       atype, gc.ClassConstraint, ptype, DeclarationName);
1158                                         return false;
1159                                 }
1160                         }
1161
1162                         //
1163                         // Now, check the interface constraints.
1164                         //
1165                         foreach (Type it in gc.InterfaceConstraints) {
1166                                 Type itype;
1167                                 if (it.IsGenericParameter)
1168                                         itype = atypes [it.GenericParameterPosition];
1169                                 else
1170                                         itype = it;
1171
1172                                 if (!CheckConstraint (ec, ptype, aexpr, itype)) {
1173                                         Report.Error (309, loc, "The type `{0}' must be " +
1174                                                       "convertible to `{1}' in order to " +
1175                                                       "use it as parameter `{2}' in the " +
1176                                                       "generic type or method `{3}'",
1177                                                       atype, itype, ptype, DeclarationName);
1178                                         return false;
1179                                 }
1180                         }
1181
1182                         //
1183                         // Finally, check the constructor constraint.
1184                         //
1185
1186                         if (!gc.HasConstructorConstraint)
1187                                 return true;
1188
1189                         if (TypeManager.IsBuiltinType (atype) || atype.IsValueType)
1190                                 return true;
1191
1192                         MethodGroupExpr mg = Expression.MemberLookup (
1193                                 ec, atype, ".ctor", MemberTypes.Constructor,
1194                                 BindingFlags.Public | BindingFlags.Instance |
1195                                 BindingFlags.DeclaredOnly, loc)
1196                                 as MethodGroupExpr;
1197
1198                         if (atype.IsAbstract || (mg == null) || !mg.IsInstance) {
1199                                 Report.Error (310, loc, "The type `{0}' must have a public " +
1200                                               "parameterless constructor in order to use it " +
1201                                               "as parameter `{1}' in the generic type or " +
1202                                               "method `{2}'", atype, ptype, DeclarationName);
1203                                 return false;
1204                         }
1205
1206                         return true;
1207                 }
1208
1209                 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
1210                 {
1211                         if (!ResolveConstructedType (ec))
1212                                 return null;
1213
1214                         return this;
1215                 }
1216
1217                 public bool CheckConstraints (EmitContext ec)
1218                 {
1219                         for (int i = 0; i < gen_params.Length; i++) {
1220                                 if (!CheckConstraints (ec, i))
1221                                         return false;
1222                         }
1223
1224                         return true;
1225                 }
1226
1227                 public override TypeExpr ResolveAsTypeTerminal (EmitContext ec)
1228                 {
1229                         if (base.ResolveAsTypeTerminal (ec) == null)
1230                                 return null;
1231
1232                         if (!CheckConstraints (ec))
1233                                 return null;
1234
1235                         return this;
1236                 }
1237
1238                 public bool ResolveConstructedType (EmitContext ec)
1239                 {
1240                         if (type != null)
1241                                 return true;
1242                         if (gt != null)
1243                                 return DoResolveType (ec);
1244
1245                         //
1246                         // First, resolve the generic type.
1247                         //
1248                         DeclSpace ds;
1249                         Type nested = ec.DeclSpace.FindNestedType (loc, name, out ds);
1250                         if (nested != null) {
1251                                 gt = nested.GetGenericTypeDefinition ();
1252
1253                                 TypeArguments new_args = new TypeArguments (loc);
1254                                 if (ds.IsGeneric) {
1255                                         foreach (TypeParameter param in ds.TypeParameters)
1256                                                 new_args.Add (new TypeParameterExpr (param, loc));
1257                                 }
1258                                 new_args.Add (args);
1259
1260                                 args = new_args;
1261                                 return DoResolveType (ec);
1262                         }
1263
1264                         Type t;
1265                         int num_args;
1266
1267                         SimpleName sn = new SimpleName (name, loc);
1268                         TypeExpr resolved = sn.ResolveAsTypeTerminal (ec);
1269                         if (resolved == null)
1270                                 return false;
1271
1272                         t = resolved.Type;
1273                         if (t == null) {
1274                                 Report.Error (246, loc, "Cannot find type `{0}'<...>",
1275                                               Basename);
1276                                 return false;
1277                         }
1278
1279                         num_args = TypeManager.GetNumberOfTypeArguments (t);
1280                         if (num_args == 0) {
1281                                 Report.Error (308, loc,
1282                                               "The non-generic type `{0}' cannot " +
1283                                               "be used with type arguments.",
1284                                               TypeManager.CSharpName (t));
1285                                 return false;
1286                         }
1287
1288                         gt = t.GetGenericTypeDefinition ();
1289                         return DoResolveType (ec);
1290                 }
1291
1292                 bool DoResolveType (EmitContext ec)
1293                 {
1294                         //
1295                         // Resolve the arguments.
1296                         //
1297                         if (args.Resolve (ec) == false)
1298                                 return false;
1299
1300                         gen_params = gt.GetGenericArguments ();
1301                         atypes = args.Arguments;
1302
1303                         if (atypes.Length != gen_params.Length) {
1304                                 Report.Error (305, loc,
1305                                               "Using the generic type `{0}' " +
1306                                               "requires {1} type arguments",
1307                                               TypeManager.GetFullName (gt),
1308                                               gen_params.Length);
1309                                 return false;
1310                         }
1311
1312                         //
1313                         // Now bind the parameters.
1314                         //
1315                         type = gt.BindGenericParameters (atypes);
1316                         return true;
1317                 }
1318
1319                 public Expression GetSimpleName (EmitContext ec)
1320                 {
1321                         return new SimpleName (Basename, args, loc);
1322                 }
1323
1324                 public override bool CheckAccessLevel (DeclSpace ds)
1325                 {
1326                         return ds.CheckAccessLevel (gt);
1327                 }
1328
1329                 public override bool AsAccessible (DeclSpace ds, int flags)
1330                 {
1331                         return ds.AsAccessible (gt, flags);
1332                 }
1333
1334                 public override bool IsClass {
1335                         get { return gt.IsClass; }
1336                 }
1337
1338                 public override bool IsValueType {
1339                         get { return gt.IsValueType; }
1340                 }
1341
1342                 public override bool IsInterface {
1343                         get { return gt.IsInterface; }
1344                 }
1345
1346                 public override bool IsSealed {
1347                         get { return gt.IsSealed; }
1348                 }
1349
1350                 public override bool IsAttribute {
1351                         get { return false; }
1352                 }
1353
1354                 public override bool Equals (object obj)
1355                 {
1356                         ConstructedType cobj = obj as ConstructedType;
1357                         if (cobj == null)
1358                                 return false;
1359
1360                         if ((type == null) || (cobj.type == null))
1361                                 return false;
1362
1363                         return type == cobj.type;
1364                 }
1365
1366                 public override int GetHashCode ()
1367                 {
1368                         return base.GetHashCode ();
1369                 }
1370
1371                 public string Basename {
1372                         get {
1373                                 int pos = name.LastIndexOf ('`');
1374                                 if (pos >= 0)
1375                                         return name.Substring (0, pos);
1376                                 else
1377                                         return name;
1378                         }
1379                 }
1380
1381                 public override string Name {
1382                         get {
1383                                 return full_name;
1384                         }
1385                 }
1386
1387
1388                 public override string FullName {
1389                         get {
1390                                 return full_name;
1391                         }
1392                 }
1393         }
1394
1395         public class GenericMethod : DeclSpace
1396         {
1397                 public GenericMethod (NamespaceEntry ns, TypeContainer parent,
1398                                       MemberName name, Location l)
1399                         : base (ns, parent, name, null, l)
1400                 { }
1401
1402                 public override TypeBuilder DefineType ()
1403                 {
1404                         throw new Exception ();
1405                 }
1406
1407                 public override bool Define ()
1408                 {
1409                         for (int i = 0; i < TypeParameters.Length; i++)
1410                                 if (!TypeParameters [i].Resolve (Parent))
1411                                         return false;
1412
1413                         return true;
1414                 }
1415
1416                 public bool Define (MethodBuilder mb, Type return_type)
1417                 {
1418                         if (!Define ())
1419                                 return false;
1420
1421                         GenericTypeParameterBuilder[] gen_params;
1422                         string[] names = MemberName.TypeArguments.GetDeclarations ();
1423                         gen_params = mb.DefineGenericParameters (names);
1424                         for (int i = 0; i < TypeParameters.Length; i++)
1425                                 TypeParameters [i].Define (gen_params [i]);
1426
1427                         ec = new EmitContext (
1428                                 this, this, Location, null, return_type, ModFlags, false);
1429
1430                         return true;
1431                 }
1432
1433                 public bool DefineType (EmitContext ec, MethodBuilder mb,
1434                                         MethodInfo implementing, bool is_override)
1435                 {
1436                         for (int i = 0; i < TypeParameters.Length; i++)
1437                                 if (!TypeParameters [i].DefineType (
1438                                             ec, mb, implementing, is_override))
1439                                         return false;
1440
1441                         return true;
1442                 }
1443
1444                 public override bool DefineMembers (TypeContainer parent)
1445                 {
1446                         return true;
1447                 }
1448
1449                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
1450                                                         MemberFilter filter, object criteria)
1451                 {
1452                         throw new Exception ();
1453                 }               
1454
1455                 public override MemberCache MemberCache {
1456                         get {
1457                                 return null;
1458                         }
1459                 }
1460
1461                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
1462                 {
1463                         // FIXME
1464                 }
1465
1466                 protected override void VerifyObsoleteAttribute()
1467                 {
1468                         // FIXME
1469                 }
1470
1471                 public override AttributeTargets AttributeTargets {
1472                         get {
1473                                 return AttributeTargets.Method | AttributeTargets.ReturnValue;
1474                         }
1475                 }
1476
1477                 public override string DocCommentHeader {
1478                         get { return "M:"; }
1479                 }
1480         }
1481
1482         public class DefaultValueExpression : Expression
1483         {
1484                 Expression expr;
1485                 LocalTemporary temp_storage;
1486
1487                 public DefaultValueExpression (Expression expr, Location loc)
1488                 {
1489                         this.expr = expr;
1490                         this.loc = loc;
1491                 }
1492
1493                 public override Expression DoResolve (EmitContext ec)
1494                 {
1495                         TypeExpr texpr = expr.ResolveAsTypeTerminal (ec);
1496                         if (texpr == null)
1497                                 return null;
1498
1499                         type = texpr.Type;
1500                         if (type.IsGenericParameter || TypeManager.IsValueType (type))
1501                                 temp_storage = new LocalTemporary (ec, type);
1502
1503                         eclass = ExprClass.Variable;
1504                         return this;
1505                 }
1506
1507                 public override void Emit (EmitContext ec)
1508                 {
1509                         if (temp_storage != null) {
1510                                 temp_storage.AddressOf (ec, AddressOp.LoadStore);
1511                                 ec.ig.Emit (OpCodes.Initobj, type);
1512                                 temp_storage.Emit (ec);
1513                         } else
1514                                 ec.ig.Emit (OpCodes.Ldnull);
1515                 }
1516         }
1517
1518         public partial class TypeManager
1519         {
1520                 //
1521                 // A list of core types that the compiler requires or uses
1522                 //
1523                 static public Type new_constraint_attr_type;
1524                 static public Type activator_type;
1525                 static public Type generic_ienumerator_type;
1526                 static public Type generic_ienumerable_type;
1527
1528                 // <remarks>
1529                 //   Tracks the generic parameters.
1530                 // </remarks>
1531                 static PtrHashtable builder_to_type_param;
1532
1533                 //
1534                 // These methods are called by code generated by the compiler
1535                 //
1536                 static public MethodInfo activator_create_instance;
1537
1538                 static void InitGenerics ()
1539                 {
1540                         builder_to_type_param = new PtrHashtable ();
1541                 }
1542
1543                 static void CleanUpGenerics ()
1544                 {
1545                         builder_to_type_param = null;
1546                 }
1547
1548                 static void InitGenericCoreTypes ()
1549                 {
1550                         activator_type = CoreLookupType ("System.Activator");
1551                         new_constraint_attr_type = CoreLookupType (
1552                                 "System.Runtime.CompilerServices.NewConstraintAttribute");
1553
1554                         generic_ienumerator_type = CoreLookupType (
1555                                 MemberName.MakeName ("System.Collections.Generic.IEnumerator", 1));
1556                         generic_ienumerable_type = CoreLookupType (
1557                                 MemberName.MakeName ("System.Collections.Generic.IEnumerable", 1));
1558                 }
1559
1560                 static void InitGenericCodeHelpers ()
1561                 {
1562                         // Activator
1563                         Type [] type_arg = { type_type };
1564                         activator_create_instance = GetMethod (
1565                                 activator_type, "CreateInstance", type_arg);
1566                 }
1567
1568                 public static void AddTypeParameter (Type t, TypeParameter tparam)
1569                 {
1570                         if (!builder_to_type_param.Contains (t))
1571                                 builder_to_type_param.Add (t, tparam);
1572                 }
1573
1574                 public static TypeContainer LookupGenericTypeContainer (Type t)
1575                 {
1576                         while (t.IsGenericInstance)
1577                                 t = t.GetGenericTypeDefinition ();
1578
1579                         return LookupTypeContainer (t);
1580                 }
1581
1582                 public static TypeParameter LookupTypeParameter (Type t)
1583                 {
1584                         return (TypeParameter) builder_to_type_param [t];
1585                 }
1586
1587                 public static bool HasConstructorConstraint (Type t)
1588                 {
1589                         GenericConstraints gc = GetTypeParameterConstraints (t);
1590                         if (gc == null)
1591                                 return false;
1592
1593                         return (gc.Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0;
1594                 }
1595
1596                 public static GenericConstraints GetTypeParameterConstraints (Type t)
1597                 {
1598                         if (!t.IsGenericParameter)
1599                                 throw new InvalidOperationException ();
1600
1601                         TypeParameter tparam = LookupTypeParameter (t);
1602                         if (tparam != null)
1603                                 return tparam.GenericConstraints;
1604
1605                         return new ReflectionConstraints (t);
1606                 }
1607
1608                 public static bool IsGeneric (Type t)
1609                 {
1610                         DeclSpace ds = (DeclSpace) builder_to_declspace [t];
1611
1612                         return ds.IsGeneric;
1613                 }
1614
1615                 public static bool HasGenericArguments (Type t)
1616                 {
1617                         return GetNumberOfTypeArguments (t) > 0;
1618                 }
1619
1620                 public static int GetNumberOfTypeArguments (Type t)
1621                 {
1622                         DeclSpace tc = LookupDeclSpace (t);
1623                         if (tc != null)
1624                                 return tc.IsGeneric ? tc.CountTypeParameters : 0;
1625                         else
1626                                 return t.HasGenericArguments ? t.GetGenericArguments ().Length : 0;
1627                 }
1628
1629                 public static Type[] GetTypeArguments (Type t)
1630                 {
1631                         DeclSpace tc = LookupDeclSpace (t);
1632                         if (tc != null) {
1633                                 if (!tc.IsGeneric)
1634                                         return Type.EmptyTypes;
1635
1636                                 TypeParameter[] tparam = tc.TypeParameters;
1637                                 Type[] ret = new Type [tparam.Length];
1638                                 for (int i = 0; i < tparam.Length; i++) {
1639                                         ret [i] = tparam [i].Type;
1640                                         if (ret [i] == null)
1641                                                 throw new InternalErrorException ();
1642                                 }
1643
1644                                 return ret;
1645                         } else
1646                                 return t.GetGenericArguments ();
1647                 }
1648
1649                 public static bool IsEqual (Type a, Type b)
1650                 {
1651                         if (a.Equals (b))
1652                                 return true;
1653
1654                         if ((a is TypeBuilder) && a.IsGenericTypeDefinition && b.IsGenericInstance) {
1655                                 //
1656                                 // `a' is a generic type definition's TypeBuilder and `b' is a
1657                                 // generic instance of the same type.
1658                                 //
1659                                 // Example:
1660                                 //
1661                                 // class Stack<T>
1662                                 // {
1663                                 //     void Test (Stack<T> stack) { }
1664                                 // }
1665                                 //
1666                                 // The first argument of `Test' will be the generic instance
1667                                 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
1668                                 //
1669                                 //
1670                                 // We hit this via Closure.Filter() for gen-82.cs.
1671                                 //
1672                                 if (a != b.GetGenericTypeDefinition ())
1673                                         return false;
1674
1675                                 Type[] aparams = a.GetGenericArguments ();
1676                                 Type[] bparams = b.GetGenericArguments ();
1677
1678                                 if (aparams.Length != bparams.Length)
1679                                         return false;
1680
1681                                 for (int i = 0; i < aparams.Length; i++)
1682                                         if (!IsEqual (aparams [i], bparams [i]))
1683                                                 return false;
1684
1685                                 return true;
1686                         }
1687
1688                         if (a.IsGenericParameter && b.IsGenericParameter) {
1689                                 if ((a.DeclaringMethod == null) || (b.DeclaringMethod == null))
1690                                         return false;
1691                                 return a.GenericParameterPosition == b.GenericParameterPosition;
1692                         }
1693
1694                         if (a.IsArray && b.IsArray) {
1695                                 if (a.GetArrayRank () != b.GetArrayRank ())
1696                                         return false;
1697                                 return IsEqual (a.GetElementType (), b.GetElementType ());
1698                         }
1699
1700                         if (a.IsGenericInstance && b.IsGenericInstance) {
1701                                 if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1702                                         return false;
1703
1704                                 Type[] aargs = a.GetGenericArguments ();
1705                                 Type[] bargs = b.GetGenericArguments ();
1706
1707                                 if (aargs.Length != bargs.Length)
1708                                         return false;
1709
1710                                 for (int i = 0; i < aargs.Length; i++) {
1711                                         if (!IsEqual (aargs [i], bargs [i]))
1712                                                 return false;
1713                                 }
1714
1715                                 return true;
1716                         }
1717
1718                         return false;
1719                 }
1720
1721                 public static bool MayBecomeEqualGenericTypes (Type a, Type b, Type[] class_infered, Type[] method_infered)
1722                 {
1723                         if (a.IsGenericParameter) {
1724                                 //
1725                                 // If a is an array of a's type, they may never
1726                                 // become equal.
1727                                 //
1728                                 while (b.IsArray) {
1729                                         b = b.GetElementType ();
1730                                         if (a.Equals (b))
1731                                                 return false;
1732                                 }
1733
1734                                 //
1735                                 // If b is a generic parameter or an actual type,
1736                                 // they may become equal:
1737                                 //
1738                                 //    class X<T,U> : I<T>, I<U>
1739                                 //    class X<T> : I<T>, I<float>
1740                                 // 
1741                                 if (b.IsGenericParameter || !b.IsGenericInstance) {
1742                                         int pos = a.GenericParameterPosition;
1743                                         Type[] args = a.DeclaringMethod != null ? method_infered : class_infered;
1744                                         if (args [pos] == null) {
1745                                                 args [pos] = b;
1746                                                 return true;
1747                                         }
1748
1749                                         return args [pos] == a;
1750                                 }
1751
1752                                 //
1753                                 // We're now comparing a type parameter with a
1754                                 // generic instance.  They may become equal unless
1755                                 // the type parameter appears anywhere in the
1756                                 // generic instance:
1757                                 //
1758                                 //    class X<T,U> : I<T>, I<X<U>>
1759                                 //        -> error because you could instanciate it as
1760                                 //           X<X<int>,int>
1761                                 //
1762                                 //    class X<T> : I<T>, I<X<T>> -> ok
1763                                 //
1764
1765                                 Type[] bargs = GetTypeArguments (b);
1766                                 for (int i = 0; i < bargs.Length; i++) {
1767                                         if (a.Equals (bargs [i]))
1768                                                 return false;
1769                                 }
1770
1771                                 return true;
1772                         }
1773
1774                         if (b.IsGenericParameter)
1775                                 return MayBecomeEqualGenericTypes (b, a, class_infered, method_infered);
1776
1777                         //
1778                         // At this point, neither a nor b are a type parameter.
1779                         //
1780                         // If one of them is a generic instance, let
1781                         // MayBecomeEqualGenericInstances() compare them (if the
1782                         // other one is not a generic instance, they can never
1783                         // become equal).
1784                         //
1785
1786                         if (a.IsGenericInstance || b.IsGenericInstance)
1787                                 return MayBecomeEqualGenericInstances (a, b, class_infered, method_infered);
1788
1789                         //
1790                         // If both of them are arrays.
1791                         //
1792
1793                         if (a.IsArray && b.IsArray) {
1794                                 if (a.GetArrayRank () != b.GetArrayRank ())
1795                                         return false;
1796                         
1797                                 a = a.GetElementType ();
1798                                 b = b.GetElementType ();
1799
1800                                 return MayBecomeEqualGenericTypes (a, b, class_infered, method_infered);
1801                         }
1802
1803                         //
1804                         // Ok, two ordinary types.
1805                         //
1806
1807                         return a.Equals (b);
1808                 }
1809
1810                 //
1811                 // Checks whether two generic instances may become equal for some
1812                 // particular instantiation (26.3.1).
1813                 //
1814                 public static bool MayBecomeEqualGenericInstances (Type a, Type b,
1815                                                                    Type[] class_infered, Type[] method_infered)
1816                 {
1817                         if (!a.IsGenericInstance || !b.IsGenericInstance)
1818                                 return false;
1819                         if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1820                                 return false;
1821
1822                         return MayBecomeEqualGenericInstances (
1823                                 GetTypeArguments (a), GetTypeArguments (b), class_infered, method_infered);
1824                 }
1825
1826                 public static bool MayBecomeEqualGenericInstances (Type[] aargs, Type[] bargs,
1827                                                                    Type[] class_infered, Type[] method_infered)
1828                 {
1829                         if (aargs.Length != bargs.Length)
1830                                 return false;
1831
1832                         for (int i = 0; i < aargs.Length; i++) {
1833                                 if (!MayBecomeEqualGenericTypes (aargs [i], bargs [i], class_infered, method_infered))
1834                                         return false;
1835                         }
1836
1837                         return true;
1838                 }
1839
1840                 public static bool IsEqualGenericInstance (Type type, Type parent)
1841                 {
1842                         int tcount = GetNumberOfTypeArguments (type);
1843                         int pcount = GetNumberOfTypeArguments (parent);
1844
1845                         if (type.IsGenericInstance)
1846                                 type = type.GetGenericTypeDefinition ();
1847                         if (parent.IsGenericInstance)
1848                                 parent = parent.GetGenericTypeDefinition ();
1849
1850                         if (tcount != pcount)
1851                                 return false;
1852
1853                         return type.Equals (parent);
1854                 }
1855
1856                 static public bool IsGenericMethod (MethodBase mb)
1857                 {
1858                         if (mb.DeclaringType is TypeBuilder) {
1859                                 IMethodData method = (IMethodData) builder_to_method [mb];
1860                                 if (method == null)
1861                                         return false;
1862
1863                                 return method.GenericMethod != null;
1864                         }
1865
1866                         return mb.IsGenericMethodDefinition;
1867                 }
1868
1869                 //
1870                 // Type inference.
1871                 //
1872
1873                 static bool InferType (Type pt, Type at, Type[] infered)
1874                 {
1875                         if (pt.IsGenericParameter && (pt.DeclaringMethod != null)) {
1876                                 int pos = pt.GenericParameterPosition;
1877
1878                                 if (infered [pos] == null) {
1879                                         Type check = at;
1880                                         while (check.IsArray)
1881                                                 check = check.GetElementType ();
1882
1883                                         if (pt == check)
1884                                                 return false;
1885
1886                                         infered [pos] = at;
1887                                         return true;
1888                                 }
1889
1890                                 if (infered [pos] != at)
1891                                         return false;
1892
1893                                 return true;
1894                         }
1895
1896                         if (!pt.ContainsGenericParameters) {
1897                                 if (at.ContainsGenericParameters)
1898                                         return InferType (at, pt, infered);
1899                                 else
1900                                         return true;
1901                         }
1902
1903                         if (at.IsArray) {
1904                                 if (!pt.IsArray ||
1905                                     (at.GetArrayRank () != pt.GetArrayRank ()))
1906                                         return false;
1907
1908                                 return InferType (pt.GetElementType (), at.GetElementType (), infered);
1909                         }
1910
1911                         if (pt.IsArray) {
1912                                 if (!at.IsArray ||
1913                                     (pt.GetArrayRank () != at.GetArrayRank ()))
1914                                         return false;
1915
1916                                 return InferType (pt.GetElementType (), at.GetElementType (), infered);
1917                         }
1918
1919                         if (pt.IsByRef && at.IsByRef)
1920                                 return InferType (pt.GetElementType (), at.GetElementType (), infered);
1921                         ArrayList list = new ArrayList ();
1922                         if (at.IsGenericInstance)
1923                                 list.Add (at);
1924                         else {
1925                                 for (Type bt = at.BaseType; bt != null; bt = bt.BaseType)
1926                                         list.Add (bt);
1927
1928                                 list.AddRange (TypeManager.GetInterfaces (at));
1929                         }
1930
1931                         bool found_one = false;
1932
1933                         foreach (Type type in list) {
1934                                 if (!type.IsGenericInstance)
1935                                         continue;
1936
1937                                 Type[] infered_types = new Type [infered.Length];
1938
1939                                 if (!InferGenericInstance (pt, type, infered_types))
1940                                         continue;
1941
1942                                 for (int i = 0; i < infered_types.Length; i++) {
1943                                         if (infered [i] == null) {
1944                                                 infered [i] = infered_types [i];
1945                                                 continue;
1946                                         }
1947
1948                                         if (infered [i] != infered_types [i])
1949                                                 return false;
1950                                 }
1951
1952                                 found_one = true;
1953                         }
1954
1955                         return found_one;
1956                 }
1957
1958                 static bool InferGenericInstance (Type pt, Type at, Type[] infered_types)
1959                 {
1960                         Type[] at_args = at.GetGenericArguments ();
1961                         Type[] pt_args = pt.GetGenericArguments ();
1962
1963                         if (at_args.Length != pt_args.Length)
1964                                 return false;
1965
1966                         for (int i = 0; i < at_args.Length; i++) {
1967                                 if (!InferType (pt_args [i], at_args [i], infered_types))
1968                                         return false;
1969                         }
1970
1971                         for (int i = 0; i < infered_types.Length; i++) {
1972                                 if (infered_types [i] == null)
1973                                         return false;
1974                         }
1975
1976                         return true;
1977                 }
1978
1979                 public static bool InferParamsTypeArguments (EmitContext ec, ArrayList arguments,
1980                                                              ref MethodBase method)
1981                 {
1982                         if ((arguments == null) || !TypeManager.IsGenericMethod (method))
1983                                 return true;
1984
1985                         int arg_count;
1986                         
1987                         if (arguments == null)
1988                                 arg_count = 0;
1989                         else
1990                                 arg_count = arguments.Count;
1991                         
1992                         ParameterData pd = Invocation.GetParameterData (method);
1993
1994                         int pd_count = pd.Count;
1995
1996                         if (pd_count == 0)
1997                                 return false;
1998                         
1999                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
2000                                 return false;
2001                         
2002                         if (pd_count - 1 > arg_count)
2003                                 return false;
2004                         
2005                         if (pd_count == 1 && arg_count == 0)
2006                                 return true;
2007
2008                         Type[] method_args = method.GetGenericArguments ();
2009                         Type[] infered_types = new Type [method_args.Length];
2010
2011                         //
2012                         // If we have come this far, the case which
2013                         // remains is when the number of parameters is
2014                         // less than or equal to the argument count.
2015                         //
2016                         for (int i = 0; i < pd_count - 1; ++i) {
2017                                 Argument a = (Argument) arguments [i];
2018
2019                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
2020                                         continue;
2021
2022                                 Type pt = pd.ParameterType (i);
2023                                 Type at = a.Type;
2024
2025                                 if (!InferType (pt, at, infered_types))
2026                                         return false;
2027                         }
2028
2029                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
2030
2031                         for (int i = pd_count - 1; i < arg_count; i++) {
2032                                 Argument a = (Argument) arguments [i];
2033
2034                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
2035                                         continue;
2036
2037                                 if (!InferType (element_type, a.Type, infered_types))
2038                                         return false;
2039                         }
2040
2041                         for (int i = 0; i < infered_types.Length; i++)
2042                                 if (infered_types [i] == null)
2043                                         return false;
2044
2045                         method = method.BindGenericParameters (infered_types);
2046                         return true;
2047                 }
2048
2049                 public static bool InferTypeArguments (Type[] param_types, Type[] arg_types, Type[] infered_types)
2050                 {
2051                         if (infered_types == null)
2052                                 return false;
2053
2054                         for (int i = 0; i < arg_types.Length; i++) {
2055                                 if (arg_types [i] == null)
2056                                         continue;
2057
2058                                 if (!InferType (param_types [i], arg_types [i], infered_types))
2059                                         return false;
2060                         }
2061
2062                         for (int i = 0; i < infered_types.Length; i++)
2063                                 if (infered_types [i] == null)
2064                                         return false;
2065
2066                         return true;
2067                 }
2068
2069                 public static bool InferTypeArguments (EmitContext ec, ArrayList arguments,
2070                                                        ref MethodBase method)
2071                 {
2072                         if (!TypeManager.IsGenericMethod (method))
2073                                 return true;
2074
2075                         int arg_count;
2076                         if (arguments != null)
2077                                 arg_count = arguments.Count;
2078                         else
2079                                 arg_count = 0;
2080
2081                         ParameterData pd = Invocation.GetParameterData (method);
2082                         if (arg_count != pd.Count)
2083                                 return false;
2084
2085                         Type[] method_args = method.GetGenericArguments ();
2086
2087                         bool is_open = false;
2088                         for (int i = 0; i < method_args.Length; i++) {
2089                                 if (method_args [i].IsGenericParameter) {
2090                                         is_open = true;
2091                                         break;
2092                                 }
2093                         }
2094                         if (!is_open)
2095                                 return true;
2096
2097                         Type[] infered_types = new Type [method_args.Length];
2098
2099                         Type[] param_types = new Type [pd.Count];
2100                         Type[] arg_types = new Type [pd.Count];
2101
2102                         for (int i = 0; i < arg_count; i++) {
2103                                 param_types [i] = pd.ParameterType (i);
2104
2105                                 Argument a = (Argument) arguments [i];
2106                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
2107                                         continue;
2108
2109                                 arg_types [i] = a.Type;
2110                         }
2111
2112                         if (!InferTypeArguments (param_types, arg_types, infered_types))
2113                                 return false;
2114
2115                         method = method.BindGenericParameters (infered_types);
2116                         return true;
2117                 }
2118
2119                 public static bool InferTypeArguments (EmitContext ec, ParameterData apd,
2120                                                        ref MethodBase method)
2121                 {
2122                         if (!TypeManager.IsGenericMethod (method))
2123                                 return true;
2124
2125                         ParameterData pd = Invocation.GetParameterData (method);
2126                         if (apd.Count != pd.Count)
2127                                 return false;
2128
2129                         Type[] method_args = method.GetGenericArguments ();
2130                         Type[] infered_types = new Type [method_args.Length];
2131
2132                         Type[] param_types = new Type [pd.Count];
2133                         Type[] arg_types = new Type [pd.Count];
2134
2135                         for (int i = 0; i < apd.Count; i++) {
2136                                 param_types [i] = pd.ParameterType (i);
2137                                 arg_types [i] = apd.ParameterType (i);
2138                         }
2139
2140                         if (!InferTypeArguments (param_types, arg_types, infered_types))
2141                                 return false;
2142
2143                         method = method.BindGenericParameters (infered_types);
2144                         return true;
2145                 }
2146         }
2147 }