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