* eliminates the need to run xsltproc on catalog.xml to produce catalog-out.xml
[mono.git] / mcs / gmcs / generic.cs
1 //
2 // generic.cs: Generics support
3 //
4 // Authors: Martin Baulig (martin@ximian.com)
5 //          Miguel de Icaza (miguel@ximian.com)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
10 // (C) 2004 Novell, Inc
11 //
12 using System;
13 using System.Reflection;
14 using System.Reflection.Emit;
15 using System.Globalization;
16 using System.Collections;
17 using System.Text;
18 using System.Text.RegularExpressions;
19         
20 namespace Mono.CSharp {
21
22         public abstract class GenericConstraints {
23                 public abstract GenericParameterAttributes Attributes {
24                         get;
25                 }
26
27                 public bool HasConstructorConstraint {
28                         get { return (Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0; }
29                 }
30
31                 public bool HasReferenceTypeConstraint {
32                         get { return (Attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0; }
33                 }
34
35                 public bool HasValueTypeConstraint {
36                         get { return (Attributes & GenericParameterAttributes.ValueTypeConstraint) != 0; }
37                 }
38
39                 public virtual bool HasClassConstraint {
40                         get { return ClassConstraint != null; }
41                 }
42
43                 public abstract Type ClassConstraint {
44                         get;
45                 }
46
47                 public abstract Type[] InterfaceConstraints {
48                         get;
49                 }
50
51                 public abstract Type EffectiveBaseClass {
52                         get;
53                 }
54
55                 // <summary>
56                 //   Returns whether the type parameter is "known to be a reference type".
57                 // </summary>
58                 public virtual bool IsReferenceType {
59                         get {
60                                 if (HasReferenceTypeConstraint)
61                                         return true;
62                                 if (HasValueTypeConstraint)
63                                         return false;
64
65                                 if (ClassConstraint != null) {
66                                         if (ClassConstraint.IsValueType)
67                                                 return false;
68
69                                         if (ClassConstraint != TypeManager.object_type)
70                                                 return true;
71                                 }
72
73                                 foreach (Type t in InterfaceConstraints) {
74                                         if (!t.IsGenericParameter)
75                                                 continue;
76
77                                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
78                                         if ((gc != null) && gc.IsReferenceType)
79                                                 return true;
80                                 }
81
82                                 return false;
83                         }
84                 }
85
86                 // <summary>
87                 //   Returns whether the type parameter is "known to be a value type".
88                 // </summary>
89                 public virtual bool IsValueType {
90                         get {
91                                 if (HasValueTypeConstraint)
92                                         return true;
93                                 if (HasReferenceTypeConstraint)
94                                         return false;
95
96                                 if (ClassConstraint != null) {
97                                         if (!ClassConstraint.IsValueType)
98                                                 return false;
99
100                                         if (ClassConstraint != TypeManager.value_type)
101                                                 return true;
102                                 }
103
104                                 foreach (Type t in InterfaceConstraints) {
105                                         if (!t.IsGenericParameter)
106                                                 continue;
107
108                                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
109                                         if ((gc != null) && gc.IsValueType)
110                                                 return true;
111                                 }
112
113                                 return false;
114                         }
115                 }
116         }
117
118         public enum SpecialConstraint
119         {
120                 Constructor,
121                 ReferenceType,
122                 ValueType
123         }
124
125         //
126         // Tracks the constraints for a type parameter
127         //
128         public class Constraints : GenericConstraints {
129                 string name;
130                 ArrayList constraints;
131                 Location loc;
132                 
133                 //
134                 // name is the identifier, constraints is an arraylist of
135                 // Expressions (with types) or `true' for the constructor constraint.
136                 // 
137                 public Constraints (string name, ArrayList constraints,
138                                     Location loc)
139                 {
140                         this.name = name;
141                         this.constraints = constraints;
142                         this.loc = loc;
143                 }
144
145                 public string TypeParameter {
146                         get {
147                                 return name;
148                         }
149                 }
150
151                 GenericParameterAttributes attrs;
152                 TypeExpr class_constraint;
153                 ArrayList iface_constraints;
154                 ArrayList type_param_constraints;
155                 int num_constraints;
156                 Type class_constraint_type;
157                 Type[] iface_constraint_types;
158                 Type effective_base_type;
159
160                 public bool Resolve (EmitContext ec)
161                 {
162                         iface_constraints = new ArrayList ();
163                         type_param_constraints = new ArrayList ();
164
165                         foreach (object obj in constraints) {
166                                 if (HasConstructorConstraint) {
167                                         Report.Error (401, loc,
168                                                       "The new() constraint must be last.");
169                                         return false;
170                                 }
171
172                                 if (obj is SpecialConstraint) {
173                                         SpecialConstraint sc = (SpecialConstraint) obj;
174
175                                         if (sc == SpecialConstraint.Constructor) {
176                                                 if (!HasValueTypeConstraint) {
177                                                         attrs |= GenericParameterAttributes.DefaultConstructorConstraint;
178                                                         continue;
179                                                 }
180
181                                                 Report.Error (
182                                                         451, loc, "The new () constraint " +
183                                                         "cannot be used with the `struct' " +
184                                                         "constraint.");
185                                                 return false;
186                                         }
187
188                                         if ((num_constraints > 0) || HasReferenceTypeConstraint || HasValueTypeConstraint) {
189                                                 Report.Error (449, loc,
190                                                               "The `class' or `struct' " +
191                                                               "constraint must be first");
192                                                 return false;
193                                         }
194
195                                         if (sc == SpecialConstraint.ReferenceType)
196                                                 attrs |= GenericParameterAttributes.ReferenceTypeConstraint;
197                                         else
198                                                 attrs |= GenericParameterAttributes.ValueTypeConstraint;
199                                         continue;
200                                 }
201
202                                 FullNamedExpression fn = ((Expression) obj).ResolveAsTypeStep (ec);
203                                 if (fn == null)
204                                         return false;
205
206                                 TypeExpr expr;
207                                 ConstructedType cexpr = fn as ConstructedType;
208                                 if (cexpr != null) {
209                                         if (!cexpr.ResolveConstructedType (ec))
210                                                 return false;
211
212                                         expr = cexpr;
213                                 } else
214                                         expr = fn.ResolveAsTypeTerminal (ec);
215
216                                 if (expr == null)
217                                         return false;
218
219                                 TypeParameterExpr texpr = expr as TypeParameterExpr;
220                                 if (texpr != null)
221                                         type_param_constraints.Add (expr);
222                                 else if (expr.IsInterface)
223                                         iface_constraints.Add (expr);
224                                 else if (class_constraint != null) {
225                                         Report.Error (406, loc,
226                                                       "`{0}': the class constraint for `{1}' " +
227                                                       "must come before any other constraints.",
228                                                       expr.Name, name);
229                                         return false;
230                                 } else if (HasReferenceTypeConstraint || HasValueTypeConstraint) {
231                                         Report.Error (450, loc, "`{0}': cannot specify both " +
232                                                       "a constraint class and the `class' " +
233                                                       "or `struct' constraint.", expr.Name);
234                                         return false;
235                                 } else
236                                         class_constraint = expr;
237
238                                 num_constraints++;
239                         }
240
241                         return true;
242                 }
243
244                 bool CheckTypeParameterConstraints (TypeParameter tparam, Hashtable seen)
245                 {
246                         seen.Add (tparam, true);
247
248                         Constraints constraints = tparam.Constraints;
249                         if (constraints == null)
250                                 return true;
251
252                         if (constraints.HasValueTypeConstraint) {
253                                 Report.Error (456, loc, "Type parameter `{0}' has " +
254                                               "the `struct' constraint, so it cannot " +
255                                               "be used as a constraint for `{1}'",
256                                               tparam.Name, name);
257                                 return false;
258                         }
259
260                         if (constraints.type_param_constraints == null)
261                                 return true;
262
263                         foreach (TypeParameterExpr expr in constraints.type_param_constraints) {
264                                 if (seen.Contains (expr.TypeParameter)) {
265                                         Report.Error (454, loc, "Circular constraint " +
266                                                       "dependency involving `{0}' and `{1}'",
267                                                       tparam.Name, expr.Name);
268                                         return false;
269                                 }
270
271                                 if (!CheckTypeParameterConstraints (expr.TypeParameter, seen))
272                                         return false;
273                         }
274
275                         return true;
276                 }
277
278                 public bool ResolveTypes (EmitContext ec)
279                 {
280                         if (effective_base_type != null)
281                                 return true;
282
283                         foreach (object obj in constraints) {
284                                 ConstructedType cexpr = obj as ConstructedType;
285                                 if (cexpr == null)
286                                         continue;
287
288                                 if (!cexpr.CheckConstraints (ec))
289                                         return false;
290                         }
291
292                         foreach (TypeParameterExpr expr in type_param_constraints) {
293                                 Hashtable seen = new Hashtable ();
294                                 if (!CheckTypeParameterConstraints (expr.TypeParameter, seen))
295                                         return false;
296                         }
297
298                         ArrayList list = new ArrayList ();
299
300                         foreach (TypeExpr iface_constraint in iface_constraints) {
301                                 foreach (Type type in list) {
302                                         if (!type.Equals (iface_constraint.Type))
303                                                 continue;
304
305                                         Report.Error (405, loc,
306                                                       "Duplicate constraint `{0}' for type " +
307                                                       "parameter `{1}'.", iface_constraint.Type,
308                                                       name);
309                                         return false;
310                                 }
311
312                                 TypeExpr te = iface_constraint.ResolveAsTypeTerminal (ec);
313                                 if (te == null)
314                                         return false;
315
316                                 list.Add (te.Type);
317                         }
318
319                         foreach (TypeParameterExpr expr in type_param_constraints) {
320                                 foreach (Type type in list) {
321                                         if (!type.Equals (expr.Type))
322                                                 continue;
323
324                                         Report.Error (405, loc,
325                                                       "Duplicate constraint `{0}' for type " +
326                                                       "parameter `{1}'.", expr.Type, name);
327                                         return false;
328                                 }
329
330                                 list.Add (expr.Type);
331                         }
332
333                         ArrayList new_list = new ArrayList ();
334                         foreach (Type iface in list) {
335                                 if (new_list.Contains (iface))
336                                         continue;
337
338                                 new_list.Add (iface);
339
340                                 Type [] implementing = TypeManager.GetInterfaces (iface);
341                         
342                                 foreach (Type imp in implementing) {
343                                         if (!new_list.Contains (imp))
344                                                 new_list.Add (imp);
345                                 }
346                         }
347
348                         iface_constraint_types = new Type [new_list.Count];
349                         new_list.CopyTo (iface_constraint_types, 0);
350
351                         if (class_constraint != null) {
352                                 TypeExpr te = class_constraint.ResolveAsTypeTerminal (ec);
353                                 if (te == null)
354                                         return false;
355
356                                 class_constraint_type = te.Type;
357                                 if (class_constraint_type == null)
358                                         return false;
359
360                                 if (class_constraint_type.IsSealed) {
361                                         Report.Error (701, loc,
362                                                       "`{0}' is not a valid bound.  Bounds " +
363                                                       "must be interfaces or non sealed " +
364                                                       "classes", class_constraint_type);
365                                         return false;
366                                 }
367
368                                 if ((class_constraint_type == TypeManager.array_type) ||
369                                     (class_constraint_type == TypeManager.delegate_type) ||
370                                     (class_constraint_type == TypeManager.enum_type) ||
371                                     (class_constraint_type == TypeManager.value_type) ||
372                                     (class_constraint_type == TypeManager.object_type)) {
373                                         Report.Error (702, loc,
374                                                       "Bound cannot be special class `{0}'",
375                                                       class_constraint_type);
376                                         return false;
377                                 }
378                         }
379
380                         if (class_constraint_type != null)
381                                 effective_base_type = class_constraint_type;
382                         else if (HasValueTypeConstraint)
383                                 effective_base_type = TypeManager.value_type;
384                         else
385                                 effective_base_type = TypeManager.object_type;
386
387                         return true;
388                 }
389
390                 public bool CheckDependencies (EmitContext ec)
391                 {
392                         foreach (TypeParameterExpr expr in type_param_constraints) {
393                                 if (!CheckDependencies (expr.TypeParameter, ec))
394                                         return false;
395                         }
396
397                         return true;
398                 }
399
400                 bool CheckDependencies (TypeParameter tparam, EmitContext ec)
401                 {
402                         Constraints constraints = tparam.Constraints;
403                         if (constraints == null)
404                                 return true;
405
406                         if (HasValueTypeConstraint && constraints.HasClassConstraint) {
407                                 Report.Error (455, loc, "Type parameter `{0}' inherits " +
408                                               "conflicting constraints `{1}' and `{2}'",
409                                               name, constraints.ClassConstraint,
410                                               "System.ValueType");
411                                 return false;
412                         }
413
414                         if (HasClassConstraint && constraints.HasClassConstraint) {
415                                 Type t1 = ClassConstraint;
416                                 TypeExpr e1 = class_constraint;
417                                 Type t2 = constraints.ClassConstraint;
418                                 TypeExpr e2 = constraints.class_constraint;
419
420                                 if (!Convert.ImplicitReferenceConversionExists (ec, e1, t2) &&
421                                     !Convert.ImplicitReferenceConversionExists (ec, e2, t1)) {
422                                         Report.Error (455, loc,
423                                                       "Type parameter `{0}' inherits " +
424                                                       "conflicting constraints `{1}' and `{2}'",
425                                                       name, t1, t2);
426                                         return false;
427                                 }
428                         }
429
430                         if (constraints.type_param_constraints == null)
431                                 return true;
432
433                         foreach (TypeParameterExpr expr in constraints.type_param_constraints) {
434                                 if (!CheckDependencies (expr.TypeParameter, ec))
435                                         return false;
436                         }
437
438                         return true;
439                 }
440
441                 public void Define (GenericTypeParameterBuilder type)
442                 {
443                         type.SetGenericParameterAttributes (attrs);
444                 }
445
446                 public override GenericParameterAttributes Attributes {
447                         get { return attrs; }
448                 }
449
450                 public override bool HasClassConstraint {
451                         get { return class_constraint != null; }
452                 }
453
454                 public override Type ClassConstraint {
455                         get { return class_constraint_type; }
456                 }
457
458                 public override Type[] InterfaceConstraints {
459                         get { return iface_constraint_types; }
460                 }
461
462                 public override Type EffectiveBaseClass {
463                         get { return effective_base_type; }
464                 }
465
466                 internal bool IsSubclassOf (Type t)
467                 {
468                         if ((class_constraint_type != null) &&
469                             class_constraint_type.IsSubclassOf (t))
470                                 return true;
471
472                         if (iface_constraint_types == null)
473                                 return false;
474
475                         foreach (Type iface in iface_constraint_types) {
476                                 if (TypeManager.IsSubclassOf (iface, t))
477                                         return true;
478                         }
479
480                         return false;
481                 }
482
483                 public bool CheckInterfaceMethod (EmitContext ec, GenericConstraints gc)
484                 {
485                         if (gc.Attributes != attrs)
486                                 return false;
487
488                         if (HasClassConstraint != gc.HasClassConstraint)
489                                 return false;
490                         if (HasClassConstraint && !TypeManager.IsEqual (gc.ClassConstraint, ClassConstraint))
491                                 return false;
492
493                         int gc_icount = gc.InterfaceConstraints != null ?
494                                 gc.InterfaceConstraints.Length : 0;
495                         int icount = InterfaceConstraints != null ?
496                                 InterfaceConstraints.Length : 0;
497
498                         if (gc_icount != icount)
499                                 return false;
500
501                         foreach (Type iface in gc.InterfaceConstraints) {
502                                 bool ok = false;
503                                 foreach (Type check in InterfaceConstraints) {
504                                         if (TypeManager.IsEqual (iface, check)) {
505                                                 ok = true;
506                                                 break;
507                                         }
508                                 }
509
510                                 if (!ok)
511                                         return false;
512                         }
513
514                         return true;
515                 }
516         }
517
518         //
519         // This type represents a generic type parameter
520         //
521         public class TypeParameter : MemberCore, IMemberContainer {
522                 string name;
523                 GenericConstraints gc;
524                 Constraints constraints;
525                 Location loc;
526                 GenericTypeParameterBuilder type;
527
528                 public TypeParameter (TypeContainer parent, string name,
529                                       Constraints constraints, Location loc)
530                         : base (parent, new MemberName (name), null, loc)
531                 {
532                         this.name = name;
533                         this.constraints = constraints;
534                         this.loc = loc;
535                 }
536
537                 public GenericConstraints GenericConstraints {
538                         get {
539                                 return gc != null ? gc : constraints;
540                         }
541                 }
542
543                 public Constraints Constraints {
544                         get {
545                                 return constraints;
546                         }
547                 }
548
549                 public bool HasConstructorConstraint {
550                         get {
551                                 if (constraints != null)
552                                         return constraints.HasConstructorConstraint;
553
554                                 return false;
555                         }
556                 }
557
558                 public Type Type {
559                         get {
560                                 return type;
561                         }
562                 }
563
564                 public bool Resolve (DeclSpace ds)
565                 {
566                         if (constraints != null) {
567                                 if (!constraints.Resolve (ds.EmitContext)) {
568                                         constraints = null;
569                                         return false;
570                                 }
571                         }
572
573                         return true;
574                 }
575
576                 public void Define (GenericTypeParameterBuilder type)
577                 {
578                         if (this.type != null)
579                                 throw new InvalidOperationException ();
580
581                         this.type = type;
582                         TypeManager.AddTypeParameter (type, this);
583                 }
584
585                 public void DefineConstraints ()
586                 {
587                         if (constraints != null)
588                                 constraints.Define (type);
589                 }
590
591                 public bool ResolveType (EmitContext ec)
592                 {
593                         if (constraints != null) {
594                                 if (!constraints.ResolveTypes (ec)) {
595                                         constraints = null;
596                                         return false;
597                                 }
598                         }
599
600                         return true;
601                 }
602
603                 public bool DefineType (EmitContext ec)
604                 {
605                         return DefineType (ec, null, null, false);
606                 }
607
608                 public bool DefineType (EmitContext ec, MethodBuilder builder,
609                                         MethodInfo implementing, bool is_override)
610                 {
611                         if (!ResolveType (ec))
612                                 return false;
613
614                         if (implementing != null) {
615                                 if (is_override && (constraints != null)) {
616                                         Report.Error (
617                                                 460, loc, "Constraints for override and " +
618                                                 "explicit interface implementation methods " +
619                                                 "are inherited from the base method so they " +
620                                                 "cannot be specified directly");
621                                         return false;
622                                 }
623
624                                 MethodBase mb = implementing;
625                                 if (mb.Mono_IsInflatedMethod)
626                                         mb = mb.GetGenericMethodDefinition ();
627
628                                 int pos = type.GenericParameterPosition;
629                                 ParameterData pd = TypeManager.GetParameterData (mb);
630                                 GenericConstraints temp_gc = pd.GenericConstraints (pos);
631                                 Type mparam = mb.GetGenericArguments () [pos];
632
633                                 if (temp_gc != null)
634                                         gc = new InflatedConstraints (temp_gc, implementing.DeclaringType);
635                                 else if (constraints != null)
636                                         gc = new InflatedConstraints (constraints, implementing.DeclaringType);
637
638                                 bool ok = true;
639                                 if (constraints != null) {
640                                         if (temp_gc == null)
641                                                 ok = false;
642                                         else if (!constraints.CheckInterfaceMethod (ec, gc))
643                                                 ok = false;
644                                 } else {
645                                         if (!is_override && (temp_gc != null))
646                                                 ok = false;
647                                 }
648
649                                 if (!ok) {
650                                         Report.SymbolRelatedToPreviousError (implementing);
651
652                                         Report.Error (
653                                                 425, loc, "The constraints for type " +
654                                                 "parameter `{0}' of method `{1}' must match " +
655                                                 "the constraints for type parameter `{2}' " +
656                                                 "of interface method `{3}'.  Consider using " +
657                                                 "an explicit interface implementation instead",
658                                                 Name, TypeManager.CSharpSignature (builder),
659                                                 mparam, TypeManager.CSharpSignature (mb));
660                                         return false;
661                                 }
662                         } else {
663                                 gc = (GenericConstraints) constraints;
664                         }
665
666                         if (gc == null)
667                                 return true;
668
669                         if (gc.HasClassConstraint)
670                                 type.SetBaseTypeConstraint (gc.ClassConstraint);
671
672                         type.SetInterfaceConstraints (gc.InterfaceConstraints);
673                         TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
674
675                         return true;
676                 }
677
678                 public bool CheckDependencies (EmitContext ec)
679                 {
680                         if (constraints != null)
681                                 return constraints.CheckDependencies (ec);
682
683                         return true;
684                 }
685
686                 public bool UpdateConstraints (EmitContext ec, Constraints new_constraints)
687                 {
688                         //
689                         // We're used in partial generic type definitions.
690                         // If `check' is false, we just encountered the first ClassPart which has
691                         // constraints - they become our "real" constraints.
692                         // Otherwise we're called after the type parameters have already been defined
693                         // and check whether the constraints are the same in all parts.
694                         //
695                         if (type == null)
696                                 throw new InvalidOperationException ();
697
698                         if (constraints == null) {
699                                 new_constraints = constraints;
700                                 return true;
701                         } else if (new_constraints == null)
702                                 return true;
703
704                         if (!new_constraints.Resolve (ec))
705                                 return false;
706                         if (!new_constraints.ResolveTypes (ec))
707                                 return false;
708
709                         return constraints.CheckInterfaceMethod (ec, new_constraints);
710                 }
711
712                 public override string DocCommentHeader {
713                         get {
714                                 throw new InvalidOperationException (
715                                         "Unexpected attempt to get doc comment from " + this.GetType () + ".");
716                         }
717                 }
718
719                 //
720                 // MemberContainer
721                 //
722
723                 public override bool Define ()
724                 {
725                         return true;
726                 }
727
728                 protected override void VerifyObsoleteAttribute ()
729                 { }
730
731                 public override void ApplyAttributeBuilder (Attribute a,
732                                                             CustomAttributeBuilder cb)
733                 { }
734
735                 public override AttributeTargets AttributeTargets {
736                         get {
737                                 return (AttributeTargets) 0;
738                         }
739                 }
740
741                 public override string[] ValidAttributeTargets {
742                         get {
743                                 return new string [0];
744                         }
745                 }
746
747                 //
748                 // IMemberContainer
749                 //
750
751                 string IMemberContainer.Name {
752                         get { return Name; }
753                 }
754
755                 MemberCache IMemberContainer.BaseCache {
756                         get { return null; }
757                 }
758
759                 bool IMemberContainer.IsInterface {
760                         get { return true; }
761                 }
762
763                 MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
764                 {
765                         return FindMembers (mt, bf, null, null);
766                 }
767
768                 MemberCache IMemberContainer.MemberCache {
769                         get { return null; }
770                 }
771
772                 public MemberList FindMembers (MemberTypes mt, BindingFlags bf,
773                                                MemberFilter filter, object criteria)
774                 {
775                         if (constraints == null)
776                                 return MemberList.Empty;
777
778                         ArrayList members = new ArrayList ();
779
780                         GenericConstraints gc = (GenericConstraints) constraints;
781
782                         if (gc.HasClassConstraint) {
783                                 MemberList list = TypeManager.FindMembers (
784                                         gc.ClassConstraint, mt, bf, filter, criteria);
785
786                                 members.AddRange (list);
787                         }
788
789                         foreach (Type t in gc.InterfaceConstraints) {
790                                 MemberList list = TypeManager.FindMembers (
791                                         t, mt, bf, filter, criteria);
792
793                                 members.AddRange (list);
794                         }
795
796                         return new MemberList (members);
797                 }
798
799                 public bool IsSubclassOf (Type t)
800                 {
801                         if (type.Equals (t))
802                                 return true;
803
804                         if (constraints != null)
805                                 return constraints.IsSubclassOf (t);
806
807                         return false;
808                 }
809
810                 public override string ToString ()
811                 {
812                         return "TypeParameter[" + name + "]";
813                 }
814
815                 protected class InflatedConstraints : GenericConstraints
816                 {
817                         GenericConstraints gc;
818                         Type base_type;
819                         Type class_constraint;
820                         Type[] iface_constraints;
821                         Type[] dargs;
822
823                         public InflatedConstraints (GenericConstraints gc, Type declaring)
824                         {
825                                 this.gc = gc;
826
827                                 dargs = TypeManager.GetTypeArguments (declaring);
828
829                                 ArrayList list = new ArrayList ();
830                                 if (gc.HasClassConstraint)
831                                         list.Add (inflate (gc.ClassConstraint));
832                                 foreach (Type iface in gc.InterfaceConstraints)
833                                         list.Add (inflate (iface));
834
835                                 bool has_class_constr = false;
836                                 if (list.Count > 0) {
837                                         Type first = (Type) list [0];
838                                         has_class_constr = !first.IsInterface && !first.IsGenericParameter;
839                                 }
840
841                                 if ((list.Count > 0) && has_class_constr) {
842                                         class_constraint = (Type) list [0];
843                                         iface_constraints = new Type [list.Count - 1];
844                                         list.CopyTo (1, iface_constraints, 0, list.Count - 1);
845                                 } else {
846                                         iface_constraints = new Type [list.Count];
847                                         list.CopyTo (iface_constraints, 0);
848                                 }
849
850                                 if (HasValueTypeConstraint)
851                                         base_type = TypeManager.value_type;
852                                 else if (class_constraint != null)
853                                         base_type = class_constraint;
854                                 else
855                                         base_type = TypeManager.object_type;
856                         }
857
858                         Type inflate (Type t)
859                         {
860                                 if (t == null)
861                                         return null;
862                                 if (t.IsGenericParameter)
863                                         return dargs [t.GenericParameterPosition];
864                                 if (t.IsGenericInstance) {
865                                         t = t.GetGenericTypeDefinition ();
866                                         t = t.BindGenericParameters (dargs);
867                                 }
868
869                                 return t;
870                         }
871
872                         public override GenericParameterAttributes Attributes {
873                                 get { return gc.Attributes; }
874                         }
875
876                         public override Type ClassConstraint {
877                                 get { return class_constraint; }
878                         }
879
880                         public override Type EffectiveBaseClass {
881                                 get { return base_type; }
882                         }
883
884                         public override Type[] InterfaceConstraints {
885                                 get { return iface_constraints; }
886                         }
887                 }
888         }
889
890         //
891         // This type represents a generic type parameter reference.
892         //
893         // These expressions are born in a fully resolved state.
894         //
895         public class TypeParameterExpr : TypeExpr {
896                 TypeParameter type_parameter;
897
898                 public override string Name {
899                         get {
900                                 return type_parameter.Name;
901                         }
902                 }
903
904                 public override string FullName {
905                         get {
906                                 return type_parameter.Name;
907                         }
908                 }
909
910                 public TypeParameter TypeParameter {
911                         get {
912                                 return type_parameter;
913                         }
914                 }
915                 
916                 public TypeParameterExpr (TypeParameter type_parameter, Location loc)
917                 {
918                         this.type_parameter = type_parameter;
919                         this.loc = loc;
920                 }
921
922                 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
923                 {
924                         type = type_parameter.Type;
925
926                         return this;
927                 }
928
929                 public override bool IsInterface {
930                         get { return false; }
931                 }
932
933                 public override bool CheckAccessLevel (DeclSpace ds)
934                 {
935                         return true;
936                 }
937
938                 public void Error_CannotUseAsUnmanagedType (Location loc)
939                 {
940                         Report.Error (-203, loc, "Can not use type parameter as unamanged type");
941                 }
942         }
943
944         public class TypeArguments {
945                 public readonly Location Location;
946                 ArrayList args;
947                 Type[] atypes;
948                 int dimension;
949                 bool has_type_args;
950                 bool created;
951                 
952                 public TypeArguments (Location loc)
953                 {
954                         args = new ArrayList ();
955                         this.Location = loc;
956                 }
957
958                 public TypeArguments (int dimension, Location loc)
959                 {
960                         this.dimension = dimension;
961                         this.Location = loc;
962                 }
963
964                 public void Add (Expression type)
965                 {
966                         if (created)
967                                 throw new InvalidOperationException ();
968
969                         args.Add (type);
970                 }
971
972                 public void Add (TypeArguments new_args)
973                 {
974                         if (created)
975                                 throw new InvalidOperationException ();
976
977                         args.AddRange (new_args.args);
978                 }
979
980                 public string[] GetDeclarations ()
981                 {
982                         string[] ret = new string [args.Count];
983                         for (int i = 0; i < args.Count; i++) {
984                                 SimpleName sn = args [i] as SimpleName;
985                                 if (sn != null) {
986                                         ret [i] = sn.Name;
987                                         continue;
988                                 }
989
990                                 Report.Error (81, Location, "Type parameter declaration " +
991                                               "must be an identifier not a type");
992                                 return null;
993                         }
994                         return ret;
995                 }
996
997                 public Type[] Arguments {
998                         get {
999                                 return atypes;
1000                         }
1001                 }
1002
1003                 public bool HasTypeArguments {
1004                         get {
1005                                 return has_type_args;
1006                         }
1007                 }
1008
1009                 public int Count {
1010                         get {
1011                                 if (dimension > 0)
1012                                         return dimension;
1013                                 else
1014                                         return args.Count;
1015                         }
1016                 }
1017
1018                 public bool IsUnbound {
1019                         get {
1020                                 return dimension > 0;
1021                         }
1022                 }
1023
1024                 public override string ToString ()
1025                 {
1026                         StringBuilder s = new StringBuilder ();
1027
1028                         int count = Count;
1029                         for (int i = 0; i < count; i++){
1030                                 //
1031                                 // FIXME: Use TypeManager.CSharpname once we have the type
1032                                 //
1033                                 if (args != null)
1034                                         s.Append (args [i].ToString ());
1035                                 if (i+1 < count)
1036                                         s.Append (",");
1037                         }
1038                         return s.ToString ();
1039                 }
1040
1041                 public bool Resolve (EmitContext ec)
1042                 {
1043                         int count = args.Count;
1044                         bool ok = true;
1045
1046                         atypes = new Type [count];
1047
1048                         for (int i = 0; i < count; i++){
1049                                 TypeExpr te = ((Expression) args [i]).ResolveAsTypeTerminal (ec);
1050                                 if (te == null) {
1051                                         ok = false;
1052                                         continue;
1053                                 }
1054                                 if (te is TypeParameterExpr)
1055                                         has_type_args = true;
1056
1057                                 if (te.Type.IsPointer) {
1058                                         Report.Error (306, Location, "The type `{0}' may not be used " +
1059                                                       "as a type argument.", TypeManager.CSharpName (te.Type));
1060                                         return false;
1061                                 }
1062
1063                                 atypes [i] = te.Type;
1064                         }
1065                         return ok;
1066                 }
1067         }
1068         
1069         public class ConstructedType : TypeExpr {
1070                 string full_name;
1071                 FullNamedExpression name;
1072                 TypeArguments args;
1073                 Type[] gen_params, atypes;
1074                 Type gt;
1075                 
1076                 public ConstructedType (FullNamedExpression fname, TypeArguments args, Location l)
1077                 {
1078                         loc = l;
1079                         this.name = fname;
1080                         this.args = args;
1081
1082                         eclass = ExprClass.Type;
1083                         full_name = name + "<" + args.ToString () + ">";
1084                 }
1085
1086                 protected ConstructedType (TypeArguments args, Location l)
1087                 {
1088                         loc = l;
1089                         this.args = args;
1090
1091                         eclass = ExprClass.Type;
1092                 }
1093
1094                 protected ConstructedType (TypeParameter[] type_params, Location l)
1095                 {
1096                         loc = l;
1097
1098                         args = new TypeArguments (l);
1099                         foreach (TypeParameter type_param in type_params)
1100                                 args.Add (new TypeParameterExpr (type_param, l));
1101
1102                         eclass = ExprClass.Type;
1103                 }
1104
1105                 public ConstructedType (Type t, TypeParameter[] type_params, Location l)
1106                         : this (type_params, l)
1107                 {
1108                         gt = t.GetGenericTypeDefinition ();
1109
1110                         this.name = new TypeExpression (gt, l);
1111                         full_name = gt.FullName + "<" + args.ToString () + ">";
1112                 }
1113
1114                 public ConstructedType (Type t, TypeArguments args, Location l)
1115                         : this (args, l)
1116                 {
1117                         gt = t.GetGenericTypeDefinition ();
1118
1119                         this.name = new TypeExpression (gt, l);
1120                         full_name = gt.FullName + "<" + args.ToString () + ">";
1121                 }
1122
1123                 public TypeArguments TypeArguments {
1124                         get { return args; }
1125                 }
1126
1127                 protected string DeclarationName {
1128                         get {
1129                                 StringBuilder sb = new StringBuilder ();
1130                                 sb.Append (gt.FullName);
1131                                 sb.Append ("<");
1132                                 for (int i = 0; i < gen_params.Length; i++) {
1133                                         if (i > 0)
1134                                                 sb.Append (",");
1135                                         sb.Append (gen_params [i]);
1136                                 }
1137                                 sb.Append (">");
1138                                 return sb.ToString ();
1139                         }
1140                 }
1141
1142                 protected bool CheckConstraint (EmitContext ec, Type ptype, Expression expr,
1143                                                 Type ctype)
1144                 {
1145                         if (TypeManager.HasGenericArguments (ctype)) {
1146                                 Type[] types = TypeManager.GetTypeArguments (ctype);
1147
1148                                 TypeArguments new_args = new TypeArguments (loc);
1149
1150                                 for (int i = 0; i < types.Length; i++) {
1151                                         Type t = types [i];
1152
1153                                         if (t.IsGenericParameter) {
1154                                                 int pos = t.GenericParameterPosition;
1155                                                 t = args.Arguments [pos];
1156                                         }
1157                                         new_args.Add (new TypeExpression (t, loc));
1158                                 }
1159
1160                                 TypeExpr ct = new ConstructedType (ctype, new_args, loc);
1161                                 if (ct.ResolveAsTypeTerminal (ec) == null)
1162                                         return false;
1163                                 ctype = ct.Type;
1164                         }
1165
1166                         return Convert.ImplicitStandardConversionExists (ec, expr, ctype);
1167                 }
1168
1169                 protected bool CheckConstraints (EmitContext ec, int index)
1170                 {
1171                         Type atype = atypes [index];
1172                         Type ptype = gen_params [index];
1173
1174                         if (atype == ptype)
1175                                 return true;
1176
1177                         Expression aexpr = new EmptyExpression (atype);
1178
1179                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (ptype);
1180                         if (gc == null)
1181                                 return true;
1182
1183                         bool is_class, is_struct;
1184                         if (atype.IsGenericParameter) {
1185                                 GenericConstraints agc = TypeManager.GetTypeParameterConstraints (atype);
1186                                 if (agc != null) {
1187                                         is_class = agc.HasReferenceTypeConstraint;
1188                                         is_struct = agc.HasValueTypeConstraint;
1189                                 } else {
1190                                         is_class = is_struct = false;
1191                                 }
1192                         } else {
1193                                 is_class = atype.IsClass;
1194                                 is_struct = atype.IsValueType;
1195                         }
1196
1197                         //
1198                         // First, check the `class' and `struct' constraints.
1199                         //
1200                         if (gc.HasReferenceTypeConstraint && !is_class) {
1201                                 Report.Error (452, loc, "The type `{0}' must be " +
1202                                               "a reference type in order to use it " +
1203                                               "as type parameter `{1}' in the " +
1204                                               "generic type or method `{2}'.",
1205                                               atype, ptype, DeclarationName);
1206                                 return false;
1207                         } else if (gc.HasValueTypeConstraint && !is_struct) {
1208                                 Report.Error (453, loc, "The type `{0}' must be " +
1209                                               "a value type in order to use it " +
1210                                               "as type parameter `{1}' in the " +
1211                                               "generic type or method `{2}'.",
1212                                               atype, ptype, DeclarationName);
1213                                 return false;
1214                         }
1215
1216                         //
1217                         // The class constraint comes next.
1218                         //
1219                         if (gc.HasClassConstraint) {
1220                                 if (!CheckConstraint (ec, ptype, aexpr, gc.ClassConstraint)) {
1221                                         Report.Error (309, loc, "The type `{0}' must be " +
1222                                                       "convertible to `{1}' in order to " +
1223                                                       "use it as parameter `{2}' in the " +
1224                                                       "generic type or method `{3}'",
1225                                                       atype, gc.ClassConstraint, ptype, DeclarationName);
1226                                         return false;
1227                                 }
1228                         }
1229
1230                         //
1231                         // Now, check the interface constraints.
1232                         //
1233                         foreach (Type it in gc.InterfaceConstraints) {
1234                                 Type itype;
1235                                 if (it.IsGenericParameter)
1236                                         itype = atypes [it.GenericParameterPosition];
1237                                 else
1238                                         itype = it;
1239
1240                                 if (!CheckConstraint (ec, ptype, aexpr, itype)) {
1241                                         Report.Error (309, loc, "The type `{0}' must be " +
1242                                                       "convertible to `{1}' in order to " +
1243                                                       "use it as parameter `{2}' in the " +
1244                                                       "generic type or method `{3}'",
1245                                                       atype, itype, ptype, DeclarationName);
1246                                         return false;
1247                                 }
1248                         }
1249
1250                         //
1251                         // Finally, check the constructor constraint.
1252                         //
1253
1254                         if (!gc.HasConstructorConstraint)
1255                                 return true;
1256
1257                         if (TypeManager.IsBuiltinType (atype) || atype.IsValueType)
1258                                 return true;
1259
1260                         MethodGroupExpr mg = Expression.MemberLookup (
1261                                 ec, atype, ".ctor", MemberTypes.Constructor,
1262                                 BindingFlags.Public | BindingFlags.Instance |
1263                                 BindingFlags.DeclaredOnly, loc)
1264                                 as MethodGroupExpr;
1265
1266                         if (atype.IsAbstract || (mg == null) || !mg.IsInstance) {
1267                                 Report.Error (310, loc, "The type `{0}' must have a public " +
1268                                               "parameterless constructor in order to use it " +
1269                                               "as parameter `{1}' in the generic type or " +
1270                                               "method `{2}'", atype, ptype, DeclarationName);
1271                                 return false;
1272                         }
1273
1274                         return true;
1275                 }
1276
1277                 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
1278                 {
1279                         if (!ResolveConstructedType (ec))
1280                                 return null;
1281
1282                         return this;
1283                 }
1284
1285                 public bool CheckConstraints (EmitContext ec)
1286                 {
1287                         for (int i = 0; i < gen_params.Length; i++) {
1288                                 if (!CheckConstraints (ec, i))
1289                                         return false;
1290                         }
1291
1292                         return true;
1293                 }
1294
1295                 public bool ResolveConstructedType (EmitContext ec)
1296                 {
1297                         if (type != null)
1298                                 return true;
1299                         if (gt != null)
1300                                 return DoResolveType (ec);
1301
1302                         int num_args;
1303                         Type t = name.Type;
1304
1305                         if (t == null) {
1306                                 Report.Error (246, loc, "Cannot find type `{0}'<...>", Name);
1307                                 return false;
1308                         }
1309
1310                         num_args = TypeManager.GetNumberOfTypeArguments (t);
1311                         if (num_args == 0) {
1312                                 Report.Error (308, loc,
1313                                               "The non-generic type `{0}' cannot " +
1314                                               "be used with type arguments.",
1315                                               TypeManager.CSharpName (t));
1316                                 return false;
1317                         }
1318
1319                         gt = t.GetGenericTypeDefinition ();
1320                         return DoResolveType (ec);
1321                 }
1322
1323                 bool DoResolveType (EmitContext ec)
1324                 {
1325                         //
1326                         // Resolve the arguments.
1327                         //
1328                         if (args.Resolve (ec) == false)
1329                                 return false;
1330
1331                         gen_params = gt.GetGenericArguments ();
1332                         atypes = args.Arguments;
1333
1334                         if (atypes.Length != gen_params.Length) {
1335                                 Report.Error (305, loc,
1336                                               "Using the generic type `{0}' " +
1337                                               "requires {1} type arguments",
1338                                               TypeManager.GetFullName (gt),
1339                                               gen_params.Length);
1340                                 return false;
1341                         }
1342
1343                         //
1344                         // Now bind the parameters.
1345                         //
1346                         type = gt.BindGenericParameters (atypes);
1347                         return true;
1348                 }
1349
1350                 public Expression GetSimpleName (EmitContext ec)
1351                 {
1352                         return this;
1353                 }
1354
1355                 public override bool CheckAccessLevel (DeclSpace ds)
1356                 {
1357                         return ds.CheckAccessLevel (gt);
1358                 }
1359
1360                 public override bool AsAccessible (DeclSpace ds, int flags)
1361                 {
1362                         return ds.AsAccessible (gt, flags);
1363                 }
1364
1365                 public override bool IsClass {
1366                         get { return gt.IsClass; }
1367                 }
1368
1369                 public override bool IsValueType {
1370                         get { return gt.IsValueType; }
1371                 }
1372
1373                 public override bool IsInterface {
1374                         get { return gt.IsInterface; }
1375                 }
1376
1377                 public override bool IsSealed {
1378                         get { return gt.IsSealed; }
1379                 }
1380
1381                 public override bool Equals (object obj)
1382                 {
1383                         ConstructedType cobj = obj as ConstructedType;
1384                         if (cobj == null)
1385                                 return false;
1386
1387                         if ((type == null) || (cobj.type == null))
1388                                 return false;
1389
1390                         return type == cobj.type;
1391                 }
1392
1393                 public override int GetHashCode ()
1394                 {
1395                         return base.GetHashCode ();
1396                 }
1397
1398                 public override string Name {
1399                         get {
1400                                 return full_name;
1401                         }
1402                 }
1403
1404
1405                 public override string FullName {
1406                         get {
1407                                 return full_name;
1408                         }
1409                 }
1410         }
1411
1412         public class GenericMethod : DeclSpace
1413         {
1414                 public GenericMethod (NamespaceEntry ns, TypeContainer parent,
1415                                       MemberName name, Location l)
1416                         : base (ns, parent, name, null, l)
1417                 { }
1418
1419                 public override TypeBuilder DefineType ()
1420                 {
1421                         throw new Exception ();
1422                 }
1423
1424                 public override bool Define ()
1425                 {
1426                         ec = new EmitContext (this, this, Location, null, null, ModFlags, false);
1427
1428                         for (int i = 0; i < TypeParameters.Length; i++)
1429                                 if (!TypeParameters [i].Resolve (this))
1430                                         return false;
1431
1432                         return true;
1433                 }
1434
1435                 public bool Define (MethodBuilder mb)
1436                 {
1437                         GenericTypeParameterBuilder[] gen_params;
1438                         string[] names = MemberName.TypeArguments.GetDeclarations ();
1439                         gen_params = mb.DefineGenericParameters (names);
1440                         for (int i = 0; i < TypeParameters.Length; i++)
1441                                 TypeParameters [i].Define (gen_params [i]);
1442
1443                         if (!Define ())
1444                                 return false;
1445
1446                         for (int i = 0; i < TypeParameters.Length; i++) {
1447                                 if (!TypeParameters [i].ResolveType (ec))
1448                                         return false;
1449                         }
1450
1451                         return true;
1452                 }
1453
1454                 public bool DefineType (EmitContext ec, MethodBuilder mb,
1455                                         MethodInfo implementing, bool is_override)
1456                 {
1457                         for (int i = 0; i < TypeParameters.Length; i++)
1458                                 if (!TypeParameters [i].DefineType (
1459                                             ec, mb, implementing, is_override))
1460                                         return false;
1461
1462                         return true;
1463                 }
1464
1465                 public override bool DefineMembers (TypeContainer parent)
1466                 {
1467                         return true;
1468                 }
1469
1470                 public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
1471                                                         MemberFilter filter, object criteria)
1472                 {
1473                         throw new Exception ();
1474                 }               
1475
1476                 public override MemberCache MemberCache {
1477                         get {
1478                                 return null;
1479                         }
1480                 }
1481
1482                 public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb)
1483                 {
1484                         // FIXME
1485                 }
1486
1487                 protected override void VerifyObsoleteAttribute()
1488                 {
1489                         // FIXME
1490                 }
1491
1492                 public override AttributeTargets AttributeTargets {
1493                         get {
1494                                 return AttributeTargets.Method | AttributeTargets.ReturnValue;
1495                         }
1496                 }
1497
1498                 public override string DocCommentHeader {
1499                         get { return "M:"; }
1500                 }
1501         }
1502
1503         public class DefaultValueExpression : Expression
1504         {
1505                 Expression expr;
1506                 LocalTemporary temp_storage;
1507
1508                 public DefaultValueExpression (Expression expr, Location loc)
1509                 {
1510                         this.expr = expr;
1511                         this.loc = loc;
1512                 }
1513
1514                 public override Expression DoResolve (EmitContext ec)
1515                 {
1516                         TypeExpr texpr = expr.ResolveAsTypeTerminal (ec);
1517                         if (texpr == null)
1518                                 return null;
1519
1520                         type = texpr.Type;
1521                         if (type.IsGenericParameter || TypeManager.IsValueType (type))
1522                                 temp_storage = new LocalTemporary (ec, type);
1523
1524                         eclass = ExprClass.Variable;
1525                         return this;
1526                 }
1527
1528                 public override void Emit (EmitContext ec)
1529                 {
1530                         if (temp_storage != null) {
1531                                 temp_storage.AddressOf (ec, AddressOp.LoadStore);
1532                                 ec.ig.Emit (OpCodes.Initobj, type);
1533                                 temp_storage.Emit (ec);
1534                         } else
1535                                 ec.ig.Emit (OpCodes.Ldnull);
1536                 }
1537         }
1538
1539         public class NullableType : TypeExpr
1540         {
1541                 Expression underlying;
1542
1543                 public NullableType (Expression underlying, Location l)
1544                 {
1545                         this.underlying = underlying;
1546                         loc = l;
1547
1548                         eclass = ExprClass.Type;
1549                 }
1550
1551                 public NullableType (Type type, Location loc)
1552                         : this (new TypeExpression (type, loc), loc)
1553                 { }
1554
1555                 public override string Name {
1556                         get { return underlying.ToString () + "?"; }
1557                 }
1558
1559                 public override string FullName {
1560                         get { return underlying.ToString () + "?"; }
1561                 }
1562
1563                 protected override TypeExpr DoResolveAsTypeStep (EmitContext ec)
1564                 {
1565                         TypeArguments args = new TypeArguments (loc);
1566                         args.Add (underlying);
1567
1568                         ConstructedType ctype = new ConstructedType (TypeManager.generic_nullable_type, args, loc);
1569                         return ctype.ResolveAsTypeTerminal (ec);
1570                 }
1571         }
1572
1573         public partial class TypeManager
1574         {
1575                 //
1576                 // A list of core types that the compiler requires or uses
1577                 //
1578                 static public Type new_constraint_attr_type;
1579                 static public Type activator_type;
1580                 static public Type generic_ienumerator_type;
1581                 static public Type generic_ienumerable_type;
1582                 static public Type generic_nullable_type;
1583
1584                 // <remarks>
1585                 //   Tracks the generic parameters.
1586                 // </remarks>
1587                 static PtrHashtable builder_to_type_param;
1588
1589                 //
1590                 // These methods are called by code generated by the compiler
1591                 //
1592                 static public MethodInfo activator_create_instance;
1593
1594                 static void InitGenerics ()
1595                 {
1596                         builder_to_type_param = new PtrHashtable ();
1597                 }
1598
1599                 static void CleanUpGenerics ()
1600                 {
1601                         builder_to_type_param = null;
1602                 }
1603
1604                 static void InitGenericCoreTypes ()
1605                 {
1606                         activator_type = CoreLookupType ("System.Activator");
1607                         new_constraint_attr_type = CoreLookupType (
1608                                 "System.Runtime.CompilerServices.NewConstraintAttribute");
1609
1610                         generic_ienumerator_type = CoreLookupType ("System.Collections.Generic.IEnumerator", 1);
1611                         generic_ienumerable_type = CoreLookupType ("System.Collections.Generic.IEnumerable", 1);
1612                         generic_nullable_type = CoreLookupType ("System.Nullable", 1);
1613                 }
1614
1615                 static void InitGenericCodeHelpers ()
1616                 {
1617                         // Activator
1618                         Type [] type_arg = { type_type };
1619                         activator_create_instance = GetMethod (
1620                                 activator_type, "CreateInstance", type_arg);
1621                 }
1622
1623                 static Type CoreLookupType (string name, int arity)
1624                 {
1625                         return CoreLookupType (MemberName.MakeName (name, arity));
1626                 }
1627
1628                 public static void AddTypeParameter (Type t, TypeParameter tparam)
1629                 {
1630                         if (!builder_to_type_param.Contains (t))
1631                                 builder_to_type_param.Add (t, tparam);
1632                 }
1633
1634                 public static TypeContainer LookupGenericTypeContainer (Type t)
1635                 {
1636                         while (t.IsGenericInstance)
1637                                 t = t.GetGenericTypeDefinition ();
1638
1639                         return LookupTypeContainer (t);
1640                 }
1641
1642                 public static TypeParameter LookupTypeParameter (Type t)
1643                 {
1644                         return (TypeParameter) builder_to_type_param [t];
1645                 }
1646
1647                 public static GenericConstraints GetTypeParameterConstraints (Type t)
1648                 {
1649                         if (!t.IsGenericParameter)
1650                                 throw new InvalidOperationException ();
1651
1652                         TypeParameter tparam = LookupTypeParameter (t);
1653                         if (tparam != null)
1654                                 return tparam.GenericConstraints;
1655
1656                         return new ReflectionConstraints (t);
1657                 }
1658
1659                 public static bool IsGeneric (Type t)
1660                 {
1661                         DeclSpace ds = (DeclSpace) builder_to_declspace [t];
1662
1663                         return ds.IsGeneric;
1664                 }
1665
1666                 public static bool HasGenericArguments (Type t)
1667                 {
1668                         return GetNumberOfTypeArguments (t) > 0;
1669                 }
1670
1671                 public static int GetNumberOfTypeArguments (Type t)
1672                 {
1673                         DeclSpace tc = LookupDeclSpace (t);
1674                         if (tc != null)
1675                                 return tc.IsGeneric ? tc.CountTypeParameters : 0;
1676                         else
1677                                 return t.HasGenericArguments ? t.GetGenericArguments ().Length : 0;
1678                 }
1679
1680                 public static Type[] GetTypeArguments (Type t)
1681                 {
1682                         DeclSpace tc = LookupDeclSpace (t);
1683                         if (tc != null) {
1684                                 if (!tc.IsGeneric)
1685                                         return Type.EmptyTypes;
1686
1687                                 TypeParameter[] tparam = tc.TypeParameters;
1688                                 Type[] ret = new Type [tparam.Length];
1689                                 for (int i = 0; i < tparam.Length; i++) {
1690                                         ret [i] = tparam [i].Type;
1691                                         if (ret [i] == null)
1692                                                 throw new InternalErrorException ();
1693                                 }
1694
1695                                 return ret;
1696                         } else
1697                                 return t.GetGenericArguments ();
1698                 }
1699
1700                 //
1701                 // Whether `array' is an array of T and `enumerator' is `IEnumerable<T>'.
1702                 // For instance "string[]" -> "IEnumerable<string>".
1703                 //
1704                 public static bool IsIEnumerable (Type array, Type enumerator)
1705                 {
1706                         if (!array.IsArray || !enumerator.IsGenericInstance)
1707                                 return false;
1708
1709                         if (enumerator.GetGenericTypeDefinition () != generic_ienumerable_type)
1710                                 return false;
1711
1712                         Type[] args = GetTypeArguments (enumerator);
1713                         return args [0] == GetElementType (array);
1714                 }
1715
1716                 public static bool IsEqual (Type a, Type b)
1717                 {
1718                         if (a.Equals (b))
1719                                 return true;
1720
1721                         if ((a is TypeBuilder) && a.IsGenericTypeDefinition && b.IsGenericInstance) {
1722                                 //
1723                                 // `a' is a generic type definition's TypeBuilder and `b' is a
1724                                 // generic instance of the same type.
1725                                 //
1726                                 // Example:
1727                                 //
1728                                 // class Stack<T>
1729                                 // {
1730                                 //     void Test (Stack<T> stack) { }
1731                                 // }
1732                                 //
1733                                 // The first argument of `Test' will be the generic instance
1734                                 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
1735                                 //
1736                                 //
1737                                 // We hit this via Closure.Filter() for gen-82.cs.
1738                                 //
1739                                 if (a != b.GetGenericTypeDefinition ())
1740                                         return false;
1741
1742                                 Type[] aparams = a.GetGenericArguments ();
1743                                 Type[] bparams = b.GetGenericArguments ();
1744
1745                                 if (aparams.Length != bparams.Length)
1746                                         return false;
1747
1748                                 for (int i = 0; i < aparams.Length; i++)
1749                                         if (!IsEqual (aparams [i], bparams [i]))
1750                                                 return false;
1751
1752                                 return true;
1753                         }
1754
1755                         if ((b is TypeBuilder) && b.IsGenericTypeDefinition && a.IsGenericInstance)
1756                                 return IsEqual (b, a);
1757
1758                         if (a.IsGenericParameter && b.IsGenericParameter) {
1759                                 if ((a.DeclaringMethod == null) || (b.DeclaringMethod == null))
1760                                         return false;
1761                                 return a.GenericParameterPosition == b.GenericParameterPosition;
1762                         }
1763
1764                         if (a.IsArray && b.IsArray) {
1765                                 if (a.GetArrayRank () != b.GetArrayRank ())
1766                                         return false;
1767                                 return IsEqual (a.GetElementType (), b.GetElementType ());
1768                         }
1769
1770                         if (a.IsGenericInstance && b.IsGenericInstance) {
1771                                 if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1772                                         return false;
1773
1774                                 Type[] aargs = a.GetGenericArguments ();
1775                                 Type[] bargs = b.GetGenericArguments ();
1776
1777                                 if (aargs.Length != bargs.Length)
1778                                         return false;
1779
1780                                 for (int i = 0; i < aargs.Length; i++) {
1781                                         if (!IsEqual (aargs [i], bargs [i]))
1782                                                 return false;
1783                                 }
1784
1785                                 return true;
1786                         }
1787
1788                         return false;
1789                 }
1790
1791                 public static bool MayBecomeEqualGenericTypes (Type a, Type b, Type[] class_infered, Type[] method_infered)
1792                 {
1793                         if (a.IsGenericParameter) {
1794                                 //
1795                                 // If a is an array of a's type, they may never
1796                                 // become equal.
1797                                 //
1798                                 while (b.IsArray) {
1799                                         b = b.GetElementType ();
1800                                         if (a.Equals (b))
1801                                                 return false;
1802                                 }
1803
1804                                 //
1805                                 // If b is a generic parameter or an actual type,
1806                                 // they may become equal:
1807                                 //
1808                                 //    class X<T,U> : I<T>, I<U>
1809                                 //    class X<T> : I<T>, I<float>
1810                                 // 
1811                                 if (b.IsGenericParameter || !b.IsGenericInstance) {
1812                                         int pos = a.GenericParameterPosition;
1813                                         Type[] args = a.DeclaringMethod != null ? method_infered : class_infered;
1814                                         if (args [pos] == null) {
1815                                                 args [pos] = b;
1816                                                 return true;
1817                                         }
1818
1819                                         return args [pos] == a;
1820                                 }
1821
1822                                 //
1823                                 // We're now comparing a type parameter with a
1824                                 // generic instance.  They may become equal unless
1825                                 // the type parameter appears anywhere in the
1826                                 // generic instance:
1827                                 //
1828                                 //    class X<T,U> : I<T>, I<X<U>>
1829                                 //        -> error because you could instanciate it as
1830                                 //           X<X<int>,int>
1831                                 //
1832                                 //    class X<T> : I<T>, I<X<T>> -> ok
1833                                 //
1834
1835                                 Type[] bargs = GetTypeArguments (b);
1836                                 for (int i = 0; i < bargs.Length; i++) {
1837                                         if (a.Equals (bargs [i]))
1838                                                 return false;
1839                                 }
1840
1841                                 return true;
1842                         }
1843
1844                         if (b.IsGenericParameter)
1845                                 return MayBecomeEqualGenericTypes (b, a, class_infered, method_infered);
1846
1847                         //
1848                         // At this point, neither a nor b are a type parameter.
1849                         //
1850                         // If one of them is a generic instance, let
1851                         // MayBecomeEqualGenericInstances() compare them (if the
1852                         // other one is not a generic instance, they can never
1853                         // become equal).
1854                         //
1855
1856                         if (a.IsGenericInstance || b.IsGenericInstance)
1857                                 return MayBecomeEqualGenericInstances (a, b, class_infered, method_infered);
1858
1859                         //
1860                         // If both of them are arrays.
1861                         //
1862
1863                         if (a.IsArray && b.IsArray) {
1864                                 if (a.GetArrayRank () != b.GetArrayRank ())
1865                                         return false;
1866                         
1867                                 a = a.GetElementType ();
1868                                 b = b.GetElementType ();
1869
1870                                 return MayBecomeEqualGenericTypes (a, b, class_infered, method_infered);
1871                         }
1872
1873                         //
1874                         // Ok, two ordinary types.
1875                         //
1876
1877                         return a.Equals (b);
1878                 }
1879
1880                 //
1881                 // Checks whether two generic instances may become equal for some
1882                 // particular instantiation (26.3.1).
1883                 //
1884                 public static bool MayBecomeEqualGenericInstances (Type a, Type b,
1885                                                                    Type[] class_infered, Type[] method_infered)
1886                 {
1887                         if (!a.IsGenericInstance || !b.IsGenericInstance)
1888                                 return false;
1889                         if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1890                                 return false;
1891
1892                         return MayBecomeEqualGenericInstances (
1893                                 GetTypeArguments (a), GetTypeArguments (b), class_infered, method_infered);
1894                 }
1895
1896                 public static bool MayBecomeEqualGenericInstances (Type[] aargs, Type[] bargs,
1897                                                                    Type[] class_infered, Type[] method_infered)
1898                 {
1899                         if (aargs.Length != bargs.Length)
1900                                 return false;
1901
1902                         for (int i = 0; i < aargs.Length; i++) {
1903                                 if (!MayBecomeEqualGenericTypes (aargs [i], bargs [i], class_infered, method_infered))
1904                                         return false;
1905                         }
1906
1907                         return true;
1908                 }
1909
1910                 public static bool IsEqualGenericInstance (Type type, Type parent)
1911                 {
1912                         int tcount = GetNumberOfTypeArguments (type);
1913                         int pcount = GetNumberOfTypeArguments (parent);
1914
1915                         if (type.IsGenericInstance)
1916                                 type = type.GetGenericTypeDefinition ();
1917                         if (parent.IsGenericInstance)
1918                                 parent = parent.GetGenericTypeDefinition ();
1919
1920                         if (tcount != pcount)
1921                                 return false;
1922
1923                         return type.Equals (parent);
1924                 }
1925
1926                 static public bool IsGenericMethod (MethodBase mb)
1927                 {
1928                         if (mb.DeclaringType is TypeBuilder) {
1929                                 IMethodData method = (IMethodData) builder_to_method [mb];
1930                                 if (method == null)
1931                                         return false;
1932
1933                                 return method.GenericMethod != null;
1934                         }
1935
1936                         return mb.IsGenericMethodDefinition;
1937                 }
1938
1939                 //
1940                 // Type inference.
1941                 //
1942
1943                 static bool InferType (Type pt, Type at, Type[] infered)
1944                 {
1945                         if (pt.IsGenericParameter && (pt.DeclaringMethod != null)) {
1946                                 int pos = pt.GenericParameterPosition;
1947
1948                                 if (infered [pos] == null) {
1949                                         Type check = at;
1950                                         while (check.IsArray)
1951                                                 check = check.GetElementType ();
1952
1953                                         if (pt == check)
1954                                                 return false;
1955
1956                                         infered [pos] = at;
1957                                         return true;
1958                                 }
1959
1960                                 if (infered [pos] != at)
1961                                         return false;
1962
1963                                 return true;
1964                         }
1965
1966                         if (!pt.ContainsGenericParameters) {
1967                                 if (at.ContainsGenericParameters)
1968                                         return InferType (at, pt, infered);
1969                                 else
1970                                         return true;
1971                         }
1972
1973                         if (at.IsArray) {
1974                                 if (!pt.IsArray ||
1975                                     (at.GetArrayRank () != pt.GetArrayRank ()))
1976                                         return false;
1977
1978                                 return InferType (pt.GetElementType (), at.GetElementType (), infered);
1979                         }
1980
1981                         if (pt.IsArray) {
1982                                 if (!at.IsArray ||
1983                                     (pt.GetArrayRank () != at.GetArrayRank ()))
1984                                         return false;
1985
1986                                 return InferType (pt.GetElementType (), at.GetElementType (), infered);
1987                         }
1988
1989                         if (pt.IsByRef && at.IsByRef)
1990                                 return InferType (pt.GetElementType (), at.GetElementType (), infered);
1991                         ArrayList list = new ArrayList ();
1992                         if (at.IsGenericInstance)
1993                                 list.Add (at);
1994                         else {
1995                                 for (Type bt = at.BaseType; bt != null; bt = bt.BaseType)
1996                                         list.Add (bt);
1997
1998                                 list.AddRange (TypeManager.GetInterfaces (at));
1999                         }
2000
2001                         bool found_one = false;
2002
2003                         foreach (Type type in list) {
2004                                 if (!type.IsGenericInstance)
2005                                         continue;
2006
2007                                 Type[] infered_types = new Type [infered.Length];
2008
2009                                 if (!InferGenericInstance (pt, type, infered_types))
2010                                         continue;
2011
2012                                 for (int i = 0; i < infered_types.Length; i++) {
2013                                         if (infered [i] == null) {
2014                                                 infered [i] = infered_types [i];
2015                                                 continue;
2016                                         }
2017
2018                                         if (infered [i] != infered_types [i])
2019                                                 return false;
2020                                 }
2021
2022                                 found_one = true;
2023                         }
2024
2025                         return found_one;
2026                 }
2027
2028                 static bool InferGenericInstance (Type pt, Type at, Type[] infered_types)
2029                 {
2030                         Type[] at_args = at.GetGenericArguments ();
2031                         Type[] pt_args = pt.GetGenericArguments ();
2032
2033                         if (at_args.Length != pt_args.Length)
2034                                 return false;
2035
2036                         for (int i = 0; i < at_args.Length; i++) {
2037                                 if (!InferType (pt_args [i], at_args [i], infered_types))
2038                                         return false;
2039                         }
2040
2041                         for (int i = 0; i < infered_types.Length; i++) {
2042                                 if (infered_types [i] == null)
2043                                         return false;
2044                         }
2045
2046                         return true;
2047                 }
2048
2049                 public static bool InferParamsTypeArguments (EmitContext ec, ArrayList arguments,
2050                                                              ref MethodBase method)
2051                 {
2052                         if ((arguments == null) || !TypeManager.IsGenericMethod (method))
2053                                 return true;
2054
2055                         int arg_count;
2056                         
2057                         if (arguments == null)
2058                                 arg_count = 0;
2059                         else
2060                                 arg_count = arguments.Count;
2061                         
2062                         ParameterData pd = TypeManager.GetParameterData (method);
2063
2064                         int pd_count = pd.Count;
2065
2066                         if (pd_count == 0)
2067                                 return false;
2068                         
2069                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
2070                                 return false;
2071                         
2072                         if (pd_count - 1 > arg_count)
2073                                 return false;
2074                         
2075                         if (pd_count == 1 && arg_count == 0)
2076                                 return true;
2077
2078                         Type[] method_args = method.GetGenericArguments ();
2079                         Type[] infered_types = new Type [method_args.Length];
2080
2081                         //
2082                         // If we have come this far, the case which
2083                         // remains is when the number of parameters is
2084                         // less than or equal to the argument count.
2085                         //
2086                         for (int i = 0; i < pd_count - 1; ++i) {
2087                                 Argument a = (Argument) arguments [i];
2088
2089                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
2090                                         continue;
2091
2092                                 Type pt = pd.ParameterType (i);
2093                                 Type at = a.Type;
2094
2095                                 if (!InferType (pt, at, infered_types))
2096                                         return false;
2097                         }
2098
2099                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
2100
2101                         for (int i = pd_count - 1; i < arg_count; i++) {
2102                                 Argument a = (Argument) arguments [i];
2103
2104                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
2105                                         continue;
2106
2107                                 if (!InferType (element_type, a.Type, infered_types))
2108                                         return false;
2109                         }
2110
2111                         for (int i = 0; i < infered_types.Length; i++)
2112                                 if (infered_types [i] == null)
2113                                         return false;
2114
2115                         method = method.BindGenericParameters (infered_types);
2116                         return true;
2117                 }
2118
2119                 public static bool InferTypeArguments (Type[] param_types, Type[] arg_types, Type[] infered_types)
2120                 {
2121                         if (infered_types == null)
2122                                 return false;
2123
2124                         for (int i = 0; i < arg_types.Length; i++) {
2125                                 if (arg_types [i] == null)
2126                                         continue;
2127
2128                                 if (!InferType (param_types [i], arg_types [i], infered_types))
2129                                         return false;
2130                         }
2131
2132                         for (int i = 0; i < infered_types.Length; i++)
2133                                 if (infered_types [i] == null)
2134                                         return false;
2135
2136                         return true;
2137                 }
2138
2139                 public static bool InferTypeArguments (EmitContext ec, ArrayList arguments,
2140                                                        ref MethodBase method)
2141                 {
2142                         if (!TypeManager.IsGenericMethod (method))
2143                                 return true;
2144
2145                         int arg_count;
2146                         if (arguments != null)
2147                                 arg_count = arguments.Count;
2148                         else
2149                                 arg_count = 0;
2150
2151                         ParameterData pd = TypeManager.GetParameterData (method);
2152                         if (arg_count != pd.Count)
2153                                 return false;
2154
2155                         Type[] method_args = method.GetGenericArguments ();
2156
2157                         bool is_open = false;
2158                         for (int i = 0; i < method_args.Length; i++) {
2159                                 if (method_args [i].IsGenericParameter) {
2160                                         is_open = true;
2161                                         break;
2162                                 }
2163                         }
2164                         if (!is_open)
2165                                 return true;
2166
2167                         Type[] infered_types = new Type [method_args.Length];
2168
2169                         Type[] param_types = new Type [pd.Count];
2170                         Type[] arg_types = new Type [pd.Count];
2171
2172                         for (int i = 0; i < arg_count; i++) {
2173                                 param_types [i] = pd.ParameterType (i);
2174
2175                                 Argument a = (Argument) arguments [i];
2176                                 if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
2177                                         continue;
2178
2179                                 arg_types [i] = a.Type;
2180                         }
2181
2182                         if (!InferTypeArguments (param_types, arg_types, infered_types))
2183                                 return false;
2184
2185                         method = method.BindGenericParameters (infered_types);
2186                         return true;
2187                 }
2188
2189                 public static bool InferTypeArguments (EmitContext ec, ParameterData apd,
2190                                                        ref MethodBase method)
2191                 {
2192                         if (!TypeManager.IsGenericMethod (method))
2193                                 return true;
2194
2195                         ParameterData pd = TypeManager.GetParameterData (method);
2196                         if (apd.Count != pd.Count)
2197                                 return false;
2198
2199                         Type[] method_args = method.GetGenericArguments ();
2200                         Type[] infered_types = new Type [method_args.Length];
2201
2202                         Type[] param_types = new Type [pd.Count];
2203                         Type[] arg_types = new Type [pd.Count];
2204
2205                         for (int i = 0; i < apd.Count; i++) {
2206                                 param_types [i] = pd.ParameterType (i);
2207                                 arg_types [i] = apd.ParameterType (i);
2208                         }
2209
2210                         if (!InferTypeArguments (param_types, arg_types, infered_types))
2211                                 return false;
2212
2213                         method = method.BindGenericParameters (infered_types);
2214                         return true;
2215                 }
2216
2217                 public static bool IsNullableType (Type t)
2218                 {
2219                         if (!t.IsGenericInstance)
2220                                 return false;
2221
2222                         Type gt = t.GetGenericTypeDefinition ();
2223                         return gt == generic_nullable_type;
2224                 }
2225         }
2226
2227         public abstract class Nullable
2228         {
2229                 protected sealed class NullableInfo
2230                 {
2231                         public readonly Type Type;
2232                         public readonly Type UnderlyingType;
2233                         public readonly MethodInfo HasValue;
2234                         public readonly MethodInfo Value;
2235                         public readonly ConstructorInfo Constructor;
2236
2237                         public NullableInfo (Type type)
2238                         {
2239                                 Type = type;
2240                                 UnderlyingType = TypeManager.GetTypeArguments (type) [0];
2241
2242                                 PropertyInfo has_value_pi = type.GetProperty ("HasValue");
2243                                 PropertyInfo value_pi = type.GetProperty ("Value");
2244
2245                                 HasValue = has_value_pi.GetGetMethod (false);
2246                                 Value = value_pi.GetGetMethod (false);
2247                                 Constructor = type.GetConstructor (new Type[] { UnderlyingType });
2248                         }
2249                 }
2250
2251                 protected class Unwrap : Expression, IMemoryLocation, IAssignMethod
2252                 {
2253                         Expression expr;
2254                         NullableInfo info;
2255
2256                         LocalTemporary temp;
2257                         bool has_temp;
2258
2259                         public Unwrap (Expression expr, Location loc)
2260                         {
2261                                 this.expr = expr;
2262                                 this.loc = loc;
2263                         }
2264
2265                         public override Expression DoResolve (EmitContext ec)
2266                         {
2267                                 expr = expr.Resolve (ec);
2268                                 if (expr == null)
2269                                         return null;
2270
2271                                 if (!(expr is IMemoryLocation))
2272                                         temp = new LocalTemporary (ec, expr.Type);
2273
2274                                 info = new NullableInfo (expr.Type);
2275                                 type = info.UnderlyingType;
2276                                 eclass = expr.eclass;
2277                                 return this;
2278                         }
2279
2280                         public override void Emit (EmitContext ec)
2281                         {
2282                                 AddressOf (ec, AddressOp.LoadStore);
2283                                 ec.ig.EmitCall (OpCodes.Call, info.Value, null);
2284                         }
2285
2286                         public void EmitCheck (EmitContext ec)
2287                         {
2288                                 AddressOf (ec, AddressOp.LoadStore);
2289                                 ec.ig.EmitCall (OpCodes.Call, info.HasValue, null);
2290                         }
2291
2292                         void create_temp (EmitContext ec)
2293                         {
2294                                 if ((temp != null) && !has_temp) {
2295                                         expr.Emit (ec);
2296                                         temp.Store (ec);
2297                                         has_temp = true;
2298                                 }
2299                         }
2300
2301                         public void AddressOf (EmitContext ec, AddressOp mode)
2302                         {
2303                                 create_temp (ec);
2304                                 if (temp != null)
2305                                         temp.AddressOf (ec, AddressOp.LoadStore);
2306                                 else
2307                                         ((IMemoryLocation) expr).AddressOf (ec, AddressOp.LoadStore);
2308                         }
2309
2310                         public void Emit (EmitContext ec, bool leave_copy)
2311                         {
2312                                 create_temp (ec);
2313                                 if (leave_copy) {
2314                                         if (temp != null)
2315                                                 temp.Emit (ec);
2316                                         else
2317                                                 expr.Emit (ec);
2318                                 }
2319
2320                                 Emit (ec);
2321                         }
2322
2323                         public void EmitAssign (EmitContext ec, Expression source,
2324                                                 bool leave_copy, bool prepare_for_load)
2325                         {
2326                                 source.Emit (ec);
2327                                 ec.ig.Emit (OpCodes.Newobj, info.Constructor);
2328
2329                                 if (leave_copy)
2330                                         ec.ig.Emit (OpCodes.Dup);
2331
2332                                 Expression empty = new EmptyExpression (expr.Type);
2333                                 ((IAssignMethod) expr).EmitAssign (ec, empty, false, prepare_for_load);
2334                         }
2335                 }
2336
2337                 protected class Wrap : Expression
2338                 {
2339                         Expression expr;
2340                         NullableInfo info;
2341
2342                         public Wrap (Expression expr, Location loc)
2343                         {
2344                                 this.expr = expr;
2345                                 this.loc = loc;
2346                         }
2347
2348                         public override Expression DoResolve (EmitContext ec)
2349                         {
2350                                 expr = expr.Resolve (ec);
2351                                 if (expr == null)
2352                                         return null;
2353
2354                                 TypeExpr target_type = new NullableType (expr.Type, loc);
2355                                 target_type = target_type.ResolveAsTypeTerminal (ec);
2356                                 if (target_type == null)
2357                                         return null;
2358
2359                                 type = target_type.Type;
2360                                 info = new NullableInfo (type);
2361                                 eclass = ExprClass.Value;
2362                                 return this;
2363                         }
2364
2365                         public override void Emit (EmitContext ec)
2366                         {
2367                                 expr.Emit (ec);
2368                                 ec.ig.Emit (OpCodes.Newobj, info.Constructor);
2369                         }
2370                 }
2371
2372                 public class NullableLiteral : Expression, IMemoryLocation {
2373                         public NullableLiteral (Type target_type, Location loc)
2374                         {
2375                                 this.type = target_type;
2376                                 this.loc = loc;
2377
2378                                 eclass = ExprClass.Value;
2379                         }
2380                 
2381                         public override Expression DoResolve (EmitContext ec)
2382                         {
2383                                 return this;
2384                         }
2385
2386                         public override void Emit (EmitContext ec)
2387                         {
2388                                 LocalTemporary value_target = new LocalTemporary (ec, type);
2389
2390                                 value_target.AddressOf (ec, AddressOp.Store);
2391                                 ec.ig.Emit (OpCodes.Initobj, type);
2392                                 value_target.Emit (ec);
2393                         }
2394
2395                         public void AddressOf (EmitContext ec, AddressOp Mode)
2396                         {
2397                                 LocalTemporary value_target = new LocalTemporary (ec, type);
2398                                         
2399                                 value_target.AddressOf (ec, AddressOp.Store);
2400                                 ec.ig.Emit (OpCodes.Initobj, type);
2401                                 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
2402                         }
2403                 }
2404
2405                 public abstract class Lifted : Expression, IMemoryLocation
2406                 {
2407                         Expression expr, underlying, wrap, null_value;
2408                         Unwrap unwrap;
2409
2410                         protected Lifted (Expression expr, Location loc)
2411                         {
2412                                 this.expr = expr;
2413                                 this.loc = loc;
2414                         }
2415
2416                         public override Expression DoResolve (EmitContext ec)
2417                         {
2418                                 expr = expr.Resolve (ec);
2419                                 if (expr == null)
2420                                         return null;
2421
2422                                 unwrap = (Unwrap) new Unwrap (expr, loc).Resolve (ec);
2423                                 if (unwrap == null)
2424                                         return null;
2425
2426                                 underlying = ResolveUnderlying (unwrap, ec);
2427                                 if (underlying == null)
2428                                         return null;
2429
2430                                 wrap = new Wrap (underlying, loc).Resolve (ec);
2431                                 if (wrap == null)
2432                                         return null;
2433
2434                                 null_value = new NullableLiteral (wrap.Type, loc).Resolve (ec);
2435                                 if (null_value == null)
2436                                         return null;
2437
2438                                 type = wrap.Type;
2439                                 eclass = ExprClass.Value;
2440                                 return this;
2441                         }
2442
2443                         protected abstract Expression ResolveUnderlying (Expression unwrap, EmitContext ec);
2444
2445                         public override void Emit (EmitContext ec)
2446                         {
2447                                 ILGenerator ig = ec.ig;
2448                                 Label is_null_label = ig.DefineLabel ();
2449                                 Label end_label = ig.DefineLabel ();
2450
2451                                 unwrap.EmitCheck (ec);
2452                                 ig.Emit (OpCodes.Brfalse, is_null_label);
2453
2454                                 wrap.Emit (ec);
2455                                 ig.Emit (OpCodes.Br, end_label);
2456
2457                                 ig.MarkLabel (is_null_label);
2458                                 null_value.Emit (ec);
2459
2460                                 ig.MarkLabel (end_label);
2461                         }
2462
2463                         public void AddressOf (EmitContext ec, AddressOp mode)
2464                         {
2465                                 unwrap.AddressOf (ec, mode);
2466                         }
2467                 }
2468
2469                 public class LiftedConversion : Lifted
2470                 {
2471                         public readonly bool IsUser;
2472                         public readonly bool IsExplicit;
2473                         public readonly Type TargetType;
2474
2475                         public LiftedConversion (Expression expr, Type target_type, bool is_user,
2476                                                  bool is_explicit, Location loc)
2477                                 : base (expr, loc)
2478                         {
2479                                 this.IsUser = is_user;
2480                                 this.IsExplicit = is_explicit;
2481                                 this.TargetType = target_type;
2482                         }
2483
2484                         protected override Expression ResolveUnderlying (Expression unwrap, EmitContext ec)
2485                         {
2486                                 Type type = TypeManager.GetTypeArguments (TargetType) [0];
2487
2488                                 if (IsUser) {
2489                                         return Convert.UserDefinedConversion (ec, unwrap, type, loc, IsExplicit);
2490                                 } else {
2491                                         if (IsExplicit)
2492                                                 return Convert.ExplicitConversion (ec, unwrap, type, loc);
2493                                         else
2494                                                 return Convert.ImplicitConversion (ec, unwrap, type, loc);
2495                                 }
2496                         }
2497                 }
2498
2499                 public class LiftedUnaryOperator : Lifted
2500                 {
2501                         public readonly Unary.Operator Oper;
2502
2503                         public LiftedUnaryOperator (Unary.Operator op, Expression expr, Location loc)
2504                                 : base (expr, loc)
2505                         {
2506                                 this.Oper = op;
2507                         }
2508
2509                         protected override Expression ResolveUnderlying (Expression unwrap, EmitContext ec)
2510                         {
2511                                 return new Unary (Oper, unwrap, loc);
2512                         }
2513                 }
2514
2515                 public class LiftedConditional : Lifted
2516                 {
2517                         Expression true_expr, false_expr;
2518
2519                         public LiftedConditional (Expression expr, Expression true_expr, Expression false_expr,
2520                                                   Location loc)
2521                                 : base (expr, loc)
2522                         {
2523                                 this.true_expr = true_expr;
2524                                 this.false_expr = false_expr;
2525                         }
2526
2527                         protected override Expression ResolveUnderlying (Expression unwrap, EmitContext ec)
2528                         {
2529                                 return new Conditional (unwrap, true_expr, false_expr, loc);
2530                         }
2531                 }
2532
2533                 public class LiftedBinaryOperator : Expression
2534                 {
2535                         public readonly Binary.Operator Oper;
2536
2537                         Expression left, right, underlying, null_value, bool_wrap;
2538                         Unwrap left_unwrap, right_unwrap;
2539                         bool is_equality, is_comparision, is_boolean;
2540
2541                         public LiftedBinaryOperator (Binary.Operator op, Expression left, Expression right,
2542                                                      Location loc)
2543                         {
2544                                 this.Oper = op;
2545                                 this.left = left;
2546                                 this.right = right;
2547                                 this.loc = loc;
2548                         }
2549
2550                         public override Expression DoResolve (EmitContext ec)
2551                         {
2552                                 if (TypeManager.IsNullableType (left.Type)) {
2553                                         left_unwrap = new Unwrap (left, loc);
2554                                         left = left_unwrap.Resolve (ec);
2555                                         if (left == null)
2556                                                 return null;
2557                                 }
2558
2559                                 if (TypeManager.IsNullableType (right.Type)) {
2560                                         right_unwrap = new Unwrap (right, loc);
2561                                         right = right_unwrap.Resolve (ec);
2562                                         if (right == null)
2563                                                 return null;
2564                                 }
2565
2566                                 if (((Oper == Binary.Operator.BitwiseAnd) || (Oper == Binary.Operator.BitwiseOr) ||
2567                                      (Oper == Binary.Operator.LogicalAnd) || (Oper == Binary.Operator.LogicalOr)) &&
2568                                     ((left.Type == TypeManager.bool_type) && (right.Type == TypeManager.bool_type))) {
2569                                         Expression empty = new EmptyExpression (TypeManager.bool_type);
2570                                         bool_wrap = new Wrap (empty, loc).Resolve (ec);
2571                                         null_value = new NullableLiteral (bool_wrap.Type, loc).Resolve (ec);
2572
2573                                         type = bool_wrap.Type;
2574                                         is_boolean = true;
2575                                 } else if ((Oper == Binary.Operator.Equality) || (Oper == Binary.Operator.Inequality)) {
2576                                         if (!(left is NullLiteral) && !(right is NullLiteral)) {
2577                                                 underlying = new Binary (Oper, left, right, loc).Resolve (ec);
2578                                                 if (underlying == null)
2579                                                         return null;
2580                                         }
2581
2582                                         type = TypeManager.bool_type;
2583                                         is_equality = true;
2584                                 } else if ((Oper == Binary.Operator.LessThan) ||
2585                                            (Oper == Binary.Operator.GreaterThan) ||
2586                                            (Oper == Binary.Operator.LessThanOrEqual) ||
2587                                            (Oper == Binary.Operator.GreaterThanOrEqual)) {
2588                                         underlying = new Binary (Oper, left, right, loc).Resolve (ec);
2589                                         if (underlying == null)
2590                                                 return null;
2591
2592                                         type = TypeManager.bool_type;
2593                                         is_comparision = true;
2594                                 } else {
2595                                         underlying = new Binary (Oper, left, right, loc).Resolve (ec);
2596                                         if (underlying == null)
2597                                                 return null;
2598
2599                                         underlying = new Wrap (underlying, loc).Resolve (ec);
2600                                         if (underlying == null)
2601                                                 return null;
2602
2603                                         type = underlying.Type;
2604                                         null_value = new NullableLiteral (type, loc).Resolve (ec);
2605                                 }
2606
2607                                 eclass = ExprClass.Value;
2608                                 return this;
2609                         }
2610
2611                         void EmitBoolean (EmitContext ec)
2612                         {
2613                                 ILGenerator ig = ec.ig;
2614
2615                                 Label left_is_null_label = ig.DefineLabel ();
2616                                 Label right_is_null_label = ig.DefineLabel ();
2617                                 Label is_null_label = ig.DefineLabel ();
2618                                 Label wrap_label = ig.DefineLabel ();
2619                                 Label end_label = ig.DefineLabel ();
2620
2621                                 if (left_unwrap != null) {
2622                                         left_unwrap.EmitCheck (ec);
2623                                         ig.Emit (OpCodes.Brfalse, left_is_null_label);
2624                                 }
2625
2626                                 left.Emit (ec);
2627                                 ig.Emit (OpCodes.Dup);
2628                                 if ((Oper == Binary.Operator.BitwiseOr) || (Oper == Binary.Operator.LogicalOr))
2629                                         ig.Emit (OpCodes.Brtrue, wrap_label);
2630                                 else
2631                                         ig.Emit (OpCodes.Brfalse, wrap_label);
2632
2633                                 if (right_unwrap != null) {
2634                                         right_unwrap.EmitCheck (ec);
2635                                         ig.Emit (OpCodes.Brfalse, right_is_null_label);
2636                                 }
2637
2638                                 if ((Oper == Binary.Operator.LogicalAnd) || (Oper == Binary.Operator.LogicalOr))
2639                                         ig.Emit (OpCodes.Pop);
2640
2641                                 right.Emit (ec);
2642                                 if (Oper == Binary.Operator.BitwiseOr)
2643                                         ig.Emit (OpCodes.Or);
2644                                 else if (Oper == Binary.Operator.BitwiseAnd)
2645                                         ig.Emit (OpCodes.And);
2646                                 ig.Emit (OpCodes.Br, wrap_label);
2647
2648                                 ig.MarkLabel (left_is_null_label);
2649                                 if (right_unwrap != null) {
2650                                         right_unwrap.EmitCheck (ec);
2651                                         ig.Emit (OpCodes.Brfalse, is_null_label);
2652                                 }
2653
2654                                 right.Emit (ec);
2655                                 ig.Emit (OpCodes.Dup);
2656                                 if ((Oper == Binary.Operator.BitwiseOr) || (Oper == Binary.Operator.LogicalOr))
2657                                         ig.Emit (OpCodes.Brtrue, wrap_label);
2658                                 else
2659                                         ig.Emit (OpCodes.Brfalse, wrap_label);
2660
2661                                 ig.MarkLabel (right_is_null_label);
2662                                 ig.Emit (OpCodes.Pop);
2663                                 ig.MarkLabel (is_null_label);
2664                                 null_value.Emit (ec);
2665                                 ig.Emit (OpCodes.Br, end_label);
2666
2667                                 ig.MarkLabel (wrap_label);
2668                                 ig.Emit (OpCodes.Nop);
2669                                 bool_wrap.Emit (ec);
2670                                 ig.Emit (OpCodes.Nop);
2671
2672                                 ig.MarkLabel (end_label);
2673                         }
2674
2675                         void EmitEquality (EmitContext ec)
2676                         {
2677                                 ILGenerator ig = ec.ig;
2678
2679                                 Label left_not_null_label = ig.DefineLabel ();
2680                                 Label false_label = ig.DefineLabel ();
2681                                 Label true_label = ig.DefineLabel ();
2682                                 Label end_label = ig.DefineLabel ();
2683
2684                                 if (left_unwrap != null) {
2685                                         left_unwrap.EmitCheck (ec);
2686                                         if (right is NullLiteral) {
2687                                                 if (Oper == Binary.Operator.Equality)
2688                                                         ig.Emit (OpCodes.Brfalse, true_label);
2689                                                 else
2690                                                         ig.Emit (OpCodes.Brfalse, false_label);
2691                                         } else if (right_unwrap != null) {
2692                                                 ig.Emit (OpCodes.Dup);
2693                                                 ig.Emit (OpCodes.Brtrue, left_not_null_label);
2694                                                 right_unwrap.EmitCheck (ec);
2695                                                 ig.Emit (OpCodes.Ceq);
2696                                                 if (Oper == Binary.Operator.Inequality) {
2697                                                         ig.Emit (OpCodes.Ldc_I4_0);
2698                                                         ig.Emit (OpCodes.Ceq);
2699                                                 }
2700                                                 ig.Emit (OpCodes.Br, end_label);
2701
2702                                                 ig.MarkLabel (left_not_null_label);
2703                                                 ig.Emit (OpCodes.Pop);
2704                                         } else {
2705                                                 if (Oper == Binary.Operator.Equality)
2706                                                         ig.Emit (OpCodes.Brfalse, false_label);
2707                                                 else
2708                                                         ig.Emit (OpCodes.Brfalse, true_label);
2709                                         }
2710                                 }
2711
2712                                 if (right_unwrap != null) {
2713                                         right_unwrap.EmitCheck (ec);
2714                                         if (left is NullLiteral) {
2715                                                 if (Oper == Binary.Operator.Equality)
2716                                                         ig.Emit (OpCodes.Brfalse, true_label);
2717                                                 else
2718                                                         ig.Emit (OpCodes.Brfalse, false_label);
2719                                         } else {
2720                                                 if (Oper == Binary.Operator.Equality)
2721                                                         ig.Emit (OpCodes.Brfalse, false_label);
2722                                                 else
2723                                                         ig.Emit (OpCodes.Brfalse, true_label);
2724                                         }
2725                                 }
2726
2727                                 bool left_is_null = left is NullLiteral;
2728                                 bool right_is_null = right is NullLiteral;
2729                                 if (left_is_null || right_is_null) {
2730                                         if (((Oper == Binary.Operator.Equality) && (left_is_null == right_is_null)) ||
2731                                             ((Oper == Binary.Operator.Inequality) && (left_is_null != right_is_null)))
2732                                                 ig.Emit (OpCodes.Br, true_label);
2733                                         else
2734                                                 ig.Emit (OpCodes.Br, false_label);
2735                                 } else {
2736                                         underlying.Emit (ec);
2737                                         ig.Emit (OpCodes.Br, end_label);
2738                                 }
2739
2740                                 ig.MarkLabel (false_label);
2741                                 ig.Emit (OpCodes.Ldc_I4_0);
2742                                 ig.Emit (OpCodes.Br, end_label);
2743
2744                                 ig.MarkLabel (true_label);
2745                                 ig.Emit (OpCodes.Ldc_I4_1);
2746
2747                                 ig.MarkLabel (end_label);
2748                         }
2749
2750                         void EmitComparision (EmitContext ec)
2751                         {
2752                                 ILGenerator ig = ec.ig;
2753
2754                                 Label is_null_label = ig.DefineLabel ();
2755                                 Label end_label = ig.DefineLabel ();
2756
2757                                 if (left_unwrap != null) {
2758                                         left_unwrap.EmitCheck (ec);
2759                                         ig.Emit (OpCodes.Brfalse, is_null_label);
2760                                 }
2761
2762                                 if (right_unwrap != null) {
2763                                         right_unwrap.EmitCheck (ec);
2764                                         ig.Emit (OpCodes.Brfalse, is_null_label);
2765                                 }
2766
2767                                 underlying.Emit (ec);
2768                                 ig.Emit (OpCodes.Br, end_label);
2769
2770                                 ig.MarkLabel (is_null_label);
2771                                 ig.Emit (OpCodes.Ldc_I4_0);
2772
2773                                 ig.MarkLabel (end_label);
2774                         }
2775
2776                         public override void Emit (EmitContext ec)
2777                         {
2778                                 if (is_boolean) {
2779                                         EmitBoolean (ec);
2780                                         return;
2781                                 } else if (is_equality) {
2782                                         EmitEquality (ec);
2783                                         return;
2784                                 } else if (is_comparision) {
2785                                         EmitComparision (ec);
2786                                         return;
2787                                 }
2788
2789                                 ILGenerator ig = ec.ig;
2790
2791                                 Label is_null_label = ig.DefineLabel ();
2792                                 Label end_label = ig.DefineLabel ();
2793
2794                                 if (left_unwrap != null) {
2795                                         left_unwrap.EmitCheck (ec);
2796                                         ig.Emit (OpCodes.Brfalse, is_null_label);
2797                                 }
2798
2799                                 if (right_unwrap != null) {
2800                                         right_unwrap.EmitCheck (ec);
2801                                         ig.Emit (OpCodes.Brfalse, is_null_label);
2802                                 }
2803
2804                                 underlying.Emit (ec);
2805                                 ig.Emit (OpCodes.Br, end_label);
2806
2807                                 ig.MarkLabel (is_null_label);
2808                                 null_value.Emit (ec);
2809
2810                                 ig.MarkLabel (end_label);
2811                         }
2812                 }
2813
2814                 public class OperatorTrueOrFalse : Expression
2815                 {
2816                         public readonly bool IsTrue;
2817
2818                         Expression expr;
2819                         Unwrap unwrap;
2820
2821                         public OperatorTrueOrFalse (Expression expr, bool is_true, Location loc)
2822                         {
2823                                 this.IsTrue = is_true;
2824                                 this.expr = expr;
2825                                 this.loc = loc;
2826                         }
2827
2828                         public override Expression DoResolve (EmitContext ec)
2829                         {
2830                                 unwrap = new Unwrap (expr, loc);
2831                                 expr = unwrap.Resolve (ec);
2832                                 if (expr == null)
2833                                         return null;
2834
2835                                 if (unwrap.Type != TypeManager.bool_type)
2836                                         return null;
2837
2838                                 type = TypeManager.bool_type;
2839                                 eclass = ExprClass.Value;
2840                                 return this;
2841                         }
2842
2843                         public override void Emit (EmitContext ec)
2844                         {
2845                                 ILGenerator ig = ec.ig;
2846
2847                                 Label is_null_label = ig.DefineLabel ();
2848                                 Label end_label = ig.DefineLabel ();
2849
2850                                 unwrap.EmitCheck (ec);
2851                                 ig.Emit (OpCodes.Brfalse, is_null_label);
2852
2853                                 unwrap.Emit (ec);
2854                                 if (!IsTrue) {
2855                                         ig.Emit (OpCodes.Ldc_I4_0);
2856                                         ig.Emit (OpCodes.Ceq);
2857                                 }
2858                                 ig.Emit (OpCodes.Br, end_label);
2859
2860                                 ig.MarkLabel (is_null_label);
2861                                 ig.Emit (OpCodes.Ldc_I4_0);
2862
2863                                 ig.MarkLabel (end_label);
2864                         }
2865                 }
2866
2867                 public class NullCoalescingOperator : Expression
2868                 {
2869                         Expression left, right;
2870                         Expression expr;
2871                         Unwrap unwrap;
2872
2873                         public NullCoalescingOperator (Expression left, Expression right, Location loc)
2874                         {
2875                                 this.left = left;
2876                                 this.right = right;
2877                                 this.loc = loc;
2878
2879                                 eclass = ExprClass.Value;
2880                         }
2881
2882                         public override Expression DoResolve (EmitContext ec)
2883                         {
2884                                 if (type != null)
2885                                         return this;
2886
2887                                 left = left.Resolve (ec);
2888                                 if (left == null)
2889                                         return null;
2890
2891                                 right = right.Resolve (ec);
2892                                 if (right == null)
2893                                         return null;
2894
2895                                 Type ltype = left.Type, rtype = right.Type;
2896
2897                                 if (!TypeManager.IsNullableType (ltype) && ltype.IsValueType) {
2898                                         Binary.Error_OperatorCannotBeApplied (loc, "??", ltype, rtype);
2899                                         return null;
2900                                 }
2901
2902                                 if (TypeManager.IsNullableType (ltype)) {
2903                                         NullableInfo info = new NullableInfo (ltype);
2904
2905                                         unwrap = (Unwrap) new Unwrap (left, loc).Resolve (ec);
2906                                         if (unwrap == null)
2907                                                 return null;
2908
2909                                         expr = Convert.ImplicitConversion (ec, right, info.UnderlyingType, loc);
2910                                         if (expr != null) {
2911                                                 left = unwrap;
2912                                                 type = expr.Type;
2913                                                 return this;
2914                                         }
2915                                 }
2916
2917                                 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
2918                                 if (expr != null) {
2919                                         type = expr.Type;
2920                                         return this;
2921                                 }
2922
2923                                 if (unwrap != null) {
2924                                         expr = Convert.ImplicitConversion (ec, unwrap, rtype, loc);
2925                                         if (expr != null) {
2926                                                 left = expr;
2927                                                 expr = right;
2928                                                 type = expr.Type;
2929                                                 return this;
2930                                         }
2931                                 }
2932
2933                                 Binary.Error_OperatorCannotBeApplied (loc, "??", ltype, rtype);
2934                                 return null;
2935                         }
2936
2937                         public override void Emit (EmitContext ec)
2938                         {
2939                                 ILGenerator ig = ec.ig;
2940
2941                                 Label is_null_label = ig.DefineLabel ();
2942                                 Label end_label = ig.DefineLabel ();
2943
2944                                 if (unwrap != null) {
2945                                         unwrap.EmitCheck (ec);
2946                                         ig.Emit (OpCodes.Brfalse, is_null_label);
2947                                 }
2948
2949                                 left.Emit (ec);
2950                                 ig.Emit (OpCodes.Br, end_label);
2951
2952                                 ig.MarkLabel (is_null_label);
2953                                 expr.Emit (ec);
2954
2955                                 ig.MarkLabel (end_label);
2956                         }
2957                 }
2958
2959                 public class LiftedUnaryMutator : ExpressionStatement
2960                 {
2961                         public readonly UnaryMutator.Mode Mode;
2962                         Expression expr, null_value;
2963                         UnaryMutator underlying;
2964                         Unwrap unwrap;
2965
2966                         public LiftedUnaryMutator (UnaryMutator.Mode mode, Expression expr, Location loc)
2967                         {
2968                                 this.expr = expr;
2969                                 this.Mode = mode;
2970                                 this.loc = loc;
2971
2972                                 eclass = ExprClass.Value;
2973                         }
2974
2975                         public override Expression DoResolve (EmitContext ec)
2976                         {
2977                                 expr = expr.Resolve (ec);
2978                                 if (expr == null)
2979                                         return null;
2980
2981                                 unwrap = (Unwrap) new Unwrap (expr, loc).Resolve (ec);
2982                                 if (unwrap == null)
2983                                         return null;
2984
2985                                 underlying = (UnaryMutator) new UnaryMutator (Mode, unwrap, loc).Resolve (ec);
2986                                 if (underlying == null)
2987                                         return null;
2988
2989                                 null_value = new NullableLiteral (expr.Type, loc).Resolve (ec);
2990                                 if (null_value == null)
2991                                         return null;
2992
2993                                 type = expr.Type;
2994                                 return this;
2995                         }
2996
2997                         void DoEmit (EmitContext ec, bool is_expr)
2998                         {
2999                                 ILGenerator ig = ec.ig;
3000                                 Label is_null_label = ig.DefineLabel ();
3001                                 Label end_label = ig.DefineLabel ();
3002
3003                                 unwrap.EmitCheck (ec);
3004                                 ig.Emit (OpCodes.Brfalse, is_null_label);
3005
3006                                 if (is_expr)
3007                                         underlying.Emit (ec);
3008                                 else
3009                                         underlying.EmitStatement (ec);
3010                                 ig.Emit (OpCodes.Br, end_label);
3011
3012                                 ig.MarkLabel (is_null_label);
3013                                 if (is_expr)
3014                                         null_value.Emit (ec);
3015
3016                                 ig.MarkLabel (end_label);
3017                         }
3018
3019                         public override void Emit (EmitContext ec)
3020                         {
3021                                 DoEmit (ec, true);
3022                         }
3023
3024                         public override void EmitStatement (EmitContext ec)
3025                         {
3026                                 DoEmit (ec, false);
3027                         }
3028                 }
3029         }
3030 }