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