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