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