2001-10-27 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mcs / mcs / expression.cs
1 //
2 // expression.cs: Expression representation for the IL tree.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.
8 //
9 //
10 // Ideas:
11 //   Maybe we should make Resolve be an instance method that just calls
12 //   the virtual DoResolve function and checks conditions like the eclass
13 //   and type being set if a non-null value is returned.  For robustness
14 //   purposes.
15 //
16
17 namespace CIR {
18         using System;
19         using System.Collections;
20         using System.Diagnostics;
21         using System.Reflection;
22         using System.Reflection.Emit;
23         using System.Text;
24         
25         // <remarks>
26         //   The ExprClass class contains the is used to pass the 
27         //   classification of an expression (value, variable, namespace,
28         //   type, method group, property access, event access, indexer access,
29         //   nothing).
30         // </remarks>
31         public enum ExprClass {
32                 Invalid,
33                 
34                 Value,
35                 Variable,
36                 Namespace,
37                 Type,
38                 MethodGroup,
39                 PropertyAccess,
40                 EventAccess,
41                 IndexerAccess,
42                 Nothing, 
43         }
44
45         // <summary>
46         //   An interface provided by expressions that can be used as
47         //   LValues and can store the value on the top of the stack on
48         //   their storage
49         // </summary>
50         public interface IStackStore {
51
52                 // <summary>
53                 //   The Store method should store the contents of the top
54                 //   of the stack into the storage that is implemented by
55                 //   the particular implementation of LValue
56                 // </summary>
57                 void Store     (EmitContext ec);
58         }
59
60         // <summary>
61         //   This interface is implemented by variables
62         // </summary>
63         public interface IMemoryLocation {
64                 // <summary>
65                 //   The AddressOf method should generate code that loads
66                 //   the address of the object and leaves it on the stack
67                 // </summary>
68                 void AddressOf (EmitContext ec);
69         }
70
71         // <remarks>
72         //   Base class for expressions
73         // </remarks>
74         public abstract class Expression {
75                 protected ExprClass eclass;
76                 protected Type      type;
77                 
78                 public Type Type {
79                         get {
80                                 return type;
81                         }
82
83                         set {
84                                 type = value;
85                         }
86                 }
87
88                 public ExprClass ExprClass {
89                         get {
90                                 return eclass;
91                         }
92
93                         set {
94                                 eclass = value;
95                         }
96                 }
97
98                 // <summary>
99                 //   Utility wrapper routine for Error, just to beautify the code
100                 // </summary>
101                 static protected void Error (int error, string s)
102                 {
103                         Report.Error (error, s);
104                 }
105
106                 static protected void Error (int error, Location loc, string s)
107                 {
108                         Report.Error (error, loc, s);
109                 }
110                 
111                 // <summary>
112                 //   Utility wrapper routine for Warning, just to beautify the code
113                 // </summary>
114                 static protected void Warning (int warning, string s)
115                 {
116                         Report.Warning (warning, s);
117                 }
118
119                 // <summary>
120                 //   Performs semantic analysis on the Expression
121                 // </summary>
122                 //
123                 // <remarks>
124                 //   The Resolve method is invoked to perform the semantic analysis
125                 //   on the node.
126                 //
127                 //   The return value is an expression (it can be the
128                 //   same expression in some cases) or a new
129                 //   expression that better represents this node.
130                 //   
131                 //   For example, optimizations of Unary (LiteralInt)
132                 //   would return a new LiteralInt with a negated
133                 //   value.
134                 //   
135                 //   If there is an error during semantic analysis,
136                 //   then an error should be reported (using Report)
137                 //   and a null value should be returned.
138                 //   
139                 //   There are two side effects expected from calling
140                 //   Resolve(): the the field variable "eclass" should
141                 //   be set to any value of the enumeration
142                 //   `ExprClass' and the type variable should be set
143                 //   to a valid type (this is the type of the
144                 //   expression).
145                 // </remarks>
146                 
147                 public abstract Expression DoResolve (EmitContext ec);
148
149                 public virtual Expression DoResolveLValue (EmitContext ec, Expression right_side)
150                 {
151                         return DoResolve (ec);
152                 }
153                 
154                 //
155                 // Currently Resolve wraps DoResolve to perform sanity
156                 // checking and assertion checking on what we expect from Resolve
157                 //
158                 public Expression Resolve (EmitContext ec)
159                 {
160                         Expression e = DoResolve (ec);
161
162                         if (e != null){
163                                 if (e is SimpleName){
164                                         SimpleName s = (SimpleName) e;
165                                         
166                                         Report.Error (
167                                                 103, s.Location,
168                                                 "The name `" + s.Name + "' could not be found in `" +
169                                                 ec.TypeContainer.Name + "'");
170                                         return null;
171                                 }
172                                 
173                                 if (e.ExprClass == ExprClass.Invalid)
174                                         throw new Exception ("Expression " + e +
175                                                              " ExprClass is Invalid after resolve");
176
177                                 if (e.ExprClass != ExprClass.MethodGroup)
178                                         if (e.type == null)
179                                                 throw new Exception ("Expression " + e +
180                                                                      " did not set its type after Resolve");
181                         }
182
183                         return e;
184                 }
185
186                 //
187                 // Just like `Resolve' above, but this allows SimpleNames to be returned.
188                 // This is used by MemberAccess to construct long names that can not be
189                 // partially resolved (namespace-qualified names for example).
190                 //
191                 public Expression ResolveWithSimpleName (EmitContext ec)
192                 {
193                         Expression e = DoResolve (ec);
194
195                         if (e != null){
196                                 if (e is SimpleName)
197                                         return e;
198
199                                 if (e.ExprClass == ExprClass.Invalid)
200                                         throw new Exception ("Expression " + e +
201                                                              " ExprClass is Invalid after resolve");
202
203                                 if (e.ExprClass != ExprClass.MethodGroup)
204                                         if (e.type == null)
205                                                 throw new Exception ("Expression " + e +
206                                                                      " did not set its type after Resolve");
207                         }
208
209                         return e;
210                 }
211                 
212                 //
213                 // Currently ResolveLValue wraps DoResolveLValue to perform sanity
214                 // checking and assertion checking on what we expect from Resolve
215                 //
216                 public Expression ResolveLValue (EmitContext ec, Expression right_side)
217                 {
218                         Expression e = DoResolveLValue (ec, right_side);
219
220                         if (e != null){
221                                 if (e is SimpleName){
222                                         SimpleName s = (SimpleName) e;
223                                         
224                                         Report.Error (
225                                                 103, s.Location,
226                                                 "The name `" + s.Name + "' could not be found in `" +
227                                                 ec.TypeContainer.Name + "'");
228                                         return null;
229                                 }
230
231                                 if (e.ExprClass == ExprClass.Invalid)
232                                         throw new Exception ("Expression " + e +
233                                                              " ExprClass is Invalid after resolve");
234
235                                 if (e.ExprClass != ExprClass.MethodGroup)
236                                         if (e.type == null)
237                                                 throw new Exception ("Expression " + e +
238                                                                      " did not set its type after Resolve");
239                         }
240
241                         return e;
242                 }
243                 
244                 // <summary>
245                 //   Emits the code for the expression
246                 // </summary>
247                 //
248                 // <remarks>
249                 // 
250                 //   The Emit method is invoked to generate the code
251                 //   for the expression.  
252                 //
253                 // </remarks>
254                 public abstract void Emit (EmitContext ec);
255                 
256                 // <summary>
257                 //   Protected constructor.  Only derivate types should
258                 //   be able to be created
259                 // </summary>
260
261                 protected Expression ()
262                 {
263                         eclass = ExprClass.Invalid;
264                         type = null;
265                 }
266
267                 // <summary>
268                 //   Returns a literalized version of a literal FieldInfo
269                 // </summary>
270                 static Expression Literalize (FieldInfo fi)
271                 {
272                         Type t = fi.FieldType;
273                         object v = fi.GetValue (fi);
274
275                         if (t == TypeManager.int32_type)
276                                 return new IntLiteral ((int) v);
277                         else if (t == TypeManager.uint32_type)
278                                 return new UIntLiteral ((uint) v);
279                         else if (t == TypeManager.int64_type)
280                                 return new LongLiteral ((long) v);
281                         else if (t == TypeManager.uint64_type)
282                                 return new ULongLiteral ((ulong) v);
283                         else if (t == TypeManager.float_type)
284                                 return new FloatLiteral ((float) v);
285                         else if (t == TypeManager.double_type)
286                                 return new DoubleLiteral ((double) v);
287                         else if (t == TypeManager.string_type)
288                                 return new StringLiteral ((string) v);
289                         else if (t == TypeManager.short_type)
290                                 return new IntLiteral ((int) ((short)v));
291                         else if (t == TypeManager.ushort_type)
292                                 return new IntLiteral ((int) ((ushort)v));
293                         else if (t == TypeManager.sbyte_type)
294                                 return new IntLiteral ((int) ((sbyte)v));
295                         else if (t == TypeManager.byte_type)
296                                 return new IntLiteral ((int) ((byte)v));
297                         else if (t == TypeManager.char_type)
298                                 return new IntLiteral ((int) ((char)v));
299                         else
300                                 throw new Exception ("Unknown type for literal (" + v.GetType () +
301                                                      "), details: " + fi);
302                 }
303
304                 // 
305                 // Returns a fully formed expression after a MemberLookup
306                 //
307                 static Expression ExprClassFromMemberInfo (EmitContext ec, MemberInfo mi, Location loc)
308                 {
309                         if (mi is EventInfo){
310                                 return new EventExpr ((EventInfo) mi, loc);
311                         } else if (mi is FieldInfo){
312                                 FieldInfo fi = (FieldInfo) mi;
313
314                                 if (fi.IsLiteral){
315                                         Expression e = Literalize (fi);
316                                         e.Resolve (ec);
317
318                                         return e;
319                                 } else
320                                         return new FieldExpr (fi, loc);
321                         } else if (mi is PropertyInfo){
322                                 return new PropertyExpr ((PropertyInfo) mi, loc);
323                         } else if (mi is Type)
324                                 return new TypeExpr ((Type) mi);
325
326                         return null;
327                 }
328                 
329                 //
330                 // FIXME: Probably implement a cache for (t,name,current_access_set)?
331                 //
332                 // FIXME: We need to cope with access permissions here, or this wont
333                 // work!
334                 //
335                 // This code could use some optimizations, but we need to do some
336                 // measurements.  For example, we could use a delegate to `flag' when
337                 // something can not any longer be a method-group (because it is something
338                 // else).
339                 //
340                 // Return values:
341                 //     If the return value is an Array, then it is an array of
342                 //     MethodBases
343                 //   
344                 //     If the return value is an MemberInfo, it is anything, but a Method
345                 //
346                 //     null on error.
347                 //
348                 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
349                 // the arguments here and have MemberLookup return only the methods that
350                 // match the argument count/type, unlike we are doing now (we delay this
351                 // decision).
352                 //
353                 // This is so we can catch correctly attempts to invoke instance methods
354                 // from a static body (scan for error 120 in ResolveSimpleName).
355                 //
356                 public static Expression MemberLookup (EmitContext ec, Type t, string name,
357                                                        bool same_type, MemberTypes mt,
358                                                        BindingFlags bf, Location loc)
359                 {
360                         if (same_type)
361                                 bf |= BindingFlags.NonPublic;
362
363                         MemberInfo [] mi = ec.TypeContainer.RootContext.TypeManager.FindMembers (
364                                 t, mt, bf, Type.FilterName, name);
365
366                         if (mi == null)
367                                 return null;
368
369                         // FIXME : How does this wierd case arise ?
370                         if (mi.Length == 0)
371                                 return null;
372                         
373                         if (mi.Length == 1 && !(mi [0] is MethodBase))
374                                 return Expression.ExprClassFromMemberInfo (ec, mi [0], loc);
375                         
376                         for (int i = 0; i < mi.Length; i++)
377                                 if (!(mi [i] is MethodBase)){
378                                         Error (-5, "Do not know how to reproduce this case: " + 
379                                                "Methods and non-Method with the same name, " +
380                                                "report this please");
381
382                                         for (i = 0; i < mi.Length; i++){
383                                                 Type tt = mi [i].GetType ();
384
385                                                 Console.WriteLine (i + ": " + mi [i]);
386                                                 while (tt != TypeManager.object_type){
387                                                         Console.WriteLine (tt);
388                                                         tt = tt.BaseType;
389                                                 }
390                                         }
391                                 }
392
393                         return new MethodGroupExpr (mi);
394                 }
395
396                 public const MemberTypes AllMemberTypes =
397                         MemberTypes.Constructor |
398                         MemberTypes.Event       |
399                         MemberTypes.Field       |
400                         MemberTypes.Method      |
401                         MemberTypes.NestedType  |
402                         MemberTypes.Property;
403                 
404                 public const BindingFlags AllBindingsFlags =
405                         BindingFlags.Public |
406                         BindingFlags.Static |
407                         BindingFlags.Instance;
408
409                 public static Expression MemberLookup (EmitContext ec, Type t, string name,
410                                                        bool same_type, Location loc)
411                 {
412                         return MemberLookup (ec, t, name, same_type, AllMemberTypes, AllBindingsFlags, loc);
413                 }
414
415                 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
416                 {
417                         Type expr_type = expr.Type;
418
419                         if (target_type == TypeManager.object_type) {
420                                 if (expr_type.IsClass)
421                                         return new EmptyCast (expr, target_type);
422                                 if (expr_type.IsValueType)
423                                         return new BoxedCast (expr);
424                         } else if (expr_type.IsSubclassOf (target_type)) {
425                                 return new EmptyCast (expr, target_type);
426                         } else {
427                                 // from any class-type S to any interface-type T.
428                                 if (expr_type.IsClass && target_type.IsInterface) {
429
430                                         if (TypeManager.ImplementsInterface (expr_type, target_type))
431                                                 return new EmptyCast (expr, target_type);
432                                         else
433                                                 return null;
434                                 }
435
436                                 // from any interface type S to interface-type T.
437                                 if (expr_type.IsInterface && target_type.IsInterface) {
438
439                                         if (TypeManager.ImplementsInterface (expr_type, target_type))
440                                                 return new EmptyCast (expr, target_type);
441                                         else
442                                                 return null;
443                                 }
444                                 
445                                 // from an array-type S to an array-type of type T
446                                 if (expr_type.IsArray && target_type.IsArray) {
447                                         if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
448
449                                                 Type expr_element_type = expr_type.GetElementType ();
450                                                 Type target_element_type = target_type.GetElementType ();
451
452                                                 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
453                                                         if (StandardConversionExists (expr_element_type,
454                                                                                       target_element_type))
455                                                                 return new EmptyCast (expr, target_type);
456                                         }
457                                 }
458                                 
459                                 
460                                 // from an array-type to System.Array
461                                 if (expr_type.IsArray && target_type == TypeManager.array_type)
462                                         return new EmptyCast (expr, target_type);
463                                 
464                                 // from any delegate type to System.Delegate
465                                 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
466                                     target_type == TypeManager.delegate_type)
467                                         return new EmptyCast (expr, target_type);
468                                         
469                                 // from any array-type or delegate type into System.ICloneable.
470                                 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
471                                         if (target_type == TypeManager.icloneable_type)
472                                                 return new EmptyCast (expr, target_type);
473                                 
474                                 // from the null type to any reference-type.
475                                 if (expr is NullLiteral)
476                                         return new EmptyCast (expr, target_type);
477
478                                 return null;
479
480                         }
481                         
482                         return null;
483                 }
484
485                 // <summary>
486                 //   Handles expressions like this: decimal d; d = 1;
487                 //   and changes them into: decimal d; d = new System.Decimal (1);
488                 // </summary>
489                 static Expression InternalTypeConstructor (EmitContext ec, Expression expr, Type target)
490                 {
491                         ArrayList args = new ArrayList ();
492
493                         args.Add (new Argument (expr, Argument.AType.Expression));
494
495                         Expression ne = new New (target.FullName, args,
496                                                  new Location (-1));
497
498                         return ne.Resolve (ec);
499                 }
500
501                 // <summary>
502                 //   Implicit Numeric Conversions.
503                 //
504                 //   expr is the expression to convert, returns a new expression of type
505                 //   target_type or null if an implicit conversion is not possible.
506                 //
507                 // </summary>
508                 static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
509                                                                     Type target_type, Location loc)
510                 {
511                         Type expr_type = expr.Type;
512                         
513                         //
514                         // Attempt to do the implicit constant expression conversions
515
516                         if (expr is IntLiteral){
517                                 Expression e;
518                                 
519                                 e = TryImplicitIntConversion (target_type, (IntLiteral) expr);
520                                 if (e != null)
521                                         return e;
522                         } else if (expr is LongLiteral){
523                                 //
524                                 // Try the implicit constant expression conversion
525                                 // from long to ulong, instead of a nice routine,
526                                 // we just inline it
527                                 //
528                                 if (((LongLiteral) expr).Value > 0)
529                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
530                         }
531                         
532                         if (expr_type == TypeManager.sbyte_type){
533                                 //
534                                 // From sbyte to short, int, long, float, double.
535                                 //
536                                 if (target_type == TypeManager.int32_type)
537                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
538                                 if (target_type == TypeManager.int64_type)
539                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
540                                 if (target_type == TypeManager.double_type)
541                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
542                                 if (target_type == TypeManager.float_type)
543                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
544                                 if (target_type == TypeManager.short_type)
545                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
546                                 if (target_type == TypeManager.decimal_type)
547                                         return InternalTypeConstructor (ec, expr, target_type);
548                         } else if (expr_type == TypeManager.byte_type){
549                                 //
550                                 // From byte to short, ushort, int, uint, long, ulong, float, double
551                                 // 
552                                 if ((target_type == TypeManager.short_type) ||
553                                     (target_type == TypeManager.ushort_type) ||
554                                     (target_type == TypeManager.int32_type) ||
555                                     (target_type == TypeManager.uint32_type))
556                                         return new EmptyCast (expr, target_type);
557
558                                 if (target_type == TypeManager.uint64_type)
559                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
560                                 if (target_type == TypeManager.int64_type)
561                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
562                                 
563                                 if (target_type == TypeManager.float_type)
564                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
565                                 if (target_type == TypeManager.double_type)
566                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
567                                 if (target_type == TypeManager.decimal_type)
568                                         return InternalTypeConstructor (ec, expr, target_type);
569                         } else if (expr_type == TypeManager.short_type){
570                                 //
571                                 // From short to int, long, float, double
572                                 // 
573                                 if (target_type == TypeManager.int32_type)
574                                         return new EmptyCast (expr, target_type);
575                                 if (target_type == TypeManager.int64_type)
576                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
577                                 if (target_type == TypeManager.double_type)
578                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
579                                 if (target_type == TypeManager.float_type)
580                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
581                                 if (target_type == TypeManager.decimal_type)
582                                         return InternalTypeConstructor (ec, expr, target_type);
583                         } else if (expr_type == TypeManager.ushort_type){
584                                 //
585                                 // From ushort to int, uint, long, ulong, float, double
586                                 //
587                                 if (target_type == TypeManager.uint32_type)
588                                         return new EmptyCast (expr, target_type);
589
590                                 if (target_type == TypeManager.uint64_type)
591                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
592                                 if (target_type == TypeManager.int32_type)
593                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
594                                 if (target_type == TypeManager.int64_type)
595                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
596                                 if (target_type == TypeManager.double_type)
597                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
598                                 if (target_type == TypeManager.float_type)
599                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
600                                 if (target_type == TypeManager.decimal_type)
601                                         return InternalTypeConstructor (ec, expr, target_type);
602                         } else if (expr_type == TypeManager.int32_type){
603                                 //
604                                 // From int to long, float, double
605                                 //
606                                 if (target_type == TypeManager.int64_type)
607                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
608                                 if (target_type == TypeManager.double_type)
609                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
610                                 if (target_type == TypeManager.float_type)
611                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
612                                 if (target_type == TypeManager.decimal_type)
613                                         return InternalTypeConstructor (ec, expr, target_type);
614                         } else if (expr_type == TypeManager.uint32_type){
615                                 //
616                                 // From uint to long, ulong, float, double
617                                 //
618                                 if (target_type == TypeManager.int64_type)
619                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
620                                 if (target_type == TypeManager.uint64_type)
621                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
622                                 if (target_type == TypeManager.double_type)
623                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
624                                                                OpCodes.Conv_R8);
625                                 if (target_type == TypeManager.float_type)
626                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
627                                                                OpCodes.Conv_R4);
628                                 if (target_type == TypeManager.decimal_type)
629                                         return InternalTypeConstructor (ec, expr, target_type);
630                         } else if ((expr_type == TypeManager.uint64_type) ||
631                                    (expr_type == TypeManager.int64_type)){
632                                 //
633                                 // From long/ulong to float, double
634                                 //
635                                 if (target_type == TypeManager.double_type)
636                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
637                                                                OpCodes.Conv_R8);
638                                 if (target_type == TypeManager.float_type)
639                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
640                                                                OpCodes.Conv_R4);        
641                                 if (target_type == TypeManager.decimal_type)
642                                         return InternalTypeConstructor (ec, expr, target_type);
643                         } else if (expr_type == TypeManager.char_type){
644                                 //
645                                 // From char to ushort, int, uint, long, ulong, float, double
646                                 // 
647                                 if ((target_type == TypeManager.ushort_type) ||
648                                     (target_type == TypeManager.int32_type) ||
649                                     (target_type == TypeManager.uint32_type))
650                                         return new EmptyCast (expr, target_type);
651                                 if (target_type == TypeManager.uint64_type)
652                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
653                                 if (target_type == TypeManager.int64_type)
654                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
655                                 if (target_type == TypeManager.float_type)
656                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
657                                 if (target_type == TypeManager.double_type)
658                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
659                                 if (target_type == TypeManager.decimal_type)
660                                         return InternalTypeConstructor (ec, expr, target_type);
661                         } else if (expr_type == TypeManager.float_type){
662                                 //
663                                 // float to double
664                                 //
665                                 if (target_type == TypeManager.double_type)
666                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
667                         }
668
669                         return null;
670                 }
671
672                 // <summary>
673                 //  Determines if a standard implicit conversion exists from
674                 //  expr_type to target_type
675                 // </summary>
676                 public static bool StandardConversionExists (Type expr_type, Type target_type)
677                 {
678                         if (expr_type == target_type)
679                                 return true;
680
681                         // First numeric conversions 
682                         
683                         if (expr_type == TypeManager.sbyte_type){
684                                 //
685                                 // From sbyte to short, int, long, float, double.
686                                 //
687                                 if ((target_type == TypeManager.int32_type) || 
688                                     (target_type == TypeManager.int64_type) ||
689                                     (target_type == TypeManager.double_type) ||
690                                     (target_type == TypeManager.float_type)  ||
691                                     (target_type == TypeManager.short_type) ||
692                                     (target_type == TypeManager.decimal_type))
693                                         return true;
694                                 
695                         } else if (expr_type == TypeManager.byte_type){
696                                 //
697                                 // From byte to short, ushort, int, uint, long, ulong, float, double
698                                 // 
699                                 if ((target_type == TypeManager.short_type) ||
700                                     (target_type == TypeManager.ushort_type) ||
701                                     (target_type == TypeManager.int32_type) ||
702                                     (target_type == TypeManager.uint32_type) ||
703                                     (target_type == TypeManager.uint64_type) ||
704                                     (target_type == TypeManager.int64_type) ||
705                                     (target_type == TypeManager.float_type) ||
706                                     (target_type == TypeManager.double_type) ||
707                                     (target_type == TypeManager.decimal_type))
708                                         return true;
709         
710                         } else if (expr_type == TypeManager.short_type){
711                                 //
712                                 // From short to int, long, float, double
713                                 // 
714                                 if ((target_type == TypeManager.int32_type) ||
715                                     (target_type == TypeManager.int64_type) ||
716                                     (target_type == TypeManager.double_type) ||
717                                     (target_type == TypeManager.float_type) ||
718                                     (target_type == TypeManager.decimal_type))
719                                         return true;
720                                         
721                         } else if (expr_type == TypeManager.ushort_type){
722                                 //
723                                 // From ushort to int, uint, long, ulong, float, double
724                                 //
725                                 if ((target_type == TypeManager.uint32_type) ||
726                                     (target_type == TypeManager.uint64_type) ||
727                                     (target_type == TypeManager.int32_type) ||
728                                     (target_type == TypeManager.int64_type) ||
729                                     (target_type == TypeManager.double_type) ||
730                                     (target_type == TypeManager.float_type) ||
731                                     (target_type == TypeManager.decimal_type))
732                                         return true;
733                                     
734                         } else if (expr_type == TypeManager.int32_type){
735                                 //
736                                 // From int to long, float, double
737                                 //
738                                 if ((target_type == TypeManager.int64_type) ||
739                                     (target_type == TypeManager.double_type) ||
740                                     (target_type == TypeManager.float_type) ||
741                                     (target_type == TypeManager.decimal_type))
742                                         return true;
743                                         
744                         } else if (expr_type == TypeManager.uint32_type){
745                                 //
746                                 // From uint to long, ulong, float, double
747                                 //
748                                 if ((target_type == TypeManager.int64_type) ||
749                                     (target_type == TypeManager.uint64_type) ||
750                                     (target_type == TypeManager.double_type) ||
751                                     (target_type == TypeManager.float_type) ||
752                                     (target_type == TypeManager.decimal_type))
753                                         return true;
754                                         
755                         } else if ((expr_type == TypeManager.uint64_type) ||
756                                    (expr_type == TypeManager.int64_type)) {
757                                 //
758                                 // From long/ulong to float, double
759                                 //
760                                 if ((target_type == TypeManager.double_type) ||
761                                     (target_type == TypeManager.float_type) ||
762                                     (target_type == TypeManager.decimal_type))
763                                         return true;
764                                     
765                         } else if (expr_type == TypeManager.char_type){
766                                 //
767                                 // From char to ushort, int, uint, long, ulong, float, double
768                                 // 
769                                 if ((target_type == TypeManager.ushort_type) ||
770                                     (target_type == TypeManager.int32_type) ||
771                                     (target_type == TypeManager.uint32_type) ||
772                                     (target_type == TypeManager.uint64_type) ||
773                                     (target_type == TypeManager.int64_type) ||
774                                     (target_type == TypeManager.float_type) ||
775                                     (target_type == TypeManager.double_type) ||
776                                     (target_type == TypeManager.decimal_type))
777                                         return true;
778
779                         } else if (expr_type == TypeManager.float_type){
780                                 //
781                                 // float to double
782                                 //
783                                 if (target_type == TypeManager.double_type)
784                                         return true;
785                         }       
786                         
787                         // Next reference conversions
788
789                         if (target_type == TypeManager.object_type) {
790                                 if ((expr_type.IsClass) ||
791                                     (expr_type.IsValueType))
792                                         return true;
793                                 
794                         } else if (expr_type.IsSubclassOf (target_type)) {
795                                 return true;
796                                 
797                         } else {
798                                 // from any class-type S to any interface-type T.
799                                 if (expr_type.IsClass && target_type.IsInterface)
800                                         return true;
801                                 
802                                 // from any interface type S to interface-type T.
803                                 // FIXME : Is it right to use IsAssignableFrom ?
804                                 if (expr_type.IsInterface && target_type.IsInterface)
805                                         if (target_type.IsAssignableFrom (expr_type))
806                                                 return true;
807                                 
808                                 // from an array-type S to an array-type of type T
809                                 if (expr_type.IsArray && target_type.IsArray) {
810                                         if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
811                                                 
812                                                 Type expr_element_type = expr_type.GetElementType ();
813                                                 Type target_element_type = target_type.GetElementType ();
814                                                 
815                                                 if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
816                                                         if (StandardConversionExists (expr_element_type,
817                                                                                       target_element_type))
818                                                                 return true;
819                                         }
820                                 }
821                                 
822                                 // from an array-type to System.Array
823                                 if (expr_type.IsArray && target_type.IsAssignableFrom (expr_type))
824                                         return true;
825                                 
826                                 // from any delegate type to System.Delegate
827                                 if (expr_type.IsSubclassOf (TypeManager.delegate_type) &&
828                                     target_type == TypeManager.delegate_type)
829                                         if (target_type.IsAssignableFrom (expr_type))
830                                                 return true;
831                                         
832                                 // from any array-type or delegate type into System.ICloneable.
833                                 if (expr_type.IsArray || expr_type.IsSubclassOf (TypeManager.delegate_type))
834                                         if (target_type == TypeManager.icloneable_type)
835                                                 return true;
836                                 
837                                 // from the null type to any reference-type.
838                                 // FIXME : How do we do this ?
839
840                         }
841
842                         return false;
843                 }
844                 
845                 // <summary>
846                 //  Finds "most encompassed type" according to the spec (13.4.2)
847                 //  amongst the methods in the MethodGroupExpr which convert from a
848                 //  type encompassing source_type
849                 // </summary>
850                 static Type FindMostEncompassedType (MethodGroupExpr me, Type source_type)
851                 {
852                         Type best = null;
853                         
854                         for (int i = me.Methods.Length; i > 0; ) {
855                                 i--;
856
857                                 MethodBase mb = me.Methods [i];
858                                 ParameterData pd = Invocation.GetParameterData (mb);
859                                 Type param_type = pd.ParameterType (0);
860
861                                 if (StandardConversionExists (source_type, param_type)) {
862                                         if (best == null)
863                                                 best = param_type;
864                                         
865                                         if (StandardConversionExists (param_type, best))
866                                                 best = param_type;
867                                 }
868                         }
869
870                         return best;
871                 }
872                 
873                 // <summary>
874                 //  Finds "most encompassing type" according to the spec (13.4.2)
875                 //  amongst the methods in the MethodGroupExpr which convert to a
876                 //  type encompassed by target_type
877                 // </summary>
878                 static Type FindMostEncompassingType (MethodGroupExpr me, Type target)
879                 {
880                         Type best = null;
881                         
882                         for (int i = me.Methods.Length; i > 0; ) {
883                                 i--;
884                                 
885                                 MethodInfo mi = (MethodInfo) me.Methods [i];
886                                 Type ret_type = mi.ReturnType;
887                                 
888                                 if (StandardConversionExists (ret_type, target)) {
889                                         if (best == null)
890                                                 best = ret_type;
891
892                                         if (!StandardConversionExists (ret_type, best))
893                                                 best = ret_type;
894                                 }
895                                 
896                         }
897                         
898                         return best;
899
900                 }
901                 
902
903                 // <summary>
904                 //  User-defined Implicit conversions
905                 // </summary>
906                 static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
907                                                                  Type target, Location loc)
908                 {
909                         return UserDefinedConversion (ec, source, target, loc, false);
910                 }
911
912                 // <summary>
913                 //  User-defined Explicit conversions
914                 // </summary>
915                 static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
916                                                                  Type target, Location loc)
917                 {
918                         return UserDefinedConversion (ec, source, target, loc, true);
919                 }
920                 
921                 // <summary>
922                 //   User-defined conversions
923                 // </summary>
924                 static public Expression UserDefinedConversion (EmitContext ec, Expression source,
925                                                                 Type target, Location loc,
926                                                                 bool look_for_explicit)
927                 {
928                         Expression mg1 = null, mg2 = null, mg3 = null, mg4 = null;
929                         Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null;
930                         Expression e;
931                         MethodBase method = null;
932                         Type source_type = source.Type;
933
934                         string op_name;
935                         
936                         // If we have a boolean type, we need to check for the True operator
937
938                         // FIXME : How does the False operator come into the picture ?
939                         // FIXME : This doesn't look complete and very correct !
940                         if (target == TypeManager.bool_type)
941                                 op_name = "op_True";
942                         else
943                                 op_name = "op_Implicit";
944                         
945                         mg1 = MemberLookup (ec, source_type, op_name, false, loc);
946
947                         if (source_type.BaseType != null)
948                                 mg2 = MemberLookup (ec, source_type.BaseType, op_name, false, loc);
949                         
950                         mg3 = MemberLookup (ec, target, op_name, false, loc);
951
952                         if (target.BaseType != null)
953                                 mg4 = MemberLookup (ec, target.BaseType, op_name, false, loc);
954
955                         MethodGroupExpr union1 = Invocation.MakeUnionSet (mg1, mg2);
956                         MethodGroupExpr union2 = Invocation.MakeUnionSet (mg3, mg4);
957
958                         MethodGroupExpr union3 = Invocation.MakeUnionSet (union1, union2);
959
960                         MethodGroupExpr union4 = null;
961
962                         if (look_for_explicit) {
963
964                                 op_name = "op_Explicit";
965                                 
966                                 mg5 = MemberLookup (ec, source_type, op_name, false, loc);
967
968                                 if (source_type.BaseType != null)
969                                         mg6 = MemberLookup (ec, source_type.BaseType, op_name, false, loc);
970                                 
971                                 mg7 = MemberLookup (ec, target, op_name, false, loc);
972                                 
973                                 if (target.BaseType != null)
974                                         mg8 = MemberLookup (ec, target.BaseType, op_name, false, loc);
975                                 
976                                 MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6);
977                                 MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8);
978
979                                 union4 = Invocation.MakeUnionSet (union5, union6);
980                         }
981                         
982                         MethodGroupExpr union = Invocation.MakeUnionSet (union3, union4);
983
984                         if (union != null) {
985
986                                 Type most_specific_source, most_specific_target;
987
988                                 most_specific_source = FindMostEncompassedType (union, source_type);
989                                 if (most_specific_source == null)
990                                         return null;
991
992                                 most_specific_target = FindMostEncompassingType (union, target);
993                                 if (most_specific_target == null) 
994                                         return null;
995                                 
996                                 int count = 0;
997                                 
998                                 for (int i = union.Methods.Length; i > 0;) {
999                                         i--;
1000
1001                                         MethodBase mb = union.Methods [i];
1002                                         ParameterData pd = Invocation.GetParameterData (mb);
1003                                         MethodInfo mi = (MethodInfo) union.Methods [i];
1004
1005                                         if (pd.ParameterType (0) == most_specific_source &&
1006                                             mi.ReturnType == most_specific_target) {
1007                                                 method = mb;
1008                                                 count++;
1009                                         }
1010                                 }
1011
1012                                 if (method == null || count > 1) {
1013                                         Report.Error (-11, loc, "Ambiguous user defined conversion");
1014                                         return null;
1015                                 }
1016                                 
1017                                 //
1018                                 // This will do the conversion to the best match that we
1019                                 // found.  Now we need to perform an implict standard conversion
1020                                 // if the best match was not the type that we were requested
1021                                 // by target.
1022                                 //
1023                                 if (look_for_explicit)
1024                                         source = ConvertExplicitStandard (ec, source, most_specific_source, loc);
1025                                 else
1026                                         source = ConvertImplicitStandard (ec, source,
1027                                                                           most_specific_source, loc);
1028
1029                                 if (source == null)
1030                                         return null;
1031                                 
1032                                 e =  new UserCast ((MethodInfo) method, source);
1033                                 
1034                                 if (e.Type != target){
1035                                         if (!look_for_explicit)
1036                                                 e = ConvertImplicitStandard (ec, e, target, loc);
1037                                         else
1038                                                 e = ConvertExplicitStandard (ec, e, target, loc);
1039
1040                                         return e;
1041                                 } else
1042                                         return e;
1043                         }
1044                         
1045                         return null;
1046                 }
1047                 
1048                 // <summary>
1049                 //   Converts implicitly the resolved expression `expr' into the
1050                 //   `target_type'.  It returns a new expression that can be used
1051                 //   in a context that expects a `target_type'. 
1052                 // </summary>
1053                 static public Expression ConvertImplicit (EmitContext ec, Expression expr,
1054                                                           Type target_type, Location loc)
1055                 {
1056                         Type expr_type = expr.Type;
1057                         Expression e;
1058
1059                         if (expr_type == target_type)
1060                                 return expr;
1061
1062                         e = ImplicitNumericConversion (ec, expr, target_type, loc);
1063                         if (e != null)
1064                                 return e;
1065
1066                         e = ImplicitReferenceConversion (expr, target_type);
1067                         if (e != null)
1068                                 return e;
1069
1070                         e = ImplicitUserConversion (ec, expr, target_type, loc);
1071                         if (e != null)
1072                                 return e;
1073
1074                         if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
1075                                 IntLiteral i = (IntLiteral) expr;
1076
1077                                 if (i.Value == 0)
1078                                         return new EmptyCast (expr, target_type);
1079                         }
1080
1081                         return null;
1082                 }
1083
1084                 
1085                 // <summary>
1086                 //   Attempts to apply the `Standard Implicit
1087                 //   Conversion' rules to the expression `expr' into
1088                 //   the `target_type'.  It returns a new expression
1089                 //   that can be used in a context that expects a
1090                 //   `target_type'.
1091                 //
1092                 //   This is different from `ConvertImplicit' in that the
1093                 //   user defined implicit conversions are excluded. 
1094                 // </summary>
1095                 static public Expression ConvertImplicitStandard (EmitContext ec, Expression expr,
1096                                                                   Type target_type, Location loc)
1097                 {
1098                         Type expr_type = expr.Type;
1099                         Expression e;
1100
1101                         if (expr_type == target_type)
1102                                 return expr;
1103
1104                         e = ImplicitNumericConversion (ec, expr, target_type, loc);
1105                         if (e != null)
1106                                 return e;
1107
1108                         e = ImplicitReferenceConversion (expr, target_type);
1109                         if (e != null)
1110                                 return e;
1111
1112                         if (target_type.IsSubclassOf (TypeManager.enum_type) && expr is IntLiteral){
1113                                 IntLiteral i = (IntLiteral) expr;
1114
1115                                 if (i.Value == 0)
1116                                         return new EmptyCast (expr, target_type);
1117                         }
1118                         return null;
1119                 }
1120                 // <summary>
1121                 //   Attemps to perform an implict constant conversion of the IntLiteral
1122                 //   into a different data type using casts (See Implicit Constant
1123                 //   Expression Conversions)
1124                 // </summary>
1125                 static protected Expression TryImplicitIntConversion (Type target_type, IntLiteral il)
1126                 {
1127                         int value = il.Value;
1128                         
1129                         if (target_type == TypeManager.sbyte_type){
1130                                 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1131                                         return il;
1132                         } else if (target_type == TypeManager.byte_type){
1133                                 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
1134                                         return il;
1135                         } else if (target_type == TypeManager.short_type){
1136                                 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1137                                         return il;
1138                         } else if (target_type == TypeManager.ushort_type){
1139                                 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1140                                         return il;
1141                         } else if (target_type == TypeManager.uint32_type){
1142                                 //
1143                                 // we can optimize this case: a positive int32
1144                                 // always fits on a uint32
1145                                 //
1146                                 if (value >= 0)
1147                                         return il;
1148                         } else if (target_type == TypeManager.uint64_type){
1149                                 //
1150                                 // we can optimize this case: a positive int32
1151                                 // always fits on a uint64.  But we need an opcode
1152                                 // to do it.
1153                                 //
1154                                 if (value >= 0)
1155                                         return new OpcodeCast (il, target_type, OpCodes.Conv_I8);
1156                         }
1157
1158                         return null;
1159                 }
1160
1161                 // <summary>
1162                 //   Attemptes to implicityly convert `target' into `type', using
1163                 //   ConvertImplicit.  If there is no implicit conversion, then
1164                 //   an error is signaled
1165                 // </summary>
1166                 static public Expression ConvertImplicitRequired (EmitContext ec, Expression target,
1167                                                                   Type type, Location loc)
1168                 {
1169                         Expression e;
1170                         
1171                         e = ConvertImplicit (ec, target, type, loc);
1172                         if (e != null)
1173                                 return e;
1174                         
1175                         string msg = "Can not convert implicitly from `"+
1176                                 TypeManager.CSharpName (target.Type) + "' to `" +
1177                                 TypeManager.CSharpName (type) + "'";
1178
1179                         Error (29, loc, msg);
1180
1181                         return null;
1182                 }
1183
1184                 // <summary>
1185                 //   Performs the explicit numeric conversions
1186                 // </summary>
1187                 static Expression ConvertNumericExplicit (EmitContext ec, Expression expr,
1188                                                           Type target_type)
1189                 {
1190                         Type expr_type = expr.Type;
1191                         
1192                         if (expr_type == TypeManager.sbyte_type){
1193                                 //
1194                                 // From sbyte to byte, ushort, uint, ulong, char
1195                                 //
1196                                 if (target_type == TypeManager.byte_type)
1197                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1198                                 if (target_type == TypeManager.ushort_type)
1199                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1200                                 if (target_type == TypeManager.uint32_type)
1201                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1202                                 if (target_type == TypeManager.uint64_type)
1203                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1204                                 if (target_type == TypeManager.char_type)
1205                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1206                         } else if (expr_type == TypeManager.byte_type){
1207                                 //
1208                                 // From byte to sbyte and char
1209                                 //
1210                                 if (target_type == TypeManager.sbyte_type)
1211                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1212                                 if (target_type == TypeManager.char_type)
1213                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1214                         } else if (expr_type == TypeManager.short_type){
1215                                 //
1216                                 // From short to sbyte, byte, ushort, uint, ulong, char
1217                                 //
1218                                 if (target_type == TypeManager.sbyte_type)
1219                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1220                                 if (target_type == TypeManager.byte_type)
1221                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1222                                 if (target_type == TypeManager.ushort_type)
1223                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1224                                 if (target_type == TypeManager.uint32_type)
1225                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1226                                 if (target_type == TypeManager.uint64_type)
1227                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1228                                 if (target_type == TypeManager.char_type)
1229                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1230                         } else if (expr_type == TypeManager.ushort_type){
1231                                 //
1232                                 // From ushort to sbyte, byte, short, char
1233                                 //
1234                                 if (target_type == TypeManager.sbyte_type)
1235                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1236                                 if (target_type == TypeManager.byte_type)
1237                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1238                                 if (target_type == TypeManager.short_type)
1239                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1240                                 if (target_type == TypeManager.char_type)
1241                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1242                         } else if (expr_type == TypeManager.int32_type){
1243                                 //
1244                                 // From int to sbyte, byte, short, ushort, uint, ulong, char
1245                                 //
1246                                 if (target_type == TypeManager.sbyte_type)
1247                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1248                                 if (target_type == TypeManager.byte_type)
1249                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1250                                 if (target_type == TypeManager.short_type)
1251                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1252                                 if (target_type == TypeManager.ushort_type)
1253                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1254                                 if (target_type == TypeManager.uint32_type)
1255                                         return new EmptyCast (expr, target_type);
1256                                 if (target_type == TypeManager.uint64_type)
1257                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1258                                 if (target_type == TypeManager.char_type)
1259                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1260                         } else if (expr_type == TypeManager.uint32_type){
1261                                 //
1262                                 // From uint to sbyte, byte, short, ushort, int, char
1263                                 //
1264                                 if (target_type == TypeManager.sbyte_type)
1265                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1266                                 if (target_type == TypeManager.byte_type)
1267                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1268                                 if (target_type == TypeManager.short_type)
1269                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1270                                 if (target_type == TypeManager.ushort_type)
1271                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1272                                 if (target_type == TypeManager.int32_type)
1273                                         return new EmptyCast (expr, target_type);
1274                                 if (target_type == TypeManager.char_type)
1275                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1276                         } else if (expr_type == TypeManager.int64_type){
1277                                 //
1278                                 // From long to sbyte, byte, short, ushort, int, uint, ulong, char
1279                                 //
1280                                 if (target_type == TypeManager.sbyte_type)
1281                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1282                                 if (target_type == TypeManager.byte_type)
1283                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1284                                 if (target_type == TypeManager.short_type)
1285                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1286                                 if (target_type == TypeManager.ushort_type)
1287                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1288                                 if (target_type == TypeManager.int32_type)
1289                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1290                                 if (target_type == TypeManager.uint32_type)
1291                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1292                                 if (target_type == TypeManager.uint64_type)
1293                                         return new EmptyCast (expr, target_type);
1294                                 if (target_type == TypeManager.char_type)
1295                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1296                         } else if (expr_type == TypeManager.uint64_type){
1297                                 //
1298                                 // From ulong to sbyte, byte, short, ushort, int, uint, long, char
1299                                 //
1300                                 if (target_type == TypeManager.sbyte_type)
1301                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1302                                 if (target_type == TypeManager.byte_type)
1303                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1304                                 if (target_type == TypeManager.short_type)
1305                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1306                                 if (target_type == TypeManager.ushort_type)
1307                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1308                                 if (target_type == TypeManager.int32_type)
1309                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1310                                 if (target_type == TypeManager.uint32_type)
1311                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1312                                 if (target_type == TypeManager.int64_type)
1313                                         return new EmptyCast (expr, target_type);
1314                                 if (target_type == TypeManager.char_type)
1315                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1316                         } else if (expr_type == TypeManager.char_type){
1317                                 //
1318                                 // From char to sbyte, byte, short
1319                                 //
1320                                 if (target_type == TypeManager.sbyte_type)
1321                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1322                                 if (target_type == TypeManager.byte_type)
1323                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1324                                 if (target_type == TypeManager.short_type)
1325                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1326                         } else if (expr_type == TypeManager.float_type){
1327                                 //
1328                                 // From float to sbyte, byte, short,
1329                                 // ushort, int, uint, long, ulong, char
1330                                 // or decimal
1331                                 //
1332                                 if (target_type == TypeManager.sbyte_type)
1333                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1334                                 if (target_type == TypeManager.byte_type)
1335                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1336                                 if (target_type == TypeManager.short_type)
1337                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1338                                 if (target_type == TypeManager.ushort_type)
1339                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1340                                 if (target_type == TypeManager.int32_type)
1341                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1342                                 if (target_type == TypeManager.uint32_type)
1343                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1344                                 if (target_type == TypeManager.int64_type)
1345                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1346                                 if (target_type == TypeManager.uint64_type)
1347                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1348                                 if (target_type == TypeManager.char_type)
1349                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1350                                 if (target_type == TypeManager.decimal_type)
1351                                         return InternalTypeConstructor (ec, expr, target_type);
1352                         } else if (expr_type == TypeManager.double_type){
1353                                 //
1354                                 // From double to byte, byte, short,
1355                                 // ushort, int, uint, long, ulong,
1356                                 // char, float or decimal
1357                                 //
1358                                 if (target_type == TypeManager.sbyte_type)
1359                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I1);
1360                                 if (target_type == TypeManager.byte_type)
1361                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U1);
1362                                 if (target_type == TypeManager.short_type)
1363                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
1364                                 if (target_type == TypeManager.ushort_type)
1365                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1366                                 if (target_type == TypeManager.int32_type)
1367                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
1368                                 if (target_type == TypeManager.uint32_type)
1369                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U4);
1370                                 if (target_type == TypeManager.int64_type)
1371                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
1372                                 if (target_type == TypeManager.uint64_type)
1373                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
1374                                 if (target_type == TypeManager.char_type)
1375                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_U2);
1376                                 if (target_type == TypeManager.float_type)
1377                                         return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
1378                                 if (target_type == TypeManager.decimal_type)
1379                                         return InternalTypeConstructor (ec, expr, target_type);
1380                         } 
1381
1382                         // decimal is taken care of by the op_Explicit methods.
1383
1384                         return null;
1385                 }
1386
1387                 // <summary>
1388                 //  Returns whether an explicit reference conversion can be performed
1389                 //  from source_type to target_type
1390                 // </summary>
1391                 static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
1392                 {
1393                         bool target_is_value_type = target_type.IsValueType;
1394                         
1395                         if (source_type == target_type)
1396                                 return true;
1397                         
1398                         //
1399                         // From object to any reference type
1400                         //
1401                         if (source_type == TypeManager.object_type && !target_is_value_type)
1402                                 return true;
1403                                         
1404                         //
1405                         // From any class S to any class-type T, provided S is a base class of T
1406                         //
1407                         if (target_type.IsSubclassOf (source_type))
1408                                 return true;
1409
1410                         //
1411                         // From any interface type S to any interface T provided S is not derived from T
1412                         //
1413                         if (source_type.IsInterface && target_type.IsInterface){
1414                                 if (!target_type.IsSubclassOf (source_type))
1415                                         return true;
1416                         }
1417                             
1418                         //
1419                         // From any class type S to any interface T, provides S is not sealed
1420                         // and provided S does not implement T.
1421                         //
1422                         if (target_type.IsInterface && !source_type.IsSealed &&
1423                             !target_type.IsAssignableFrom (source_type))
1424                                 return true;
1425
1426                         //
1427                         // From any interface-type S to to any class type T, provided T is not
1428                         // sealed, or provided T implements S.
1429                         //
1430                         if (source_type.IsInterface &&
1431                             (!target_type.IsSealed || source_type.IsAssignableFrom (target_type)))
1432                                 return true;
1433
1434                         // From an array type S with an element type Se to an array type T with an 
1435                         // element type Te provided all the following are true:
1436                         //     * S and T differe only in element type, in other words, S and T
1437                         //       have the same number of dimensions.
1438                         //     * Both Se and Te are reference types
1439                         //     * An explicit referenc conversions exist from Se to Te
1440                         //
1441                         if (source_type.IsArray && target_type.IsArray) {
1442                                 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1443                                         
1444                                         Type source_element_type = source_type.GetElementType ();
1445                                         Type target_element_type = target_type.GetElementType ();
1446                                         
1447                                         if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1448                                                 if (ExplicitReferenceConversionExists (source_element_type,
1449                                                                                        target_element_type))
1450                                                         return true;
1451                                 }
1452                         }
1453                         
1454
1455                         // From System.Array to any array-type
1456                         if (source_type == TypeManager.array_type &&
1457                             target_type.IsSubclassOf (TypeManager.array_type)){
1458                                 return true;
1459                         }
1460
1461                         //
1462                         // From System delegate to any delegate-type
1463                         //
1464                         if (source_type == TypeManager.delegate_type &&
1465                             target_type.IsSubclassOf (TypeManager.delegate_type))
1466                                 return true;
1467
1468                         //
1469                         // From ICloneable to Array or Delegate types
1470                         //
1471                         if (source_type == TypeManager.icloneable_type &&
1472                             (target_type == TypeManager.array_type ||
1473                              target_type == TypeManager.delegate_type))
1474                                 return true;
1475                         
1476                         return false;
1477                 }
1478
1479                 // <summary>
1480                 //   Implements Explicit Reference conversions
1481                 // </summary>
1482                 static Expression ConvertReferenceExplicit (Expression source, Type target_type)
1483                 {
1484                         Type source_type = source.Type;
1485                         bool target_is_value_type = target_type.IsValueType;
1486                         
1487                         //
1488                         // From object to any reference type
1489                         //
1490                         if (source_type == TypeManager.object_type && !target_is_value_type)
1491                                 return new ClassCast (source, target_type);
1492
1493
1494                         //
1495                         // From any class S to any class-type T, provided S is a base class of T
1496                         //
1497                         if (target_type.IsSubclassOf (source_type))
1498                                 return new ClassCast (source, target_type);
1499
1500                         //
1501                         // From any interface type S to any interface T provided S is not derived from T
1502                         //
1503                         if (source_type.IsInterface && target_type.IsInterface){
1504
1505                                 Type [] ifaces = source_type.GetInterfaces ();
1506
1507                                 if (TypeManager.ImplementsInterface (source_type, target_type))
1508                                         return null;
1509                                 else
1510                                         return new ClassCast (source, target_type);
1511                         }
1512                             
1513                         //
1514                         // From any class type S to any interface T, provides S is not sealed
1515                         // and provided S does not implement T.
1516                         //
1517                         if (target_type.IsInterface && !source_type.IsSealed) {
1518                                 
1519                                 if (TypeManager.ImplementsInterface (source_type, target_type))
1520                                         return null;
1521                                 else
1522                                         return new ClassCast (source, target_type);
1523                                 
1524                         }
1525
1526                         //
1527                         // From any interface-type S to to any class type T, provided T is not
1528                         // sealed, or provided T implements S.
1529                         //
1530                         if (source_type.IsInterface) {
1531
1532                                 if (target_type.IsSealed)
1533                                         return null;
1534                                 
1535                                 if (TypeManager.ImplementsInterface (target_type, source_type))
1536                                         return new ClassCast (source, target_type);
1537                                 else
1538                                         return null;
1539                         }
1540                         
1541                         // From an array type S with an element type Se to an array type T with an 
1542                         // element type Te provided all the following are true:
1543                         //     * S and T differe only in element type, in other words, S and T
1544                         //       have the same number of dimensions.
1545                         //     * Both Se and Te are reference types
1546                         //     * An explicit referenc conversions exist from Se to Te
1547                         //
1548                         if (source_type.IsArray && target_type.IsArray) {
1549                                 if (source_type.GetArrayRank () == target_type.GetArrayRank ()) {
1550                                         
1551                                         Type source_element_type = source_type.GetElementType ();
1552                                         Type target_element_type = target_type.GetElementType ();
1553                                         
1554                                         if (!source_element_type.IsValueType && !target_element_type.IsValueType)
1555                                                 if (ExplicitReferenceConversionExists (source_element_type,
1556                                                                                        target_element_type))
1557                                                         return new ClassCast (source, target_type);
1558                                 }
1559                         }
1560                         
1561
1562                         // From System.Array to any array-type
1563                         if (source_type == TypeManager.array_type &&
1564                             target_type.IsSubclassOf (TypeManager.array_type)){
1565                                 return new ClassCast (source, target_type);
1566                         }
1567
1568                         //
1569                         // From System delegate to any delegate-type
1570                         //
1571                         if (source_type == TypeManager.delegate_type &&
1572                             target_type.IsSubclassOf (TypeManager.delegate_type))
1573                                 return new ClassCast (source, target_type);
1574
1575                         //
1576                         // From ICloneable to Array or Delegate types
1577                         //
1578                         if (source_type == TypeManager.icloneable_type &&
1579                             (target_type == TypeManager.array_type ||
1580                              target_type == TypeManager.delegate_type))
1581                                 return new ClassCast (source, target_type);
1582                         
1583                         return null;
1584                 }
1585                 
1586                 // <summary>
1587                 //   Performs an explicit conversion of the expression `expr' whose
1588                 //   type is expr.Type to `target_type'.
1589                 // </summary>
1590                 static public Expression ConvertExplicit (EmitContext ec, Expression expr,
1591                                                           Type target_type, Location loc)
1592                 {
1593                         Expression ne = ConvertImplicitStandard (ec, expr, target_type, loc);
1594
1595                         if (ne != null)
1596                                 return ne;
1597
1598                         ne = ConvertNumericExplicit (ec, expr, target_type);
1599                         if (ne != null)
1600                                 return ne;
1601
1602                         ne = ConvertReferenceExplicit (expr, target_type);
1603                         if (ne != null)
1604                                 return ne;
1605
1606                         ne = ExplicitUserConversion (ec, expr, target_type, loc);
1607                         if (ne != null)
1608                                 return ne;
1609
1610                         Report.Error (30, loc, "Cannot convert type '" + TypeManager.CSharpName (expr.Type) + "' to '"
1611                                       + TypeManager.CSharpName (target_type) + "'");
1612                         return null;
1613                 }
1614
1615                 // <summary>
1616                 //   Same as ConverExplicit, only it doesn't include user defined conversions
1617                 // </summary>
1618                 static public Expression ConvertExplicitStandard (EmitContext ec, Expression expr,
1619                                                                   Type target_type, Location l)
1620                 {
1621                         Expression ne = ConvertImplicitStandard (ec, expr, target_type, l);
1622
1623                         if (ne != null)
1624                                 return ne;
1625
1626                         ne = ConvertNumericExplicit (ec, expr, target_type);
1627                         if (ne != null)
1628                                 return ne;
1629
1630                         ne = ConvertReferenceExplicit (expr, target_type);
1631                         if (ne != null)
1632                                 return ne;
1633
1634                         Report.Error (30, l, "Cannot convert type '" +
1635                                       TypeManager.CSharpName (expr.Type) + "' to '" + 
1636                                       TypeManager.CSharpName (target_type) + "'");
1637                         return null;
1638                 }
1639
1640                 static string ExprClassName (ExprClass c)
1641                 {
1642                         switch (c){
1643                         case ExprClass.Invalid:
1644                                 return "Invalid";
1645                         case ExprClass.Value:
1646                                 return "value";
1647                         case ExprClass.Variable:
1648                                 return "variable";
1649                         case ExprClass.Namespace:
1650                                 return "namespace";
1651                         case ExprClass.Type:
1652                                 return "type";
1653                         case ExprClass.MethodGroup:
1654                                 return "method group";
1655                         case ExprClass.PropertyAccess:
1656                                 return "property access";
1657                         case ExprClass.EventAccess:
1658                                 return "event access";
1659                         case ExprClass.IndexerAccess:
1660                                 return "indexer access";
1661                         case ExprClass.Nothing:
1662                                 return "null";
1663                         }
1664                         throw new Exception ("Should not happen");
1665                 }
1666                 
1667                 // <summary>
1668                 //   Reports that we were expecting `expr' to be of class `expected'
1669                 // </summary>
1670                 protected void report118 (Location loc, Expression expr, string expected)
1671                 {
1672                         string kind = "Unknown";
1673                         
1674                         if (expr != null)
1675                                 kind = ExprClassName (expr.ExprClass);
1676
1677                         Error (118, loc, "Expression denotes a '" + kind +
1678                                "' where an " + expected + " was expected");
1679                 }
1680         }
1681
1682         // <summary>
1683         //   This is just a base class for expressions that can
1684         //   appear on statements (invocations, object creation,
1685         //   assignments, post/pre increment and decrement).  The idea
1686         //   being that they would support an extra Emition interface that
1687         //   does not leave a result on the stack.
1688         // </summary>
1689
1690         public abstract class ExpressionStatement : Expression {
1691
1692                 // <summary>
1693                 //   Requests the expression to be emitted in a `statement'
1694                 //   context.  This means that no new value is left on the
1695                 //   stack after invoking this method (constrasted with
1696                 //   Emit that will always leave a value on the stack).
1697                 // </summary>
1698                 public abstract void EmitStatement (EmitContext ec);
1699         }
1700
1701         // <summary>
1702         //   This kind of cast is used to encapsulate the child
1703         //   whose type is child.Type into an expression that is
1704         //   reported to return "return_type".  This is used to encapsulate
1705         //   expressions which have compatible types, but need to be dealt
1706         //   at higher levels with.
1707         //
1708         //   For example, a "byte" expression could be encapsulated in one
1709         //   of these as an "unsigned int".  The type for the expression
1710         //   would be "unsigned int".
1711         //
1712         // </summary>
1713         
1714         public class EmptyCast : Expression {
1715                 protected Expression child;
1716
1717                 public EmptyCast (Expression child, Type return_type)
1718                 {
1719                         ExprClass = child.ExprClass;
1720                         type = return_type;
1721                         this.child = child;
1722                 }
1723
1724                 public override Expression DoResolve (EmitContext ec)
1725                 {
1726                         // This should never be invoked, we are born in fully
1727                         // initialized state.
1728
1729                         return this;
1730                 }
1731
1732                 public override void Emit (EmitContext ec)
1733                 {
1734                         child.Emit (ec);
1735                 }                       
1736         }
1737
1738         // <summary>
1739         //   This kind of cast is used to encapsulate Value Types in objects.
1740         //
1741         //   The effect of it is to box the value type emitted by the previous
1742         //   operation.
1743         // </summary>
1744         public class BoxedCast : EmptyCast {
1745
1746                 public BoxedCast (Expression expr)
1747                         : base (expr, TypeManager.object_type)
1748                 {
1749                 }
1750
1751                 public override Expression DoResolve (EmitContext ec)
1752                 {
1753                         // This should never be invoked, we are born in fully
1754                         // initialized state.
1755
1756                         return this;
1757                 }
1758
1759                 public override void Emit (EmitContext ec)
1760                 {
1761                         base.Emit (ec);
1762                         ec.ig.Emit (OpCodes.Box, child.Type);
1763                 }
1764         }
1765
1766         // <summary>
1767         //   This kind of cast is used to encapsulate a child expression
1768         //   that can be trivially converted to a target type using one or 
1769         //   two opcodes.  The opcodes are passed as arguments.
1770         // </summary>
1771         public class OpcodeCast : EmptyCast {
1772                 OpCode op, op2;
1773                 bool second_valid;
1774                 
1775                 public OpcodeCast (Expression child, Type return_type, OpCode op)
1776                         : base (child, return_type)
1777                         
1778                 {
1779                         this.op = op;
1780                         second_valid = false;
1781                 }
1782
1783                 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
1784                         : base (child, return_type)
1785                         
1786                 {
1787                         this.op = op;
1788                         this.op2 = op2;
1789                         second_valid = true;
1790                 }
1791
1792                 public override Expression DoResolve (EmitContext ec)
1793                 {
1794                         // This should never be invoked, we are born in fully
1795                         // initialized state.
1796
1797                         return this;
1798                 }
1799
1800                 public override void Emit (EmitContext ec)
1801                 {
1802                         base.Emit (ec);
1803                         ec.ig.Emit (op);
1804
1805                         if (second_valid)
1806                                 ec.ig.Emit (op2);
1807                 }                       
1808                 
1809         }
1810
1811         // <summary>
1812         //   This kind of cast is used to encapsulate a child and cast it
1813         //   to the class requested
1814         // </summary>
1815         public class ClassCast : EmptyCast {
1816                 public ClassCast (Expression child, Type return_type)
1817                         : base (child, return_type)
1818                         
1819                 {
1820                 }
1821
1822                 public override Expression DoResolve (EmitContext ec)
1823                 {
1824                         // This should never be invoked, we are born in fully
1825                         // initialized state.
1826
1827                         return this;
1828                 }
1829
1830                 public override void Emit (EmitContext ec)
1831                 {
1832                         base.Emit (ec);
1833
1834                         ec.ig.Emit (OpCodes.Castclass, type);
1835                 }                       
1836                 
1837         }
1838         
1839         // <summary>
1840         //   Unary expressions.  
1841         // </summary>
1842         //
1843         // <remarks>
1844         //   Unary implements unary expressions.   It derives from
1845         //   ExpressionStatement becuase the pre/post increment/decrement
1846         //   operators can be used in a statement context.
1847         // </remarks>
1848         public class Unary : ExpressionStatement {
1849                 public enum Operator {
1850                         UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
1851                         Indirection, AddressOf, PreIncrement,
1852                         PreDecrement, PostIncrement, PostDecrement 
1853                 }
1854
1855                 Operator   oper;
1856                 Expression expr;
1857                 ArrayList  Arguments;
1858                 MethodBase method;
1859                 Location   loc;
1860                 
1861                 public Unary (Operator op, Expression expr, Location loc)
1862                 {
1863                         this.oper = op;
1864                         this.expr = expr;
1865                         this.loc = loc;
1866                 }
1867
1868                 public Expression Expr {
1869                         get {
1870                                 return expr;
1871                         }
1872
1873                         set {
1874                                 expr = value;
1875                         }
1876                 }
1877
1878                 public Operator Oper {
1879                         get {
1880                                 return oper;
1881                         }
1882
1883                         set {
1884                                 oper = value;
1885                         }
1886                 }
1887
1888                 // <summary>
1889                 //   Returns a stringified representation of the Operator
1890                 // </summary>
1891                 string OperName ()
1892                 {
1893                         switch (oper){
1894                         case Operator.UnaryPlus:
1895                                 return "+";
1896                         case Operator.UnaryNegation:
1897                                 return "-";
1898                         case Operator.LogicalNot:
1899                                 return "!";
1900                         case Operator.OnesComplement:
1901                                 return "~";
1902                         case Operator.AddressOf:
1903                                 return "&";
1904                         case Operator.Indirection:
1905                                 return "*";
1906                         case Operator.PreIncrement : case Operator.PostIncrement :
1907                                 return "++";
1908                         case Operator.PreDecrement : case Operator.PostDecrement :
1909                                 return "--";
1910                         }
1911
1912                         return oper.ToString ();
1913                 }
1914
1915                 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1916                 {
1917                         if (expr.Type == target_type)
1918                                 return expr;
1919
1920                         return ConvertImplicit (ec, expr, target_type, new Location (-1));
1921                 }
1922
1923                 void error23 (Type t)
1924                 {
1925                         Report.Error (
1926                                 23, loc, "Operator " + OperName () +
1927                                 " cannot be applied to operand of type `" +
1928                                 TypeManager.CSharpName (t) + "'");
1929                 }
1930
1931                 // <summary>
1932                 //   Returns whether an object of type `t' can be incremented
1933                 //   or decremented with add/sub (ie, basically whether we can
1934                 //   use pre-post incr-decr operations on it, but it is not a
1935                 //   System.Decimal, which we test elsewhere)
1936                 // </summary>
1937                 static bool IsIncrementableNumber (Type t)
1938                 {
1939                         return (t == TypeManager.sbyte_type) ||
1940                                 (t == TypeManager.byte_type) ||
1941                                 (t == TypeManager.short_type) ||
1942                                 (t == TypeManager.ushort_type) ||
1943                                 (t == TypeManager.int32_type) ||
1944                                 (t == TypeManager.uint32_type) ||
1945                                 (t == TypeManager.int64_type) ||
1946                                 (t == TypeManager.uint64_type) ||
1947                                 (t == TypeManager.char_type) ||
1948                                 (t.IsSubclassOf (TypeManager.enum_type)) ||
1949                                 (t == TypeManager.float_type) ||
1950                                 (t == TypeManager.double_type);
1951                 }
1952                         
1953                 Expression ResolveOperator (EmitContext ec)
1954                 {
1955                         Type expr_type = expr.Type;
1956
1957                         //
1958                         // Step 1: Perform Operator Overload location
1959                         //
1960                         Expression mg;
1961                         string op_name;
1962                         
1963                         if (oper == Operator.PostIncrement || oper == Operator.PreIncrement)
1964                                 op_name = "op_Increment";
1965                         else if (oper == Operator.PostDecrement || oper == Operator.PreDecrement)
1966                                 op_name = "op_Decrement";
1967                         else
1968                                 op_name = "op_" + oper;
1969
1970                         mg = MemberLookup (ec, expr_type, op_name, false, loc);
1971                         
1972                         if (mg == null && expr_type.BaseType != null)
1973                                 mg = MemberLookup (ec, expr_type.BaseType, op_name, false, loc);
1974                         
1975                         if (mg != null) {
1976                                 Arguments = new ArrayList ();
1977                                 Arguments.Add (new Argument (expr, Argument.AType.Expression));
1978                                 
1979                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg,
1980                                                                      Arguments, loc);
1981                                 if (method != null) {
1982                                         MethodInfo mi = (MethodInfo) method;
1983                                         type = mi.ReturnType;
1984                                         return this;
1985                                 } else {
1986                                         error23 (expr_type);
1987                                         return null;
1988                                 }
1989                                         
1990                         }
1991
1992                         //
1993                         // Step 2: Default operations on CLI native types.
1994                         //
1995
1996                         // Only perform numeric promotions on:
1997                         // +, -, ++, --
1998
1999                         if (expr_type == null)
2000                                 return null;
2001                         
2002                         if (oper == Operator.LogicalNot){
2003                                 if (expr_type != TypeManager.bool_type) {
2004                                         error23 (expr.Type);
2005                                         return null;
2006                                 }
2007                                 
2008                                 type = TypeManager.bool_type;
2009                                 return this;
2010                         }
2011
2012                         if (oper == Operator.OnesComplement) {
2013                                 if (!((expr_type == TypeManager.int32_type) ||
2014                                       (expr_type == TypeManager.uint32_type) ||
2015                                       (expr_type == TypeManager.int64_type) ||
2016                                       (expr_type == TypeManager.uint64_type) ||
2017                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){
2018                                         error23 (expr.Type);
2019                                         return null;
2020                                 }
2021                                 type = expr_type;
2022                                 return this;
2023                         }
2024
2025                         if (oper == Operator.UnaryPlus) {
2026                                 //
2027                                 // A plus in front of something is just a no-op, so return the child.
2028                                 //
2029                                 return expr;
2030                         }
2031
2032                         //
2033                         // Deals with -literals
2034                         // int     operator- (int x)
2035                         // long    operator- (long x)
2036                         // float   operator- (float f)
2037                         // double  operator- (double d)
2038                         // decimal operator- (decimal d)
2039                         //
2040                         if (oper == Operator.UnaryNegation){
2041                                 //
2042                                 // Fold a "- Constant" into a negative constant
2043                                 //
2044                         
2045                                 Expression e = null;
2046
2047                                 //
2048                                 // Is this a constant? 
2049                                 //
2050                                 if (expr is IntLiteral)
2051                                         e = new IntLiteral (-((IntLiteral) expr).Value);
2052                                 else if (expr is LongLiteral)
2053                                         e = new LongLiteral (-((LongLiteral) expr).Value);
2054                                 else if (expr is FloatLiteral)
2055                                         e = new FloatLiteral (-((FloatLiteral) expr).Value);
2056                                 else if (expr is DoubleLiteral)
2057                                         e = new DoubleLiteral (-((DoubleLiteral) expr).Value);
2058                                 else if (expr is DecimalLiteral)
2059                                         e = new DecimalLiteral (-((DecimalLiteral) expr).Value);
2060                                 
2061                                 if (e != null){
2062                                         e = e.Resolve (ec);
2063                                         return e;
2064                                 }
2065
2066                                 //
2067                                 // Not a constant we can optimize, perform numeric 
2068                                 // promotions to int, long, double.
2069                                 //
2070                                 //
2071                                 // The following is inneficient, because we call
2072                                 // ConvertImplicit too many times.
2073                                 //
2074                                 // It is also not clear if we should convert to Float
2075                                 // or Double initially.
2076                                 //
2077                                 if (expr_type == TypeManager.uint32_type){
2078                                         //
2079                                         // FIXME: handle exception to this rule that
2080                                         // permits the int value -2147483648 (-2^31) to
2081                                         // bt written as a decimal interger literal
2082                                         //
2083                                         type = TypeManager.int64_type;
2084                                         expr = ConvertImplicit (ec, expr, type, loc);
2085                                         return this;
2086                                 }
2087
2088                                 if (expr_type == TypeManager.uint64_type){
2089                                         //
2090                                         // FIXME: Handle exception of `long value'
2091                                         // -92233720368547758087 (-2^63) to be written as
2092                                         // decimal integer literal.
2093                                         //
2094                                         error23 (expr_type);
2095                                         return null;
2096                                 }
2097
2098                                 e = ConvertImplicit (ec, expr, TypeManager.int32_type, loc);
2099                                 if (e != null){
2100                                         expr = e;
2101                                         type = e.Type;
2102                                         return this;
2103                                 } 
2104
2105                                 e = ConvertImplicit (ec, expr, TypeManager.int64_type, loc);
2106                                 if (e != null){
2107                                         expr = e;
2108                                         type = e.Type;
2109                                         return this;
2110                                 }
2111
2112                                 e = ConvertImplicit (ec, expr, TypeManager.double_type, loc);
2113                                 if (e != null){
2114                                         expr = e;
2115                                         type = e.Type;
2116                                         return this;
2117                                 }
2118
2119                                 error23 (expr_type);
2120                                 return null;
2121                         }
2122
2123                         //
2124                         // The operand of the prefix/postfix increment decrement operators
2125                         // should be an expression that is classified as a variable,
2126                         // a property access or an indexer access
2127                         //
2128                         if (oper == Operator.PreDecrement || oper == Operator.PreIncrement ||
2129                             oper == Operator.PostDecrement || oper == Operator.PostIncrement){
2130                                 if (expr.ExprClass == ExprClass.Variable){
2131                                         if (IsIncrementableNumber (expr_type) ||
2132                                             expr_type == TypeManager.decimal_type){
2133                                                 type = expr_type;
2134                                                 return this;
2135                                         }
2136                                 } else if (expr.ExprClass == ExprClass.IndexerAccess){
2137                                         //
2138                                         // FIXME: Verify that we have both get and set methods
2139                                         //
2140                                         throw new Exception ("Implement me");
2141                                 } else if (expr.ExprClass == ExprClass.PropertyAccess){
2142                                         PropertyExpr pe = (PropertyExpr) expr;
2143                                         
2144                                         if (pe.VerifyAssignable ())
2145                                                 return this;
2146                                         return null;
2147                                 } else {
2148                                         report118 (loc, expr, "variable, indexer or property access");
2149                                 }
2150                         }
2151
2152                         if (oper == Operator.AddressOf){
2153                                 if (expr.ExprClass != ExprClass.Variable){
2154                                         Error (211, "Cannot take the address of non-variables");
2155                                         return null;
2156                                 }
2157                                 type = Type.GetType (expr.Type.ToString () + "*");
2158                         }
2159                         
2160                         Error (187, "No such operator '" + OperName () + "' defined for type '" +
2161                                TypeManager.CSharpName (expr_type) + "'");
2162                         return null;
2163
2164                 }
2165
2166                 public override Expression DoResolve (EmitContext ec)
2167                 {
2168                         expr = expr.Resolve (ec);
2169                         
2170                         if (expr == null)
2171                                 return null;
2172
2173                         eclass = ExprClass.Value;
2174                         return ResolveOperator (ec);
2175                 }
2176
2177                 public override void Emit (EmitContext ec)
2178                 {
2179                         ILGenerator ig = ec.ig;
2180                         Type expr_type = expr.Type;
2181                         ExprClass eclass;
2182                         
2183                         if (method != null) {
2184
2185                                 // Note that operators are static anyway
2186                                 
2187                                 if (Arguments != null) 
2188                                         Invocation.EmitArguments (ec, method, Arguments);
2189
2190                                 //
2191                                 // Post increment/decrement operations need a copy at this
2192                                 // point.
2193                                 //
2194                                 if (oper == Operator.PostDecrement || oper == Operator.PostIncrement)
2195                                         ig.Emit (OpCodes.Dup);
2196                                 
2197
2198                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
2199
2200                                 //
2201                                 // Pre Increment and Decrement operators
2202                                 //
2203                                 if (oper == Operator.PreIncrement || oper == Operator.PreDecrement){
2204                                         ig.Emit (OpCodes.Dup);
2205                                 }
2206                                 
2207                                 //
2208                                 // Increment and Decrement should store the result
2209                                 //
2210                                 if (oper == Operator.PreDecrement || oper == Operator.PreIncrement ||
2211                                     oper == Operator.PostDecrement || oper == Operator.PostIncrement){
2212                                         ((IStackStore) expr).Store (ec);
2213                                 }
2214                                 return;
2215                         }
2216                         
2217                         switch (oper) {
2218                         case Operator.UnaryPlus:
2219                                 throw new Exception ("This should be caught by Resolve");
2220                                 
2221                         case Operator.UnaryNegation:
2222                                 expr.Emit (ec);
2223                                 ig.Emit (OpCodes.Neg);
2224                                 break;
2225                                 
2226                         case Operator.LogicalNot:
2227                                 expr.Emit (ec);
2228                                 ig.Emit (OpCodes.Ldc_I4_0);
2229                                 ig.Emit (OpCodes.Ceq);
2230                                 break;
2231                                 
2232                         case Operator.OnesComplement:
2233                                 expr.Emit (ec);
2234                                 ig.Emit (OpCodes.Not);
2235                                 break;
2236                                 
2237                         case Operator.AddressOf:
2238                                 ((IMemoryLocation)expr).AddressOf (ec);
2239                                 break;
2240                                 
2241                         case Operator.Indirection:
2242                                 throw new Exception ("Not implemented yet");
2243                                 
2244                         case Operator.PreIncrement:
2245                         case Operator.PreDecrement:
2246                                 if (expr.ExprClass == ExprClass.Variable){
2247                                         //
2248                                         // Resolve already verified that it is an "incrementable"
2249                                         // 
2250                                         expr.Emit (ec);
2251                                         ig.Emit (OpCodes.Ldc_I4_1);
2252                                         
2253                                         if (oper == Operator.PreDecrement)
2254                                                 ig.Emit (OpCodes.Sub);
2255                                         else
2256                                                 ig.Emit (OpCodes.Add);
2257                                         ig.Emit (OpCodes.Dup);
2258                                         ((IStackStore) expr).Store (ec);
2259                                 } else {
2260                                         throw new Exception ("Handle Indexers and Properties here");
2261                                 }
2262                                 break;
2263                                 
2264                         case Operator.PostIncrement:
2265                         case Operator.PostDecrement:
2266                                 eclass = expr.ExprClass;
2267                                 if (eclass == ExprClass.Variable){
2268                                         //
2269                                         // Resolve already verified that it is an "incrementable"
2270                                         // 
2271                                         expr.Emit (ec);
2272                                         ig.Emit (OpCodes.Dup);
2273                                         ig.Emit (OpCodes.Ldc_I4_1);
2274                                         
2275                                         if (oper == Operator.PostDecrement)
2276                                                 ig.Emit (OpCodes.Sub);
2277                                         else
2278                                                 ig.Emit (OpCodes.Add);
2279                                         ((IStackStore) expr).Store (ec);
2280                                 } else if (eclass == ExprClass.PropertyAccess){
2281                                         throw new Exception ("Handle Properties here");
2282                                 } else if (eclass == ExprClass.IndexerAccess) {
2283                                         throw new Exception ("Handle Indexers here");
2284                                 } else {
2285                                         Console.WriteLine ("Unknown exprclass: " + eclass);
2286                                 }
2287                                 break;
2288                                 
2289                         default:
2290                                 throw new Exception ("This should not happen: Operator = "
2291                                                      + oper.ToString ());
2292                         }
2293                 }
2294                 
2295
2296                 public override void EmitStatement (EmitContext ec)
2297                 {
2298                         //
2299                         // FIXME: we should rewrite this code to generate
2300                         // better code for ++ and -- as we know we wont need
2301                         // the values on the stack
2302                         //
2303                         Emit (ec);
2304                         ec.ig.Emit (OpCodes.Pop);
2305                 }
2306         }
2307         
2308         public class Probe : Expression {
2309                 public readonly string ProbeType;
2310                 public readonly Operator Oper;
2311                 Expression expr;
2312                 Type probe_type;
2313                 
2314                 public enum Operator {
2315                         Is, As
2316                 }
2317                 
2318                 public Probe (Operator oper, Expression expr, string probe_type)
2319                 {
2320                         Oper = oper;
2321                         ProbeType = probe_type;
2322                         this.expr = expr;
2323                 }
2324
2325                 public Expression Expr {
2326                         get {
2327                                 return expr;
2328                         }
2329                 }
2330                 
2331                 public override Expression DoResolve (EmitContext ec)
2332                 {
2333                         probe_type = ec.TypeContainer.LookupType (ProbeType, false);
2334
2335                         if (probe_type == null)
2336                                 return null;
2337
2338                         expr = expr.Resolve (ec);
2339                         
2340                         type = TypeManager.bool_type;
2341                         eclass = ExprClass.Value;
2342
2343                         return this;
2344                 }
2345
2346                 public override void Emit (EmitContext ec)
2347                 {
2348                         ILGenerator ig = ec.ig;
2349                         
2350                         expr.Emit (ec);
2351                         
2352                         if (Oper == Operator.Is){
2353                                 ig.Emit (OpCodes.Isinst, probe_type);
2354                                 ig.Emit (OpCodes.Ldnull);
2355                                 ig.Emit (OpCodes.Cgt_Un);
2356                         } else {
2357                                 ig.Emit (OpCodes.Isinst, probe_type);
2358                         }
2359                 }
2360         }
2361
2362         // <summary>
2363         //   This represents a typecast in the source language.
2364         //
2365         //   FIXME: Cast expressions have an unusual set of parsing
2366         //   rules, we need to figure those out.
2367         // </summary>
2368         public class Cast : Expression {
2369                 string target_type;
2370                 Expression expr;
2371                 Location   loc;
2372                         
2373                 public Cast (string cast_type, Expression expr, Location loc)
2374                 {
2375                         this.target_type = cast_type;
2376                         this.expr = expr;
2377                         this.loc = loc;
2378                 }
2379
2380                 public string TargetType {
2381                         get {
2382                                 return target_type;
2383                         }
2384                 }
2385
2386                 public Expression Expr {
2387                         get {
2388                                 return expr;
2389                         }
2390                         set {
2391                                 expr = value;
2392                         }
2393                 }
2394                 
2395                 public override Expression DoResolve (EmitContext ec)
2396                 {
2397                         expr = expr.Resolve (ec);
2398                         if (expr == null)
2399                                 return null;
2400                         
2401                         type = ec.TypeContainer.LookupType (target_type, false);
2402                         eclass = ExprClass.Value;
2403                         
2404                         if (type == null)
2405                                 return null;
2406
2407                         expr = ConvertExplicit (ec, expr, type, loc);
2408
2409                         return expr;
2410                 }
2411
2412                 public override void Emit (EmitContext ec)
2413                 {
2414                         //
2415                         // This one will never happen
2416                         //
2417                         throw new Exception ("Should not happen");
2418                 }
2419         }
2420
2421         public class Binary : Expression {
2422                 public enum Operator {
2423                         Multiply, Division, Modulus,
2424                         Addition, Subtraction,
2425                         LeftShift, RightShift,
2426                         LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, 
2427                         Equality, Inequality,
2428                         BitwiseAnd,
2429                         ExclusiveOr,
2430                         BitwiseOr,
2431                         LogicalAnd,
2432                         LogicalOr
2433                 }
2434
2435                 Operator oper;
2436                 Expression left, right;
2437                 MethodBase method;
2438                 ArrayList  Arguments;
2439                 Location   loc;
2440                 
2441
2442                 public Binary (Operator oper, Expression left, Expression right, Location loc)
2443                 {
2444                         this.oper = oper;
2445                         this.left = left;
2446                         this.right = right;
2447                         this.loc = loc;
2448                 }
2449
2450                 public Operator Oper {
2451                         get {
2452                                 return oper;
2453                         }
2454                         set {
2455                                 oper = value;
2456                         }
2457                 }
2458                 
2459                 public Expression Left {
2460                         get {
2461                                 return left;
2462                         }
2463                         set {
2464                                 left = value;
2465                         }
2466                 }
2467
2468                 public Expression Right {
2469                         get {
2470                                 return right;
2471                         }
2472                         set {
2473                                 right = value;
2474                         }
2475                 }
2476
2477
2478                 // <summary>
2479                 //   Returns a stringified representation of the Operator
2480                 // </summary>
2481                 string OperName ()
2482                 {
2483                         switch (oper){
2484                         case Operator.Multiply:
2485                                 return "*";
2486                         case Operator.Division:
2487                                 return "/";
2488                         case Operator.Modulus:
2489                                 return "%";
2490                         case Operator.Addition:
2491                                 return "+";
2492                         case Operator.Subtraction:
2493                                 return "-";
2494                         case Operator.LeftShift:
2495                                 return "<<";
2496                         case Operator.RightShift:
2497                                 return ">>";
2498                         case Operator.LessThan:
2499                                 return "<";
2500                         case Operator.GreaterThan:
2501                                 return ">";
2502                         case Operator.LessThanOrEqual:
2503                                 return "<=";
2504                         case Operator.GreaterThanOrEqual:
2505                                 return ">=";
2506                         case Operator.Equality:
2507                                 return "==";
2508                         case Operator.Inequality:
2509                                 return "!=";
2510                         case Operator.BitwiseAnd:
2511                                 return "&";
2512                         case Operator.BitwiseOr:
2513                                 return "|";
2514                         case Operator.ExclusiveOr:
2515                                 return "^";
2516                         case Operator.LogicalOr:
2517                                 return "||";
2518                         case Operator.LogicalAnd:
2519                                 return "&&";
2520                         }
2521
2522                         return oper.ToString ();
2523                 }
2524
2525                 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
2526                 {
2527                         if (expr.Type == target_type)
2528                                 return expr;
2529
2530                         return ConvertImplicit (ec, expr, target_type, new Location (-1));
2531                 }
2532                 
2533                 //
2534                 // Note that handling the case l == Decimal || r == Decimal
2535                 // is taken care of by the Step 1 Operator Overload resolution.
2536                 //
2537                 void DoNumericPromotions (EmitContext ec, Type l, Type r)
2538                 {
2539                         if (l == TypeManager.double_type || r == TypeManager.double_type){
2540                                 //
2541                                 // If either operand is of type double, the other operand is
2542                                 // conveted to type double.
2543                                 //
2544                                 if (r != TypeManager.double_type)
2545                                         right = ConvertImplicit (ec, right, TypeManager.double_type, loc);
2546                                 if (l != TypeManager.double_type)
2547                                         left = ConvertImplicit (ec, left, TypeManager.double_type, loc);
2548                                 
2549                                 type = TypeManager.double_type;
2550                         } else if (l == TypeManager.float_type || r == TypeManager.float_type){
2551                                 //
2552                                 // if either operand is of type float, th eother operand is
2553                                 // converd to type float.
2554                                 //
2555                                 if (r != TypeManager.double_type)
2556                                         right = ConvertImplicit (ec, right, TypeManager.float_type, loc);
2557                                 if (l != TypeManager.double_type)
2558                                         left = ConvertImplicit (ec, left, TypeManager.float_type, loc);
2559                                 type = TypeManager.float_type;
2560                         } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
2561                                 Expression e;
2562                                 Type other;
2563                                 //
2564                                 // If either operand is of type ulong, the other operand is
2565                                 // converted to type ulong.  or an error ocurrs if the other
2566                                 // operand is of type sbyte, short, int or long
2567                                 //
2568                                 
2569                                 if (l == TypeManager.uint64_type){
2570                                         if (r != TypeManager.uint64_type && right is IntLiteral){
2571                                                 e = TryImplicitIntConversion (l, (IntLiteral) right);
2572                                                 if (e != null)
2573                                                         right = e;
2574                                         }
2575                                         other = right.Type;
2576                                 } else {
2577                                         if (left is IntLiteral){
2578                                                 e = TryImplicitIntConversion (r, (IntLiteral) left);
2579                                                 if (e != null)
2580                                                         left = e;
2581                                         }
2582                                         other = left.Type;
2583                                 }
2584
2585                                 if ((other == TypeManager.sbyte_type) ||
2586                                     (other == TypeManager.short_type) ||
2587                                     (other == TypeManager.int32_type) ||
2588                                     (other == TypeManager.int64_type)){
2589                                         string oper = OperName ();
2590                                         
2591                                         Error (34, loc, "Operator `" + OperName ()
2592                                                + "' is ambiguous on operands of type `"
2593                                                + TypeManager.CSharpName (l) + "' "
2594                                                + "and `" + TypeManager.CSharpName (r)
2595                                                + "'");
2596                                 }
2597                                 type = TypeManager.uint64_type;
2598                         } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
2599                                 //
2600                                 // If either operand is of type long, the other operand is converted
2601                                 // to type long.
2602                                 //
2603                                 if (l != TypeManager.int64_type)
2604                                         left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);
2605                                 if (r != TypeManager.int64_type)
2606                                         right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);
2607
2608                                 type = TypeManager.int64_type;
2609                         } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
2610                                 //
2611                                 // If either operand is of type uint, and the other
2612                                 // operand is of type sbyte, short or int, othe operands are
2613                                 // converted to type long.
2614                                 //
2615                                 Type other = null;
2616                                 
2617                                 if (l == TypeManager.uint32_type)
2618                                         other = r;
2619                                 else if (r == TypeManager.uint32_type)
2620                                         other = l;
2621
2622                                 if ((other == TypeManager.sbyte_type) ||
2623                                     (other == TypeManager.short_type) ||
2624                                     (other == TypeManager.int32_type)){
2625                                         left = ForceConversion (ec, left, TypeManager.int64_type);
2626                                         right = ForceConversion (ec, right, TypeManager.int64_type);
2627                                         type = TypeManager.int64_type;
2628                                 } else {
2629                                         //
2630                                         // if either operand is of type uint, the other
2631                                         // operand is converd to type uint
2632                                         //
2633                                         left = ForceConversion (ec, left, TypeManager.uint32_type);
2634                                         right = ForceConversion (ec, right, TypeManager.uint32_type);
2635                                         type = TypeManager.uint32_type;
2636                                 } 
2637                         } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
2638                                 if (l != TypeManager.decimal_type)
2639                                         left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);
2640                                 if (r != TypeManager.decimal_type)
2641                                         right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);
2642
2643                                 type = TypeManager.decimal_type;
2644                         } else {
2645                                 Expression l_tmp, r_tmp;
2646
2647                                 l_tmp = ForceConversion (ec, left, TypeManager.int32_type);
2648                                 if (l_tmp == null) {
2649                                         error19 ();
2650                                         left = l_tmp;
2651                                         return;
2652                                 }
2653                                 
2654                                 r_tmp = ForceConversion (ec, right, TypeManager.int32_type);
2655                                 if (r_tmp == null) {
2656                                         error19 ();
2657                                         right = r_tmp;
2658                                         return;
2659                                 }
2660                                 
2661                                 type = TypeManager.int32_type;
2662                         }
2663                 }
2664
2665                 void error19 ()
2666                 {
2667                         Error (19, loc,
2668                                "Operator " + OperName () + " cannot be applied to operands of type `" +
2669                                TypeManager.CSharpName (left.Type) + "' and `" +
2670                                TypeManager.CSharpName (right.Type) + "'");
2671                                                      
2672                 }
2673                 
2674                 Expression CheckShiftArguments (EmitContext ec)
2675                 {
2676                         Expression e;
2677                         Type l = left.Type;
2678                         Type r = right.Type;
2679
2680                         e = ForceConversion (ec, right, TypeManager.int32_type);
2681                         if (e == null){
2682                                 error19 ();
2683                                 return null;
2684                         }
2685                         right = e;
2686
2687                         if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
2688                             ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
2689                             ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
2690                             ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){
2691                                 left = e;
2692                                 type = e.Type;
2693
2694                                 return this;
2695                         }
2696                         error19 ();
2697                         return null;
2698                 }
2699                 
2700                 Expression ResolveOperator (EmitContext ec)
2701                 {
2702                         Type l = left.Type;
2703                         Type r = right.Type;
2704
2705                         //
2706                         // Step 1: Perform Operator Overload location
2707                         //
2708                         Expression left_expr, right_expr;
2709                         
2710                         string op = "op_" + oper;
2711
2712                         left_expr = MemberLookup (ec, l, op, false, loc);
2713                         if (left_expr == null && l.BaseType != null)
2714                                 left_expr = MemberLookup (ec, l.BaseType, op, false, loc);
2715                         
2716                         right_expr = MemberLookup (ec, r, op, false, loc);
2717                         if (right_expr == null && r.BaseType != null)
2718                                 right_expr = MemberLookup (ec, r.BaseType, op, false, loc);
2719                         
2720                         MethodGroupExpr union = Invocation.MakeUnionSet (left_expr, right_expr);
2721                         
2722                         if (union != null) {
2723                                 Arguments = new ArrayList ();
2724                                 Arguments.Add (new Argument (left, Argument.AType.Expression));
2725                                 Arguments.Add (new Argument (right, Argument.AType.Expression));
2726                                 
2727                                 method = Invocation.OverloadResolve (ec, union, Arguments, loc);
2728                                 if (method != null) {
2729                                         MethodInfo mi = (MethodInfo) method;
2730                                         type = mi.ReturnType;
2731                                         return this;
2732                                 } else {
2733                                         error19 ();
2734                                         return null;
2735                                 }
2736                         }       
2737
2738                         //
2739                         // Step 2: Default operations on CLI native types.
2740                         //
2741                         
2742                         // Only perform numeric promotions on:
2743                         // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2744                         //
2745                         if (oper == Operator.Addition){
2746                                 //
2747                                 // If any of the arguments is a string, cast to string
2748                                 //
2749                                 if (l == TypeManager.string_type){
2750                                         if (r == TypeManager.string_type){
2751                                                 // string + string
2752                                                 method = TypeManager.string_concat_string_string;
2753                                         } else {
2754                                                 // string + object
2755                                                 method = TypeManager.string_concat_object_object;
2756                                                 right = ConvertImplicit (ec, right,
2757                                                                          TypeManager.object_type, loc);
2758                                         }
2759                                         type = TypeManager.string_type;
2760
2761                                         Arguments = new ArrayList ();
2762                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
2763                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
2764
2765                                         return this;
2766                                         
2767                                 } else if (r == TypeManager.string_type){
2768                                         // object + string
2769                                         method = TypeManager.string_concat_object_object;
2770                                         Arguments = new ArrayList ();
2771                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
2772                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
2773
2774                                         left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
2775                                         type = TypeManager.string_type;
2776
2777                                         return this;
2778                                 }
2779
2780                                 //
2781                                 // FIXME: is Delegate operator + (D x, D y) handled?
2782                                 //
2783                         }
2784                         
2785                         if (oper == Operator.LeftShift || oper == Operator.RightShift)
2786                                 return CheckShiftArguments (ec);
2787
2788                         if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2789                                 if (l != TypeManager.bool_type || r != TypeManager.bool_type)
2790                                         error19 ();
2791
2792                                 type = TypeManager.bool_type;
2793                                 return this;
2794                         } 
2795
2796                         //
2797                         // We are dealing with numbers
2798                         //
2799
2800                         DoNumericPromotions (ec, l, r);
2801
2802                         if (left == null || right == null)
2803                                 return null;
2804
2805                         
2806                         if (oper == Operator.BitwiseAnd ||
2807                             oper == Operator.BitwiseOr ||
2808                             oper == Operator.ExclusiveOr){
2809                                 if (!((l == TypeManager.int32_type) ||
2810                                       (l == TypeManager.uint32_type) ||
2811                                       (l == TypeManager.int64_type) ||
2812                                       (l == TypeManager.uint64_type))){
2813                                         error19 ();
2814                                         return null;
2815                                 }
2816                                 type = l;
2817                         }
2818
2819                         if (oper == Operator.Equality ||
2820                             oper == Operator.Inequality ||
2821                             oper == Operator.LessThanOrEqual ||
2822                             oper == Operator.LessThan ||
2823                             oper == Operator.GreaterThanOrEqual ||
2824                             oper == Operator.GreaterThan){
2825                                 type = TypeManager.bool_type;
2826                         }
2827
2828                         return this;
2829                 }
2830                 
2831                 public override Expression DoResolve (EmitContext ec)
2832                 {
2833                         left = left.Resolve (ec);
2834                         right = right.Resolve (ec);
2835
2836                         if (left == null || right == null)
2837                                 return null;
2838
2839                         if (left.Type == null)
2840                                 throw new Exception (
2841                                         "Resolve returned non null, but did not set the type! (" +
2842                                         left + ") at Line: " + loc.Row);
2843                         if (right.Type == null)
2844                                 throw new Exception (
2845                                         "Resolve returned non null, but did not set the type! (" +
2846                                         right + ") at Line: "+ loc.Row);
2847
2848                         eclass = ExprClass.Value;
2849
2850                         return ResolveOperator (ec);
2851                 }
2852
2853                 public bool IsBranchable ()
2854                 {
2855                         if (oper == Operator.Equality ||
2856                             oper == Operator.Inequality ||
2857                             oper == Operator.LessThan ||
2858                             oper == Operator.GreaterThan ||
2859                             oper == Operator.LessThanOrEqual ||
2860                             oper == Operator.GreaterThanOrEqual){
2861                                 return true;
2862                         } else
2863                                 return false;
2864                 }
2865
2866                 // <summary>
2867                 //   This entry point is used by routines that might want
2868                 //   to emit a brfalse/brtrue after an expression, and instead
2869                 //   they could use a more compact notation.
2870                 //
2871                 //   Typically the code would generate l.emit/r.emit, followed
2872                 //   by the comparission and then a brtrue/brfalse.  The comparissions
2873                 //   are sometimes inneficient (there are not as complete as the branches
2874                 //   look for the hacks in Emit using double ceqs).
2875                 //
2876                 //   So for those cases we provide EmitBranchable that can emit the
2877                 //   branch with the test
2878                 // </summary>
2879                 public void EmitBranchable (EmitContext ec, int target)
2880                 {
2881                         OpCode opcode;
2882                         bool close_target = false;
2883                         
2884                         left.Emit (ec);
2885                         right.Emit (ec);
2886                         
2887                         switch (oper){
2888                         case Operator.Equality:
2889                                 if (close_target)
2890                                         opcode = OpCodes.Beq_S;
2891                                 else
2892                                         opcode = OpCodes.Beq;
2893                                 break;
2894
2895                         case Operator.Inequality:
2896                                 if (close_target)
2897                                         opcode = OpCodes.Bne_Un_S;
2898                                 else
2899                                         opcode = OpCodes.Bne_Un;
2900                                 break;
2901
2902                         case Operator.LessThan:
2903                                 if (close_target)
2904                                         opcode = OpCodes.Blt_S;
2905                                 else
2906                                         opcode = OpCodes.Blt;
2907                                 break;
2908
2909                         case Operator.GreaterThan:
2910                                 if (close_target)
2911                                         opcode = OpCodes.Bgt_S;
2912                                 else
2913                                         opcode = OpCodes.Bgt;
2914                                 break;
2915
2916                         case Operator.LessThanOrEqual:
2917                                 if (close_target)
2918                                         opcode = OpCodes.Ble_S;
2919                                 else
2920                                         opcode = OpCodes.Ble;
2921                                 break;
2922
2923                         case Operator.GreaterThanOrEqual:
2924                                 if (close_target)
2925                                         opcode = OpCodes.Bge_S;
2926                                 else
2927                                         opcode = OpCodes.Ble;
2928                                 break;
2929
2930                         default:
2931                                 throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "
2932                                                      + oper.ToString ());
2933                         }
2934
2935                         ec.ig.Emit (opcode, target);
2936                 }
2937                 
2938                 public override void Emit (EmitContext ec)
2939                 {
2940                         ILGenerator ig = ec.ig;
2941                         Type l = left.Type;
2942                         Type r = right.Type;
2943                         OpCode opcode;
2944
2945                         if (method != null) {
2946
2947                                 // Note that operators are static anyway
2948                                 
2949                                 if (Arguments != null) 
2950                                         Invocation.EmitArguments (ec, method, Arguments);
2951                                 
2952                                 if (method is MethodInfo)
2953                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
2954                                 else
2955                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2956
2957                                 return;
2958                         }
2959                         
2960                         left.Emit (ec);
2961                         right.Emit (ec);
2962
2963                         switch (oper){
2964                         case Operator.Multiply:
2965                                 if (ec.CheckState){
2966                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2967                                                 opcode = OpCodes.Mul_Ovf;
2968                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2969                                                 opcode = OpCodes.Mul_Ovf_Un;
2970                                         else
2971                                                 opcode = OpCodes.Mul;
2972                                 } else
2973                                         opcode = OpCodes.Mul;
2974
2975                                 break;
2976
2977                         case Operator.Division:
2978                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2979                                         opcode = OpCodes.Div_Un;
2980                                 else
2981                                         opcode = OpCodes.Div;
2982                                 break;
2983
2984                         case Operator.Modulus:
2985                                 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2986                                         opcode = OpCodes.Rem_Un;
2987                                 else
2988                                         opcode = OpCodes.Rem;
2989                                 break;
2990
2991                         case Operator.Addition:
2992                                 if (ec.CheckState){
2993                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2994                                                 opcode = OpCodes.Add_Ovf;
2995                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2996                                                 opcode = OpCodes.Add_Ovf_Un;
2997                                         else
2998                                                 opcode = OpCodes.Mul;
2999                                 } else
3000                                         opcode = OpCodes.Add;
3001                                 break;
3002
3003                         case Operator.Subtraction:
3004                                 if (ec.CheckState){
3005                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3006                                                 opcode = OpCodes.Sub_Ovf;
3007                                         else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
3008                                                 opcode = OpCodes.Sub_Ovf_Un;
3009                                         else
3010                                                 opcode = OpCodes.Sub;
3011                                 } else
3012                                         opcode = OpCodes.Sub;
3013                                 break;
3014
3015                         case Operator.RightShift:
3016                                 opcode = OpCodes.Shr;
3017                                 break;
3018                                 
3019                         case Operator.LeftShift:
3020                                 opcode = OpCodes.Shl;
3021                                 break;
3022
3023                         case Operator.Equality:
3024                                 opcode = OpCodes.Ceq;
3025                                 break;
3026
3027                         case Operator.Inequality:
3028                                 ec.ig.Emit (OpCodes.Ceq);
3029                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
3030                                 
3031                                 opcode = OpCodes.Ceq;
3032                                 break;
3033
3034                         case Operator.LessThan:
3035                                 opcode = OpCodes.Clt;
3036                                 break;
3037
3038                         case Operator.GreaterThan:
3039                                 opcode = OpCodes.Cgt;
3040                                 break;
3041
3042                         case Operator.LessThanOrEqual:
3043                                 ec.ig.Emit (OpCodes.Cgt);
3044                                 ec.ig.Emit (OpCodes.Ldc_I4_0);
3045                                 
3046                                 opcode = OpCodes.Ceq;
3047                                 break;
3048
3049                         case Operator.GreaterThanOrEqual:
3050                                 ec.ig.Emit (OpCodes.Clt);
3051                                 ec.ig.Emit (OpCodes.Ldc_I4_1);
3052                                 
3053                                 opcode = OpCodes.Sub;
3054                                 break;
3055
3056                         case Operator.LogicalOr:
3057                         case Operator.BitwiseOr:
3058                                 opcode = OpCodes.Or;
3059                                 break;
3060
3061                         case Operator.LogicalAnd:
3062                         case Operator.BitwiseAnd:
3063                                 opcode = OpCodes.And;
3064                                 break;
3065
3066                         case Operator.ExclusiveOr:
3067                                 opcode = OpCodes.Xor;
3068                                 break;
3069
3070                         default:
3071                                 throw new Exception ("This should not happen: Operator = "
3072                                                      + oper.ToString ());
3073                         }
3074
3075                         ig.Emit (opcode);
3076                 }
3077         }
3078
3079         public class Conditional : Expression {
3080                 Expression expr, trueExpr, falseExpr;
3081                 Location loc;
3082                 
3083                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3084                 {
3085                         this.expr = expr;
3086                         this.trueExpr = trueExpr;
3087                         this.falseExpr = falseExpr;
3088                         this.loc = l;
3089                 }
3090
3091                 public Expression Expr {
3092                         get {
3093                                 return expr;
3094                         }
3095                 }
3096
3097                 public Expression TrueExpr {
3098                         get {
3099                                 return trueExpr;
3100                         }
3101                 }
3102
3103                 public Expression FalseExpr {
3104                         get {
3105                                 return falseExpr;
3106                         }
3107                 }
3108
3109                 public override Expression DoResolve (EmitContext ec)
3110                 {
3111                         expr = expr.Resolve (ec);
3112
3113                         if (expr.Type != TypeManager.bool_type)
3114                                 expr = Expression.ConvertImplicitRequired (
3115                                         ec, expr, TypeManager.bool_type, loc);
3116                         
3117                         trueExpr = trueExpr.Resolve (ec);
3118                         falseExpr = falseExpr.Resolve (ec);
3119
3120                         if (expr == null || trueExpr == null || falseExpr == null)
3121                                 return null;
3122                         
3123                         if (trueExpr.Type == falseExpr.Type)
3124                                 type = trueExpr.Type;
3125                         else {
3126                                 Expression conv;
3127
3128                                 //
3129                                 // First, if an implicit conversion exists from trueExpr
3130                                 // to falseExpr, then the result type is of type falseExpr.Type
3131                                 //
3132                                 conv = ConvertImplicit (ec, trueExpr, falseExpr.Type, loc);
3133                                 if (conv != null){
3134                                         type = falseExpr.Type;
3135                                         trueExpr = conv;
3136                                 } else if ((conv = ConvertImplicit(ec, falseExpr,trueExpr.Type,loc))!= null){
3137                                         type = trueExpr.Type;
3138                                         falseExpr = conv;
3139                                 } else {
3140                                         Error (173, loc, "The type of the conditional expression can " +
3141                                                "not be computed because there is no implicit conversion" +
3142                                                " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
3143                                                " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
3144                                         return null;
3145                                 }
3146                         }
3147
3148                         eclass = ExprClass.Value;
3149                         return this;
3150                 }
3151
3152                 public override void Emit (EmitContext ec)
3153                 {
3154                         ILGenerator ig = ec.ig;
3155                         Label false_target = ig.DefineLabel ();
3156                         Label end_target = ig.DefineLabel ();
3157
3158                         expr.Emit (ec);
3159                         ig.Emit (OpCodes.Brfalse, false_target);
3160                         trueExpr.Emit (ec);
3161                         ig.Emit (OpCodes.Br, end_target);
3162                         ig.MarkLabel (false_target);
3163                         falseExpr.Emit (ec);
3164                         ig.MarkLabel (end_target);
3165                 }
3166         }
3167
3168         //
3169         // SimpleName expressions are initially formed of a single
3170         // word and it only happens at the beginning of the expression.
3171         //
3172         // The expression will try to be bound to a Field, a Method
3173         // group or a Property.  If those fail we pass the name to our
3174         // caller and the SimpleName is compounded to perform a type
3175         // lookup.  The idea behind this process is that we want to avoid
3176         // creating a namespace map from the assemblies, as that requires
3177         // the GetExportedTypes function to be called and a hashtable to
3178         // be constructed which reduces startup time.  If later we find
3179         // that this is slower, we should create a `NamespaceExpr' expression
3180         // that fully participates in the resolution process. 
3181         //
3182         // For example `System.Console.WriteLine' is decomposed into
3183         // MemberAccess (MemberAccess (SimpleName ("System"), "Console"), "WriteLine")
3184         //
3185         // The first SimpleName wont produce a match on its own, so it will
3186         // be turned into:
3187         // MemberAccess (SimpleName ("System.Console"), "WriteLine").
3188         //
3189         // System.Console will produce a TypeExpr match.
3190         //
3191         // The downside of this is that we might be hitting `LookupType' too many
3192         // times with this scheme.
3193         //
3194         public class SimpleName : Expression {
3195                 public readonly string Name;
3196                 public readonly Location Location;
3197                 
3198                 public SimpleName (string name, Location l)
3199                 {
3200                         Name = name;
3201                         Location = l;
3202                 }
3203
3204                 public static void Error120 (Location l, string name)
3205                 {
3206                         Report.Error (
3207                                 120, l,
3208                                 "An object reference is required " +
3209                                 "for the non-static field `"+name+"'");
3210                 }
3211                 
3212                 //
3213                 // Checks whether we are trying to access an instance
3214                 // property, method or field from a static body.
3215                 //
3216                 Expression MemberStaticCheck (Expression e)
3217                 {
3218                         if (e is FieldExpr){
3219                                 FieldInfo fi = ((FieldExpr) e).FieldInfo;
3220                                 
3221                                 if (!fi.IsStatic){
3222                                         Error120 (Location, Name);
3223                                         return null;
3224                                 }
3225                         } else if (e is MethodGroupExpr){
3226                                 MethodGroupExpr mg = (MethodGroupExpr) e;
3227
3228                                 if (!mg.RemoveInstanceMethods ()){
3229                                         Error120 (Location, mg.Methods [0].Name);
3230                                         return null;
3231                                 }
3232                                 return e;
3233                         } else if (e is PropertyExpr){
3234                                 if (!((PropertyExpr) e).IsStatic){
3235                                         Error120 (Location, Name);
3236                                         return null;
3237                                 }
3238                         }
3239
3240                         return e;
3241                 }
3242                 
3243                 //
3244                 // 7.5.2: Simple Names. 
3245                 //
3246                 // Local Variables and Parameters are handled at
3247                 // parse time, so they never occur as SimpleNames.
3248                 //
3249                 public override Expression DoResolve (EmitContext ec)
3250                 {
3251                         Expression e;
3252
3253                         //
3254                         // Stage 1: Performed by the parser (binding to local or parameters).
3255                         //
3256
3257                         //
3258                         // Stage 2: Lookup members
3259                         //
3260                         e = MemberLookup (ec, ec.TypeContainer.TypeBuilder, Name, true, Location);
3261                         if (e == null){
3262                                 //
3263                                 // Stage 3: Lookup symbol in the various namespaces. 
3264                                 // 
3265                                 Type t;
3266                                 
3267                                 if ((t = ec.TypeContainer.LookupType (Name, true)) != null)
3268                                         return new TypeExpr (t);
3269
3270                                 //
3271                                 // Stage 3 part b: Lookup up if we are an alias to a type
3272                                 // or a namespace.
3273                                 //
3274                                 // Since we are cheating: we only do the Alias lookup for
3275                                 // namespaces if the name does not include any dots in it
3276                                 //
3277                                 
3278                                 // IMPLEMENT ME.  Read mcs/mcs/TODO for ideas, or rewrite
3279                                 // using NamespaceExprs (dunno how that fixes the alias
3280                                 // per-file though).
3281                                 
3282                                 // No match, maybe our parent can compose us
3283                                 // into something meaningful.
3284                                 //
3285                                 return this;
3286                         }
3287
3288                         // Step 2, continues here.
3289                         if (e is TypeExpr)
3290                                 return e;
3291
3292                         if (e is FieldExpr){
3293                                 FieldExpr fe = (FieldExpr) e;
3294                                 
3295                                 if (!fe.FieldInfo.IsStatic)
3296                                         fe.InstanceExpression = new This (Location.Null);
3297                         }                               
3298
3299                         if (ec.IsStatic)
3300                                 return MemberStaticCheck (e);
3301                         else
3302                                 return e;
3303                 }
3304
3305                 public override void Emit (EmitContext ec)
3306                 {
3307                         //
3308                         // If this is ever reached, then we failed to
3309                         // find the name as a namespace
3310                         //
3311
3312                         Error (103, Location, "The name `" + Name +
3313                                "' does not exist in the class `" +
3314                                ec.TypeContainer.Name + "'");
3315                 }
3316         }
3317         
3318         public class LocalVariableReference : Expression, IStackStore, IMemoryLocation {
3319                 public readonly string Name;
3320                 public readonly Block Block;
3321
3322                 VariableInfo variable_info;
3323                 
3324                 public LocalVariableReference (Block block, string name)
3325                 {
3326                         Block = block;
3327                         Name = name;
3328                         eclass = ExprClass.Variable;
3329                 }
3330
3331                 public VariableInfo VariableInfo {
3332                         get {
3333                                 if (variable_info == null)
3334                                         variable_info = Block.GetVariableInfo (Name);
3335                                 return variable_info;
3336                         }
3337                 }
3338                 
3339                 public override Expression DoResolve (EmitContext ec)
3340                 {
3341                         VariableInfo vi = VariableInfo;
3342
3343                         type = vi.VariableType;
3344                         return this;
3345                 }
3346
3347                 public override void Emit (EmitContext ec)
3348                 {
3349                         VariableInfo vi = VariableInfo;
3350                         ILGenerator ig = ec.ig;
3351                         int idx = vi.Idx;
3352
3353                         vi.Used = true;
3354                         
3355                         switch (idx){
3356                         case 0:
3357                                 ig.Emit (OpCodes.Ldloc_0);
3358                                 break;
3359                                 
3360                         case 1:
3361                                 ig.Emit (OpCodes.Ldloc_1);
3362                                 break;
3363
3364                         case 2:
3365                                 ig.Emit (OpCodes.Ldloc_2);
3366                                 break;
3367
3368                         case 3:
3369                                 ig.Emit (OpCodes.Ldloc_3);
3370                                 break;
3371
3372                         default:
3373                                 if (idx <= 255)
3374                                         ig.Emit (OpCodes.Ldloc_S, (byte) idx);
3375                                 else
3376                                         ig.Emit (OpCodes.Ldloc, idx);
3377                                 break;
3378                         }
3379                 }
3380
3381                 public static void Store (ILGenerator ig, int idx)
3382                 {
3383                         switch (idx){
3384                         case 0:
3385                                 ig.Emit (OpCodes.Stloc_0);
3386                                 break;
3387                                 
3388                         case 1:
3389                                 ig.Emit (OpCodes.Stloc_1);
3390                                 break;
3391                                 
3392                         case 2:
3393                                 ig.Emit (OpCodes.Stloc_2);
3394                                 break;
3395                                 
3396                         case 3:
3397                                 ig.Emit (OpCodes.Stloc_3);
3398                                 break;
3399                                 
3400                         default:
3401                                 if (idx <= 255)
3402                                         ig.Emit (OpCodes.Stloc_S, (byte) idx);
3403                                 else
3404                                         ig.Emit (OpCodes.Stloc, idx);
3405                                 break;
3406                         }
3407                 }
3408                 
3409                 public void Store (EmitContext ec)
3410                 {
3411                         ILGenerator ig = ec.ig;
3412                         VariableInfo vi = VariableInfo;
3413
3414                         vi.Assigned = true;
3415
3416                         // Funny seems the above generates optimal code for us, but
3417                         // seems to take too long to generate what we need.
3418                         // ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
3419
3420                         Store (ig, vi.Idx);
3421                 }
3422
3423                 public void AddressOf (EmitContext ec)
3424                 {
3425                         VariableInfo vi = VariableInfo;
3426                         int idx = vi.Idx;
3427
3428                         vi.Used = true;
3429                         vi.Assigned = true;
3430                         
3431                         if (idx <= 255)
3432                                 ec.ig.Emit (OpCodes.Ldloca_S, (byte) idx);
3433                         else
3434                                 ec.ig.Emit (OpCodes.Ldloca, idx);
3435                 }
3436         }
3437
3438         public class ParameterReference : Expression, IStackStore, IMemoryLocation {
3439                 public readonly Parameters Pars;
3440                 public readonly String Name;
3441                 public readonly int Idx;
3442                 int arg_idx;
3443                 
3444                 public ParameterReference (Parameters pars, int idx, string name)
3445                 {
3446                         Pars = pars;
3447                         Idx  = idx;
3448                         Name = name;
3449                         eclass = ExprClass.Variable;
3450                 }
3451
3452                 public override Expression DoResolve (EmitContext ec)
3453                 {
3454                         Type [] types = Pars.GetParameterInfo (ec.TypeContainer);
3455
3456                         type = types [Idx];
3457
3458                         arg_idx = Idx;
3459                         if (!ec.IsStatic)
3460                                 arg_idx++;
3461                         
3462                         return this;
3463                 }
3464
3465                 public override void Emit (EmitContext ec)
3466                 {
3467                         if (arg_idx <= 255)
3468                                 ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
3469                         else
3470                                 ec.ig.Emit (OpCodes.Ldarg, arg_idx);
3471                 }
3472
3473                 public void Store (EmitContext ec)
3474                 {
3475                         if (arg_idx <= 255)
3476                                 ec.ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
3477                         else
3478                                 ec.ig.Emit (OpCodes.Starg, arg_idx);
3479                         
3480                 }
3481
3482                 public void AddressOf (EmitContext ec)
3483                 {
3484                         if (arg_idx <= 255)
3485                                 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
3486                         else
3487                                 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
3488                 }
3489         }
3490         
3491         // <summary>
3492         //   Used for arguments to New(), Invocation()
3493         // </summary>
3494         public class Argument {
3495                 public enum AType {
3496                         Expression,
3497                         Ref,
3498                         Out
3499                 };
3500
3501                 public readonly AType Type;
3502                 public Expression expr;
3503
3504                 public Argument (Expression expr, AType type)
3505                 {
3506                         this.expr = expr;
3507                         this.Type = type;
3508                 }
3509
3510                 public Expression Expr {
3511                         get {
3512                                 return expr;
3513                         }
3514
3515                         set {
3516                                 expr = value;
3517                         }
3518                 }
3519
3520                 public bool Resolve (EmitContext ec)
3521                 {
3522                         expr = expr.Resolve (ec);
3523
3524                         return expr != null;
3525                 }
3526
3527                 public void Emit (EmitContext ec)
3528                 {
3529                         expr.Emit (ec);
3530                 }
3531         }
3532
3533         // <summary>
3534         //   Invocation of methods or delegates.
3535         // </summary>
3536         public class Invocation : ExpressionStatement {
3537                 public readonly ArrayList Arguments;
3538                 public readonly Location Location;
3539
3540                 Expression expr;
3541                 MethodBase method = null;
3542                         
3543                 static Hashtable method_parameter_cache;
3544
3545                 static Invocation ()
3546                 {
3547                         method_parameter_cache = new Hashtable ();
3548                 }
3549                         
3550                 //
3551                 // arguments is an ArrayList, but we do not want to typecast,
3552                 // as it might be null.
3553                 //
3554                 // FIXME: only allow expr to be a method invocation or a
3555                 // delegate invocation (7.5.5)
3556                 //
3557                 public Invocation (Expression expr, ArrayList arguments, Location l)
3558                 {
3559                         this.expr = expr;
3560                         Arguments = arguments;
3561                         Location = l;
3562                 }
3563
3564                 public Expression Expr {
3565                         get {
3566                                 return expr;
3567                         }
3568                 }
3569
3570                 // <summary>
3571                 //   Returns the Parameters (a ParameterData interface) for the
3572                 //   Method `mb'
3573                 // </summary>
3574                 public static ParameterData GetParameterData (MethodBase mb)
3575                 {
3576                         object pd = method_parameter_cache [mb];
3577                         object ip;
3578                         
3579                         if (pd != null)
3580                                 return (ParameterData) pd;
3581
3582                         
3583                         ip = TypeContainer.LookupParametersByBuilder (mb);
3584                         if (ip != null){
3585                                 method_parameter_cache [mb] = ip;
3586
3587                                 return (ParameterData) ip;
3588                         } else {
3589                                 ParameterInfo [] pi = mb.GetParameters ();
3590                                 ReflectionParameters rp = new ReflectionParameters (pi);
3591                                 method_parameter_cache [mb] = rp;
3592
3593                                 return (ParameterData) rp;
3594                         }
3595                 }
3596
3597                 // <summary>
3598                 //   Tells whether a user defined conversion from Type `from' to
3599                 //   Type `to' exists.
3600                 //
3601                 //   FIXME: we could implement a cache here. 
3602                 // </summary>
3603                 static bool ConversionExists (EmitContext ec, Type from, Type to, Location loc)
3604                 {
3605                         // Locate user-defined implicit operators
3606
3607                         Expression mg;
3608                         
3609                         mg = MemberLookup (ec, to, "op_Implicit", false, loc);
3610
3611                         if (mg != null) {
3612                                 MethodGroupExpr me = (MethodGroupExpr) mg;
3613                                 
3614                                 for (int i = me.Methods.Length; i > 0;) {
3615                                         i--;
3616                                         MethodBase mb = me.Methods [i];
3617                                         ParameterData pd = GetParameterData (mb);
3618                                         
3619                                         if (from == pd.ParameterType (0))
3620                                                 return true;
3621                                 }
3622                         }
3623
3624                         mg = MemberLookup (ec, from, "op_Implicit", false, loc);
3625
3626                         if (mg != null) {
3627                                 MethodGroupExpr me = (MethodGroupExpr) mg;
3628
3629                                 for (int i = me.Methods.Length; i > 0;) {
3630                                         i--;
3631                                         MethodBase mb = me.Methods [i];
3632                                         MethodInfo mi = (MethodInfo) mb;
3633                                         
3634                                         if (mi.ReturnType == to)
3635                                                 return true;
3636                                 }
3637                         }
3638                         
3639                         return false;
3640                 }
3641                 
3642                 // <summary>
3643                 //  Determines "better conversion" as specified in 7.4.2.3
3644                 //  Returns : 1 if a->p is better
3645                 //            0 if a->q or neither is better 
3646                 // </summary>
3647                 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, bool use_standard,
3648                                              Location loc)
3649                 {
3650                         Type argument_type = a.Expr.Type;
3651                         Expression argument_expr = a.Expr;
3652
3653                         if (argument_type == null)
3654                                 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
3655
3656                         if (p == q)
3657                                 return 0;
3658                         
3659                         if (argument_type == p)
3660                                 return 1;
3661
3662                         if (argument_type == q)
3663                                 return 0;
3664
3665                         //
3666                         // Now probe whether an implicit constant expression conversion
3667                         // can be used.
3668                         //
3669                         // An implicit constant expression conversion permits the following
3670                         // conversions:
3671                         //
3672                         //    * A constant-expression of type `int' can be converted to type
3673                         //      sbyte, byute, short, ushort, uint, ulong provided the value of
3674                         //      of the expression is withing the range of the destination type.
3675                         //
3676                         //    * A constant-expression of type long can be converted to type
3677                         //      ulong, provided the value of the constant expression is not negative
3678                         //
3679                         // FIXME: Note that this assumes that constant folding has
3680                         // taken place.  We dont do constant folding yet.
3681                         //
3682
3683                         if (argument_expr is IntLiteral){
3684                                 IntLiteral ei = (IntLiteral) argument_expr;
3685                                 int value = ei.Value;
3686                                 
3687                                 if (p == TypeManager.sbyte_type){
3688                                         if (value >= SByte.MinValue && value <= SByte.MaxValue)
3689                                                 return 1;
3690                                 } else if (p == TypeManager.byte_type){
3691                                         if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
3692                                                 return 1;
3693                                 } else if (p == TypeManager.short_type){
3694                                         if (value >= Int16.MinValue && value <= Int16.MaxValue)
3695                                                 return 1;
3696                                 } else if (p == TypeManager.ushort_type){
3697                                         if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
3698                                                 return 1;
3699                                 } else if (p == TypeManager.uint32_type){
3700                                         //
3701                                         // we can optimize this case: a positive int32
3702                                         // always fits on a uint32
3703                                         //
3704                                         if (value >= 0)
3705                                                 return 1;
3706                                 } else if (p == TypeManager.uint64_type){
3707                                         //
3708                                         // we can optimize this case: a positive int32
3709                                         // always fits on a uint64
3710                                         //
3711                                         if (value >= 0)
3712                                                 return 1;
3713                                 }
3714                         } else if (argument_type == TypeManager.int64_type && argument_expr is LongLiteral){
3715                                 LongLiteral ll = (LongLiteral) argument_expr;
3716                                 
3717                                 if (p == TypeManager.uint64_type){
3718                                         if (ll.Value > 0)
3719                                                 return 1;
3720                                 }
3721                         }
3722
3723                         if (q == null) {
3724
3725                                 Expression tmp;
3726
3727                                 if (use_standard)
3728                                         tmp = ConvertImplicitStandard (ec, argument_expr, p, loc);
3729                                 else
3730                                         tmp = ConvertImplicit (ec, argument_expr, p, loc);
3731
3732                                 if (tmp != null)
3733                                         return 1;
3734                                 else
3735                                         return 0;
3736
3737                         }
3738
3739                         if (ConversionExists (ec, p, q, loc) == true &&
3740                             ConversionExists (ec, q, p, loc) == false)
3741                                 return 1;
3742
3743                         if (p == TypeManager.sbyte_type)
3744                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3745                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3746                                         return 1;
3747
3748                         if (p == TypeManager.short_type)
3749                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3750                                     q == TypeManager.uint64_type)
3751                                         return 1;
3752
3753                         if (p == TypeManager.int32_type)
3754                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3755                                         return 1;
3756
3757                         if (p == TypeManager.int64_type)
3758                                 if (q == TypeManager.uint64_type)
3759                                         return 1;
3760
3761                         return 0;
3762                 }
3763                 
3764                 // <summary>
3765                 //  Determines "Better function" and returns an integer indicating :
3766                 //  0 if candidate ain't better
3767                 //  1 if candidate is better than the current best match
3768                 // </summary>
3769                 static int BetterFunction (EmitContext ec, ArrayList args,
3770                                            MethodBase candidate, MethodBase best,
3771                                            bool use_standard, Location loc)
3772                 {
3773                         ParameterData candidate_pd = GetParameterData (candidate);
3774                         ParameterData best_pd;
3775                         int argument_count;
3776
3777                         if (args == null)
3778                                 argument_count = 0;
3779                         else
3780                                 argument_count = args.Count;
3781
3782                         if (candidate_pd.Count == 0 && argument_count == 0)
3783                                 return 1;
3784
3785                         if (best == null) {
3786                                 if (candidate_pd.Count == argument_count) {
3787                                         int x = 0;
3788                                         for (int j = argument_count; j > 0;) {
3789                                                 j--;
3790                                                 
3791                                                 Argument a = (Argument) args [j];
3792                                                 
3793                                                 x = BetterConversion (
3794                                                         ec, a, candidate_pd.ParameterType (j), null,
3795                                                         use_standard, loc);
3796                                                 
3797                                                 if (x <= 0)
3798                                                         break;
3799                                         }
3800                                         
3801                                         if (x > 0)
3802                                                 return 1;
3803                                         else
3804                                                 return 0;
3805                                         
3806                                 } else
3807                                         return 0;
3808                         }
3809
3810                         best_pd = GetParameterData (best);
3811
3812                         if (candidate_pd.Count == argument_count && best_pd.Count == argument_count) {
3813                                 int rating1 = 0, rating2 = 0;
3814                                 
3815                                 for (int j = argument_count; j > 0;) {
3816                                         j--;
3817                                         int x, y;
3818                                         
3819                                         Argument a = (Argument) args [j];
3820
3821                                         x = BetterConversion (ec, a, candidate_pd.ParameterType (j),
3822                                                               best_pd.ParameterType (j), use_standard, loc);
3823                                         y = BetterConversion (ec, a, best_pd.ParameterType (j),
3824                                                               candidate_pd.ParameterType (j), use_standard,
3825                                                               loc);
3826                                         
3827                                         rating1 += x;
3828                                         rating2 += y;
3829                                 }
3830
3831                                 if (rating1 > rating2)
3832                                         return 1;
3833                                 else
3834                                         return 0;
3835                         } else
3836                                 return 0;
3837                         
3838                 }
3839
3840                 public static string FullMethodDesc (MethodBase mb)
3841                 {
3842                         StringBuilder sb = new StringBuilder (mb.Name);
3843                         ParameterData pd = GetParameterData (mb);
3844
3845                         int count = pd.Count;
3846                         sb.Append (" (");
3847                         
3848                         for (int i = count; i > 0; ) {
3849                                 i--;
3850                                 
3851                                 sb.Append (TypeManager.CSharpName (pd.ParameterType (count - i - 1)));
3852                                 if (i != 0)
3853                                         sb.Append (", ");
3854                         }
3855                         
3856                         sb.Append (")");
3857                         return sb.ToString ();
3858                 }
3859
3860                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2)
3861                 {
3862                         MemberInfo [] miset;
3863                         MethodGroupExpr union;
3864                         
3865                         if (mg1 != null && mg2 != null) {
3866                                 
3867                                 MethodGroupExpr left_set = null, right_set = null;
3868                                 int length1 = 0, length2 = 0;
3869                                 
3870                                 left_set = (MethodGroupExpr) mg1;
3871                                 length1 = left_set.Methods.Length;
3872                                 
3873                                 right_set = (MethodGroupExpr) mg2;
3874                                 length2 = right_set.Methods.Length;
3875
3876                                 ArrayList common = new ArrayList ();
3877                                 
3878                                 for (int i = 0; i < left_set.Methods.Length; i++) {
3879                                         for (int j = 0; j < right_set.Methods.Length; j++) {
3880                                                 if (left_set.Methods [i] == right_set.Methods [j]) 
3881                                                         common.Add (left_set.Methods [i]);
3882                                         }
3883                                 }
3884                                 
3885                                 miset = new MemberInfo [length1 + length2 - common.Count];
3886
3887                                 left_set.Methods.CopyTo (miset, 0);
3888
3889                                 int k = 0;
3890                                 
3891                                 for (int j = 0; j < right_set.Methods.Length; j++)
3892                                         if (!common.Contains (right_set.Methods [j]))
3893                                                 miset [length1 + k++] = right_set.Methods [j];
3894                                 
3895                                 union = new MethodGroupExpr (miset);
3896
3897                                 return union;
3898
3899                         } else if (mg1 == null && mg2 != null) {
3900                                 
3901                                 MethodGroupExpr me = (MethodGroupExpr) mg2; 
3902                                 
3903                                 miset = new MemberInfo [me.Methods.Length];
3904                                 me.Methods.CopyTo (miset, 0);
3905
3906                                 union = new MethodGroupExpr (miset);
3907                                 
3908                                 return union;
3909
3910                         } else if (mg2 == null && mg1 != null) {
3911                                 
3912                                 MethodGroupExpr me = (MethodGroupExpr) mg1; 
3913                                 
3914                                 miset = new MemberInfo [me.Methods.Length];
3915                                 me.Methods.CopyTo (miset, 0);
3916
3917                                 union = new MethodGroupExpr (miset);
3918                                 
3919                                 return union;
3920                         }
3921                         
3922                         return null;
3923                 }
3924
3925                 // <summary>
3926                 //   Find the Applicable Function Members (7.4.2.1)
3927                 //
3928                 //   me: Method Group expression with the members to select.
3929                 //       it might contain constructors or methods (or anything
3930                 //       that maps to a method).
3931                 //
3932                 //   Arguments: ArrayList containing resolved Argument objects.
3933                 //
3934                 //   loc: The location if we want an error to be reported, or a Null
3935                 //        location for "probing" purposes.
3936                 //
3937                 //   inside_user_defined: controls whether OverloadResolve should use the 
3938                 //   ConvertImplicit or ConvertImplicitStandard during overload resolution.
3939                 //
3940                 //   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
3941                 //            that is the best match of me on Arguments.
3942                 //
3943                 // </summary>
3944                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
3945                                                           ArrayList Arguments, Location loc,
3946                                                           bool use_standard)
3947                 {
3948                         ArrayList afm = new ArrayList ();
3949                         int best_match_idx = -1;
3950                         MethodBase method = null;
3951                         int argument_count;
3952                         
3953                         for (int i = me.Methods.Length; i > 0; ){
3954                                 i--;
3955                                 MethodBase candidate  = me.Methods [i];
3956                                 int x;
3957
3958                                 x = BetterFunction (ec, Arguments, candidate, method, use_standard, loc);
3959                                 
3960                                 if (x == 0)
3961                                         continue;
3962                                 else {
3963                                         best_match_idx = i;
3964                                         method = me.Methods [best_match_idx];
3965                                 }
3966                         }
3967
3968                         if (Arguments == null)
3969                                 argument_count = 0;
3970                         else
3971                                 argument_count = Arguments.Count;
3972                         
3973                         ParameterData pd;
3974                         
3975                         // Now we see if we can at least find a method with the same number of arguments
3976                         // and then try doing implicit conversion on the arguments
3977                         if (best_match_idx == -1) {
3978                                 
3979                                 for (int i = me.Methods.Length; i > 0;) {
3980                                         i--;
3981                                         MethodBase mb = me.Methods [i];
3982                                         pd = GetParameterData (mb);
3983                                         
3984                                         if (pd.Count == argument_count) {
3985                                                 best_match_idx = i;
3986                                                 method = me.Methods [best_match_idx];
3987                                                 break;
3988                                         } else
3989                                                 continue;
3990                                 }
3991
3992                         }
3993
3994                         if (method == null)
3995                                 return null;
3996
3997                         // And now convert implicitly, each argument to the required type
3998                         
3999                         pd = GetParameterData (method);
4000
4001                         for (int j = argument_count; j > 0;) {
4002                                 j--;
4003                                 Argument a = (Argument) Arguments [j];
4004                                 Expression a_expr = a.Expr;
4005                                 Type parameter_type = pd.ParameterType (j);
4006                                 
4007                                 if (a_expr.Type != parameter_type){
4008                                         Expression conv;
4009
4010                                         if (use_standard)
4011                                                 conv = ConvertImplicitStandard (ec, a_expr, parameter_type,
4012                                                                                 Location.Null);
4013                                         else
4014                                                 conv = ConvertImplicit (ec, a_expr, parameter_type,
4015                                                                         Location.Null);
4016
4017                                         if (conv == null){
4018                                                 if (!Location.IsNull (loc)) {
4019                                                         Error (1502, loc,
4020                                                                "The best overloaded match for method '" + FullMethodDesc (method) +
4021                                                                "' has some invalid arguments");
4022                                                         Error (1503, loc,
4023                                                                "Argument " + (j+1) +
4024                                                                ": Cannot convert from '" + TypeManager.CSharpName (a_expr.Type)
4025                                                                + "' to '" + TypeManager.CSharpName (pd.ParameterType (j)) + "'");
4026                                                 }
4027                                                 return null;
4028                                         }
4029                                         //
4030                                         // Update the argument with the implicit conversion
4031                                         //
4032                                         if (a_expr != conv)
4033                                                 a.Expr = conv;
4034                                 }
4035                         }
4036                         
4037                         return method;
4038                 }
4039
4040                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4041                                                           ArrayList Arguments, Location loc)
4042                 {
4043                         return OverloadResolve (ec, me, Arguments, loc, false);
4044                 }
4045                         
4046                 public override Expression DoResolve (EmitContext ec)
4047                 {
4048                         //
4049                         // First, resolve the expression that is used to
4050                         // trigger the invocation
4051                         //
4052                         expr = expr.Resolve (ec);
4053                         if (expr == null)
4054                                 return null;
4055
4056                         if (!(expr is MethodGroupExpr)) {
4057                                 Type expr_type = expr.Type;
4058
4059                                 if (expr_type != null){
4060                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
4061                                         if (IsDelegate)
4062                                                 return (new DelegateInvocation (
4063                                                         this.expr, Arguments, Location)).Resolve (ec);
4064                                 }
4065                         }
4066
4067                         if (!(expr is MethodGroupExpr)){
4068                                 report118 (Location, this.expr, "method group");
4069                                 return null;
4070                         }
4071
4072                         //
4073                         // Next, evaluate all the expressions in the argument list
4074                         //
4075                         if (Arguments != null){
4076                                 for (int i = Arguments.Count; i > 0;){
4077                                         --i;
4078                                         Argument a = (Argument) Arguments [i];
4079
4080                                         if (!a.Resolve (ec))
4081                                                 return null;
4082                                 }
4083                         }
4084
4085                         method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments,
4086                                                   Location);
4087
4088                         if (method == null){
4089                                 Error (-6, Location,
4090                                        "Could not find any applicable function for this argument list");
4091                                 return null;
4092                         }
4093
4094                         if (method is MethodInfo)
4095                                 type = ((MethodInfo)method).ReturnType;
4096
4097                         eclass = ExprClass.Value;
4098                         return this;
4099                 }
4100
4101                 public static void EmitArguments (EmitContext ec, MethodBase method, ArrayList Arguments)
4102                 {
4103                         int top;
4104
4105                         if (Arguments != null)
4106                                 top = Arguments.Count;
4107                         else
4108                                 top = 0;
4109
4110                         for (int i = 0; i < top; i++){
4111                                 Argument a = (Argument) Arguments [i];
4112
4113                                 a.Emit (ec);
4114                         }
4115                 }
4116
4117                 public static void EmitCall (EmitContext ec,
4118                                              bool is_static, Expression instance_expr,
4119                                              MethodBase method, ArrayList Arguments)
4120                 {
4121                         ILGenerator ig = ec.ig;
4122                         bool struct_call = false;
4123                                 
4124                         if (!is_static){
4125                                 //
4126                                 // If this is ourselves, push "this"
4127                                 //
4128                                 if (instance_expr == null){
4129                                         ig.Emit (OpCodes.Ldarg_0);
4130                                 } else {
4131                                         //
4132                                         // Push the instance expression
4133                                         //
4134                                         if (instance_expr.Type.IsSubclassOf (TypeManager.value_type)){
4135
4136                                                 struct_call = true;
4137
4138                                                 //
4139                                                 // If the expression implements IMemoryLocation, then
4140                                                 // we can optimize and use AddressOf on the
4141                                                 // return.
4142                                                 //
4143                                                 // If not we have to use some temporary storage for
4144                                                 // it.
4145                                                 if (instance_expr is IMemoryLocation)
4146                                                         ((IMemoryLocation) instance_expr).AddressOf (ec);
4147                                                 else {
4148                                                         Type t = instance_expr.Type;
4149                                                         
4150                                                         instance_expr.Emit (ec);
4151                                                         LocalBuilder temp = ec.GetTemporaryStorage (t);
4152                                                         ig.Emit (OpCodes.Stloc, temp);
4153                                                         ig.Emit (OpCodes.Ldloca, temp);
4154                                                 }
4155                                         } else 
4156                                                 instance_expr.Emit (ec);
4157                                 }
4158                         }
4159
4160                         if (Arguments != null)
4161                                 EmitArguments (ec, method, Arguments);
4162
4163                         if (is_static || struct_call){
4164                                 if (method is MethodInfo)
4165                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
4166                                 else
4167                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
4168                         } else {
4169                                 if (method is MethodInfo)
4170                                         ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
4171                                 else
4172                                         ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
4173                         }
4174                 }
4175                 
4176                 public override void Emit (EmitContext ec)
4177                 {
4178                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
4179                         EmitCall (ec, method.IsStatic, mg.InstanceExpression, method, Arguments);
4180                 }
4181                 
4182                 public override void EmitStatement (EmitContext ec)
4183                 {
4184                         Emit (ec);
4185
4186                         // 
4187                         // Pop the return value if there is one
4188                         //
4189                         if (method is MethodInfo){
4190                                 if (((MethodInfo)method).ReturnType != TypeManager.void_type)
4191                                         ec.ig.Emit (OpCodes.Pop);
4192                         }
4193                 }
4194         }
4195
4196         public class New : ExpressionStatement {
4197
4198                 public enum NType {
4199                         Object,
4200                         Array
4201                 };
4202
4203                 public readonly NType     NewType;
4204                 public readonly ArrayList Arguments;
4205                 public readonly string    RequestedType;
4206
4207                 // These are for the case when we have an array
4208                 public readonly string    Rank;
4209                 public readonly ArrayList Initializers;
4210
4211                 Location Location;
4212                 MethodBase method = null;
4213
4214                 //
4215                 // If set, the new expression is for a value_target, and
4216                 // we will not leave anything on the stack.
4217                 //
4218                 Expression value_target;
4219                 
4220                 public New (string requested_type, ArrayList arguments, Location loc)
4221                 {
4222                         RequestedType = requested_type;
4223                         Arguments = arguments;
4224                         NewType = NType.Object;
4225                         Location = loc;
4226                 }
4227
4228                 public New (string requested_type, ArrayList exprs, string rank, ArrayList initializers, Location loc)
4229                 {
4230                         RequestedType = requested_type;
4231                         Rank          = rank;
4232                         Initializers  = initializers;
4233                         NewType       = NType.Array;
4234                         Location      = loc;
4235
4236                         Arguments = new ArrayList ();
4237
4238                         foreach (Expression e in exprs)
4239                                 Arguments.Add (new Argument (e, Argument.AType.Expression));
4240                         
4241                 }
4242
4243                 public static string FormLookupType (string base_type, int idx_count, string rank)
4244                 {
4245                         StringBuilder sb = new StringBuilder (base_type);
4246
4247                         sb.Append (rank);
4248
4249                         sb.Append ("[");
4250                         for (int i = 1; i < idx_count; i++)
4251                                 sb.Append (",");
4252                         sb.Append ("]");
4253                         
4254                         return sb.ToString ();
4255                 }
4256                 
4257                 public Expression ValueTypeVariable {
4258                         get {
4259                                 return value_target;
4260                         }
4261
4262                         set {
4263                                 value_target = value;
4264                         }
4265                 }
4266                 
4267                 public override Expression DoResolve (EmitContext ec)
4268                 {
4269                         if (NewType == NType.Object) {
4270
4271                                 type = ec.TypeContainer.LookupType (RequestedType, false);
4272                                 
4273                                 if (type == null)
4274                                         return null;
4275
4276                                 bool IsDelegate = TypeManager.IsDelegateType (type);
4277                                 
4278                                 if (IsDelegate)
4279                                         return (new NewDelegate (type, Arguments, Location)).Resolve (ec);
4280                                 
4281                                 Expression ml;
4282                                 
4283                                 ml = MemberLookup (ec, type, ".ctor", false,
4284                                                    MemberTypes.Constructor, AllBindingsFlags, Location);
4285                                 
4286                                 bool is_struct = false;
4287                                 is_struct = type.IsSubclassOf (TypeManager.value_type);
4288                                 
4289                                 if (! (ml is MethodGroupExpr)){
4290                                         if (!is_struct){
4291                                                 report118 (Location, ml, "method group");
4292                                                 return null;
4293                                         }
4294                                 }
4295                                 
4296                                 if (ml != null) {
4297                                         if (Arguments != null){
4298                                                 for (int i = Arguments.Count; i > 0;){
4299                                                         --i;
4300                                                         Argument a = (Argument) Arguments [i];
4301                                                         
4302                                                         if (!a.Resolve (ec))
4303                                                                 return null;
4304                                                 }
4305                                         }
4306                                         
4307                                         method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
4308                                                                              Arguments, Location);
4309                                 }
4310                                 
4311                                 
4312                                 if (method == null && !is_struct) {
4313                                         Error (-6, Location,
4314                                                "New invocation: Can not find a constructor for " +
4315                                                "this argument list");
4316                                         return null;
4317                                 }
4318                                 
4319                                 eclass = ExprClass.Value;
4320                                 return this;
4321                                 
4322                         }
4323                         
4324                         if (NewType == NType.Array) {
4325                                 throw new Exception ("Finish array creation");
4326                         }
4327                         
4328                         return null;
4329                 }
4330                 
4331                 //
4332                 // This DoEmit can be invoked in two contexts:
4333                 //    * As a mechanism that will leave a value on the stack (new object)
4334                 //    * As one that wont (init struct)
4335                 //
4336                 // You can control whether a value is required on the stack by passing
4337                 // need_value_on_stack.  The code *might* leave a value on the stack
4338                 // so it must be popped manually
4339                 //
4340                 // Returns whether a value is left on the stack
4341                 //
4342                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
4343                 {
4344                         if (method == null){
4345                                 IMemoryLocation ml = (IMemoryLocation) value_target;
4346
4347                                 ml.AddressOf (ec);
4348                         } else {
4349                                 Invocation.EmitArguments (ec, method, Arguments);
4350                                 ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
4351                                 return true;
4352                         }
4353
4354                         //
4355                         // It must be a value type, sanity check
4356                         //
4357                         if (value_target != null){
4358                                 ec.ig.Emit (OpCodes.Initobj, type);
4359
4360                                 if (need_value_on_stack){
4361                                         value_target.Emit (ec);
4362                                         return true;
4363                                 }
4364                                 return false;
4365                         }
4366
4367                         throw new Exception ("No method and no value type");
4368                 }
4369
4370                 public override void Emit (EmitContext ec)
4371                 {
4372                         DoEmit (ec, true);
4373                 }
4374                 
4375                 public override void EmitStatement (EmitContext ec)
4376                 {
4377                         if (DoEmit (ec, false))
4378                                 ec.ig.Emit (OpCodes.Pop);
4379                 }
4380         }
4381
4382         //
4383         // Represents the `this' construct
4384         //
4385         public class This : Expression, IStackStore, IMemoryLocation {
4386                 Location loc;
4387                 
4388                 public This (Location loc)
4389                 {
4390                         this.loc = loc;
4391                 }
4392
4393                 public override Expression DoResolve (EmitContext ec)
4394                 {
4395                         eclass = ExprClass.Variable;
4396                         type = ec.TypeContainer.TypeBuilder;
4397
4398                         if (ec.IsStatic){
4399                                 Report.Error (26, loc,
4400                                               "Keyword this not valid in static code");
4401                                 return null;
4402                         }
4403                         
4404                         return this;
4405                 }
4406
4407                 public Expression DoResolveLValue (EmitContext ec)
4408                 {
4409                         DoResolve (ec);
4410                         
4411                         if (ec.TypeContainer is Class){
4412                                 Report.Error (1604, loc, "Cannot assign to `this'");
4413                                 return null;
4414                         }
4415
4416                         return this;
4417                 }
4418
4419                 public override void Emit (EmitContext ec)
4420                 {
4421                         ec.ig.Emit (OpCodes.Ldarg_0);
4422                 }
4423
4424                 public void Store (EmitContext ec)
4425                 {
4426                         ec.ig.Emit (OpCodes.Starg, 0);
4427                 }
4428
4429                 public void AddressOf (EmitContext ec)
4430                 {
4431                         ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
4432                 }
4433         }
4434
4435         // <summary>
4436         //   Implements the typeof operator
4437         // </summary>
4438         public class TypeOf : Expression {
4439                 public readonly string QueriedType;
4440                 Type typearg;
4441                 
4442                 public TypeOf (string queried_type)
4443                 {
4444                         QueriedType = queried_type;
4445                 }
4446
4447                 public override Expression DoResolve (EmitContext ec)
4448                 {
4449                         typearg = ec.TypeContainer.LookupType (QueriedType, false);
4450
4451                         if (typearg == null)
4452                                 return null;
4453
4454                         type = TypeManager.type_type;
4455                         eclass = ExprClass.Type;
4456                         return this;
4457                 }
4458
4459                 public override void Emit (EmitContext ec)
4460                 {
4461                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
4462                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
4463                 }
4464         }
4465
4466         public class SizeOf : Expression {
4467                 public readonly string QueriedType;
4468                 
4469                 public SizeOf (string queried_type)
4470                 {
4471                         this.QueriedType = queried_type;
4472                 }
4473
4474                 public override Expression DoResolve (EmitContext ec)
4475                 {
4476                         // FIXME: Implement;
4477                         throw new Exception ("Unimplemented");
4478                         // return this;
4479                 }
4480
4481                 public override void Emit (EmitContext ec)
4482                 {
4483                         throw new Exception ("Implement me");
4484                 }
4485         }
4486
4487         public class MemberAccess : Expression {
4488                 public readonly string Identifier;
4489                 Expression expr;
4490                 Expression member_lookup;
4491                 Location loc;
4492                 
4493                 public MemberAccess (Expression expr, string id, Location l)
4494                 {
4495                         this.expr = expr;
4496                         Identifier = id;
4497                         loc = l;
4498                 }
4499
4500                 public Expression Expr {
4501                         get {
4502                                 return expr;
4503                         }
4504                 }
4505
4506                 void error176 (Location loc, string name)
4507                 {
4508                         Report.Error (176, loc, "Static member `" +
4509                                       name + "' cannot be accessed " +
4510                                       "with an instance reference, qualify with a " +
4511                                       "type name instead");
4512                 }
4513                 
4514                 public override Expression DoResolve (EmitContext ec)
4515                 {
4516                         //
4517                         // We are the sole users of ResolveWithSimpleName (ie, the only
4518                         // ones that can cope with it
4519                         //
4520                         expr = expr.ResolveWithSimpleName (ec);
4521
4522                         if (expr == null)
4523                                 return null;
4524
4525                         if (expr is SimpleName){
4526                                 SimpleName child_expr = (SimpleName) expr;
4527                                 
4528                                 expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
4529
4530                                 return expr.Resolve (ec);
4531                         }
4532                                         
4533                         member_lookup = MemberLookup (ec, expr.Type, Identifier, false, loc);
4534
4535                         if (member_lookup == null)
4536                                 return null;
4537                         
4538                         //
4539                         // Method Groups
4540                         //
4541                         if (member_lookup is MethodGroupExpr){
4542                                 MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
4543                                 
4544                                 //
4545                                 // Type.MethodGroup
4546                                 //
4547                                 if (expr is TypeExpr){
4548                                         if (!mg.RemoveInstanceMethods ()){
4549                                                 SimpleName.Error120 (loc, mg.Methods [0].Name); 
4550                                                 return null;
4551                                         }
4552
4553                                         return member_lookup;
4554                                 }
4555
4556                                 //
4557                                 // Instance.MethodGroup
4558                                 //
4559                                 if (!mg.RemoveStaticMethods ()){
4560                                         error176 (loc, mg.Methods [0].Name);
4561                                         return null;
4562                                 }
4563                                 
4564                                 mg.InstanceExpression = expr;
4565                                         
4566                                 return member_lookup;
4567                         }
4568
4569                         if (member_lookup is FieldExpr){
4570                                 FieldExpr fe = (FieldExpr) member_lookup;
4571
4572                                 if (expr is TypeExpr){
4573                                         if (!fe.FieldInfo.IsStatic){
4574                                                 error176 (loc, fe.FieldInfo.Name);
4575                                                 return null;
4576                                         }
4577                                         return member_lookup;
4578                                 } else {
4579                                         if (fe.FieldInfo.IsStatic){
4580                                                 error176 (loc, fe.FieldInfo.Name);
4581                                                 return null;
4582                                         }
4583                                         fe.InstanceExpression = expr;
4584
4585                                         return fe;
4586                                 }
4587                         }
4588
4589                         if (member_lookup is PropertyExpr){
4590                                 PropertyExpr pe = (PropertyExpr) member_lookup;
4591
4592                                 if (expr is TypeExpr){
4593                                         if (!pe.IsStatic){
4594                                                 SimpleName.Error120 (loc, pe.PropertyInfo.Name);
4595                                                 return null;
4596                                         }
4597                                         return pe;
4598                                 } else {
4599                                         if (pe.IsStatic){
4600                                                 error176 (loc, pe.PropertyInfo.Name);
4601                                                 return null;
4602                                         }
4603                                         pe.InstanceExpression = expr;
4604
4605                                         return pe;
4606                                 }
4607                         }
4608                         
4609                         Console.WriteLine ("Support for [" + member_lookup + "] is not present yet");
4610                         Environment.Exit (0);
4611                         return null;
4612                 }
4613
4614                 public override void Emit (EmitContext ec)
4615                 {
4616                         throw new Exception ("Should not happen I think");
4617                 }
4618
4619         }
4620
4621         // <summary>
4622         //   Fully resolved expression that evaluates to a type
4623         // </summary>
4624         public class TypeExpr : Expression {
4625                 public TypeExpr (Type t)
4626                 {
4627                         Type = t;
4628                         eclass = ExprClass.Type;
4629                 }
4630
4631                 override public Expression DoResolve (EmitContext ec)
4632                 {
4633                         return this;
4634                 }
4635
4636                 override public void Emit (EmitContext ec)
4637                 {
4638                         throw new Exception ("Implement me");
4639                 }
4640         }
4641
4642         // <summary>
4643         //   MethodGroup Expression.
4644         //  
4645         //   This is a fully resolved expression that evaluates to a type
4646         // </summary>
4647         public class MethodGroupExpr : Expression {
4648                 public MethodBase [] Methods;
4649                 Expression instance_expression = null;
4650                 
4651                 public MethodGroupExpr (MemberInfo [] mi)
4652                 {
4653                         Methods = new MethodBase [mi.Length];
4654                         mi.CopyTo (Methods, 0);
4655                         eclass = ExprClass.MethodGroup;
4656                 }
4657
4658                 public MethodGroupExpr (ArrayList l)
4659                 {
4660                         Methods = new MethodBase [l.Count];
4661
4662                         l.CopyTo (Methods, 0);
4663                         eclass = ExprClass.MethodGroup;
4664                 }
4665                 
4666                 //
4667                 // `A method group may have associated an instance expression' 
4668                 // 
4669                 public Expression InstanceExpression {
4670                         get {
4671                                 return instance_expression;
4672                         }
4673
4674                         set {
4675                                 instance_expression = value;
4676                         }
4677                 }
4678                 
4679                 override public Expression DoResolve (EmitContext ec)
4680                 {
4681                         return this;
4682                 }
4683
4684                 override public void Emit (EmitContext ec)
4685                 {
4686                         throw new Exception ("This should never be reached");
4687                 }
4688
4689                 bool RemoveMethods (bool keep_static)
4690                 {
4691                         ArrayList smethods = new ArrayList ();
4692                         int top = Methods.Length;
4693                         int i;
4694                         
4695                         for (i = 0; i < top; i++){
4696                                 MethodBase mb = Methods [i];
4697
4698                                 if (mb.IsStatic == keep_static)
4699                                         smethods.Add (mb);
4700                         }
4701
4702                         if (smethods.Count == 0)
4703                                 return false;
4704
4705                         Methods = new MethodBase [smethods.Count];
4706                         smethods.CopyTo (Methods, 0);
4707
4708                         return true;
4709                 }
4710                 
4711                 // <summary>
4712                 //   Removes any instance methods from the MethodGroup, returns
4713                 //   false if the resulting set is empty.
4714                 // </summary>
4715                 public bool RemoveInstanceMethods ()
4716                 {
4717                         return RemoveMethods (true);
4718                 }
4719
4720                 // <summary>
4721                 //   Removes any static methods from the MethodGroup, returns
4722                 //   false if the resulting set is empty.
4723                 // </summary>
4724                 public bool RemoveStaticMethods ()
4725                 {
4726                         return RemoveMethods (false);
4727                 }
4728         }
4729
4730         // <summary>
4731         //   Fully resolved expression that evaluates to a Field
4732         // </summary>
4733         public class FieldExpr : Expression, IStackStore, IMemoryLocation {
4734                 public readonly FieldInfo FieldInfo;
4735                 public Expression InstanceExpression;
4736                 Location loc;
4737                 
4738                 public FieldExpr (FieldInfo fi, Location l)
4739                 {
4740                         FieldInfo = fi;
4741                         eclass = ExprClass.Variable;
4742                         type = fi.FieldType;
4743                         loc = l;
4744                 }
4745
4746                 override public Expression DoResolve (EmitContext ec)
4747                 {
4748                         if (!FieldInfo.IsStatic){
4749                                 if (InstanceExpression == null){
4750                                         throw new Exception ("non-static FieldExpr without instance var\n" +
4751                                                              "You have to assign the Instance variable\n" +
4752                                                              "Of the FieldExpr to set this\n");
4753                                 }
4754
4755                                 InstanceExpression = InstanceExpression.Resolve (ec);
4756                                 if (InstanceExpression == null)
4757                                         return null;
4758                                 
4759                         }
4760                         return this;
4761                 }
4762
4763                 public Expression DoResolveLValue (EmitContext ec)
4764                 {
4765                         if (!FieldInfo.IsInitOnly)
4766                                 return this;
4767
4768                         //
4769                         // InitOnly fields can only be assigned in constructors
4770                         //
4771
4772                         if (ec.IsConstructor)
4773                                 return this;
4774
4775                         Report.Error (191, loc,
4776                                       "Readonly field can not be assigned outside " +
4777                                       "of constructor or variable initializer");
4778                         
4779                         return null;
4780                 }
4781
4782                 override public void Emit (EmitContext ec)
4783                 {
4784                         ILGenerator ig = ec.ig;
4785
4786                         if (FieldInfo.IsStatic)
4787                                 ig.Emit (OpCodes.Ldsfld, FieldInfo);
4788                         else {
4789                                 InstanceExpression.Emit (ec);
4790                                 
4791                                 ig.Emit (OpCodes.Ldfld, FieldInfo);
4792                         }
4793                 }
4794
4795                 public void Store (EmitContext ec)
4796                 {
4797                         if (FieldInfo.IsStatic)
4798                                 ec.ig.Emit (OpCodes.Stsfld, FieldInfo);
4799                         else
4800                                 ec.ig.Emit (OpCodes.Stfld, FieldInfo);
4801                 }
4802
4803                 public void AddressOf (EmitContext ec)
4804                 {
4805                         if (FieldInfo.IsStatic)
4806                                 ec.ig.Emit (OpCodes.Ldsflda, FieldInfo);
4807                         else {
4808                                 InstanceExpression.Emit (ec);
4809                                 ec.ig.Emit (OpCodes.Ldflda, FieldInfo);
4810                         }
4811                 }
4812         }
4813         
4814         // <summary>
4815         //   Expression that evaluates to a Property.  The Assign class
4816         //   might set the `Value' expression if we are in an assignment.
4817         //
4818         //   This is not an LValue because we need to re-write the expression, we
4819         //   can not take data from the stack and store it.  
4820         // </summary>
4821         public class PropertyExpr : ExpressionStatement, IAssignMethod {
4822                 public readonly PropertyInfo PropertyInfo;
4823                 public readonly bool IsStatic;
4824                 MethodInfo [] Accessors;
4825                 Location loc;
4826                 
4827                 Expression instance_expr;
4828                 
4829                 public PropertyExpr (PropertyInfo pi, Location l)
4830                 {
4831                         PropertyInfo = pi;
4832                         eclass = ExprClass.PropertyAccess;
4833                         IsStatic = false;
4834                         loc = l;
4835                         Accessors = TypeManager.GetAccessors (pi);
4836
4837                         if (Accessors != null)
4838                                 for (int i = 0; i < Accessors.Length; i++){
4839                                         if (Accessors [i] != null)
4840                                                 if (Accessors [i].IsStatic)
4841                                                         IsStatic = true;
4842                                 }
4843                         else
4844                                 Accessors = new MethodInfo [2];
4845                         
4846                         type = pi.PropertyType;
4847                 }
4848
4849                 //
4850                 // The instance expression associated with this expression
4851                 //
4852                 public Expression InstanceExpression {
4853                         set {
4854                                 instance_expr = value;
4855                         }
4856
4857                         get {
4858                                 return instance_expr;
4859                         }
4860                 }
4861
4862                 public bool VerifyAssignable ()
4863                 {
4864                         if (!PropertyInfo.CanWrite){
4865                                 Report.Error (200, loc, 
4866                                               "The property `" + PropertyInfo.Name +
4867                                               "' can not be assigned to, as it has not set accessor");
4868                                 return false;
4869                         }
4870
4871                         return true;
4872                 }
4873
4874                 override public Expression DoResolve (EmitContext ec)
4875                 {
4876                         if (!PropertyInfo.CanRead){
4877                                 Report.Error (154, loc, 
4878                                               "The property `" + PropertyInfo.Name +
4879                                               "' can not be used in " +
4880                                               "this context because it lacks a get accessor");
4881                                 return null;
4882                         }
4883
4884                         return this;
4885                 }
4886
4887                 override public void Emit (EmitContext ec)
4888                 {
4889                         Invocation.EmitCall (ec, IsStatic, instance_expr, Accessors [0], null);
4890                         
4891                 }
4892
4893                 //
4894                 // Implements the IAssignMethod interface for assignments
4895                 //
4896                 public void EmitAssign (EmitContext ec, Expression source)
4897                 {
4898                         Argument arg = new Argument (source, Argument.AType.Expression);
4899                         ArrayList args = new ArrayList ();
4900
4901                         args.Add (arg);
4902                         Invocation.EmitCall (ec, IsStatic, instance_expr, Accessors [1], args);
4903                 }
4904
4905                 override public void EmitStatement (EmitContext ec)
4906                 {
4907                         Emit (ec);
4908                         ec.ig.Emit (OpCodes.Pop);
4909                 }
4910         }
4911
4912         // <summary>
4913         //   Fully resolved expression that evaluates to a Expression
4914         // </summary>
4915         public class EventExpr : Expression {
4916                 public readonly EventInfo EventInfo;
4917                 Location loc;
4918                 
4919                 public EventExpr (EventInfo ei, Location loc)
4920                 {
4921                         EventInfo = ei;
4922                         this.loc = loc;
4923                         eclass = ExprClass.EventAccess;
4924                 }
4925
4926                 override public Expression DoResolve (EmitContext ec)
4927                 {
4928                         // We are born in resolved state. 
4929                         return this;
4930                 }
4931
4932                 override public void Emit (EmitContext ec)
4933                 {
4934                         throw new Exception ("Implement me");
4935                         // FIXME: Implement.
4936                 }
4937         }
4938         
4939         public class CheckedExpr : Expression {
4940
4941                 public Expression Expr;
4942
4943                 public CheckedExpr (Expression e)
4944                 {
4945                         Expr = e;
4946                 }
4947
4948                 public override Expression DoResolve (EmitContext ec)
4949                 {
4950                         Expr = Expr.Resolve (ec);
4951
4952                         if (Expr == null)
4953                                 return null;
4954
4955                         eclass = Expr.ExprClass;
4956                         type = Expr.Type;
4957                         return this;
4958                 }
4959
4960                 public override void Emit (EmitContext ec)
4961                 {
4962                         bool last_check = ec.CheckState;
4963                         
4964                         ec.CheckState = true;
4965                         Expr.Emit (ec);
4966                         ec.CheckState = last_check;
4967                 }
4968                 
4969         }
4970
4971         public class UnCheckedExpr : Expression {
4972
4973                 public Expression Expr;
4974
4975                 public UnCheckedExpr (Expression e)
4976                 {
4977                         Expr = e;
4978                 }
4979
4980                 public override Expression DoResolve (EmitContext ec)
4981                 {
4982                         Expr = Expr.Resolve (ec);
4983
4984                         if (Expr == null)
4985                                 return null;
4986
4987                         eclass = Expr.ExprClass;
4988                         type = Expr.Type;
4989                         return this;
4990                 }
4991
4992                 public override void Emit (EmitContext ec)
4993                 {
4994                         bool last_check = ec.CheckState;
4995                         
4996                         ec.CheckState = false;
4997                         Expr.Emit (ec);
4998                         ec.CheckState = last_check;
4999                 }
5000                 
5001         }
5002
5003         public class ElementAccess : Expression {
5004                 
5005                 public ArrayList  Arguments;
5006                 public Expression Expr;
5007                 public Location   loc;
5008                 
5009                 public ElementAccess (Expression e, ArrayList e_list, Location l)
5010                 {
5011                         Expr = e;
5012
5013                         Arguments = new ArrayList ();
5014                         foreach (Expression tmp in e_list)
5015                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
5016                         
5017                         loc  = l;
5018                 }
5019
5020                 bool CommonResolve (EmitContext ec)
5021                 {
5022                         Expr = Expr.Resolve (ec);
5023
5024                         if (Expr == null) 
5025                                 return false;
5026
5027                         if (Arguments == null)
5028                                 return false;
5029
5030                         for (int i = Arguments.Count; i > 0;){
5031                                 --i;
5032                                 Argument a = (Argument) Arguments [i];
5033                                 
5034                                 if (!a.Resolve (ec))
5035                                         return false;
5036                         }
5037
5038                         return true;
5039                 }
5040                                 
5041                 public override Expression DoResolve (EmitContext ec)
5042                 {
5043                         if (!CommonResolve (ec))
5044                                 return null;
5045
5046                         //
5047                         // We perform some simple tests, and then to "split" the emit and store
5048                         // code we create an instance of a different class, and return that.
5049                         //
5050                         // I am experimenting with this pattern.
5051                         //
5052                         if (Expr.Type == TypeManager.array_type)
5053                                 return (new ArrayAccess (this)).Resolve (ec);
5054                         else
5055                                 return (new IndexerAccess (this)).Resolve (ec);
5056                 }
5057
5058                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5059                 {
5060                         if (!CommonResolve (ec))
5061                                 return null;
5062
5063                         if (Expr.Type == TypeManager.array_type)
5064                                 return (new ArrayAccess (this)).ResolveLValue (ec, right_side);
5065                         else
5066                                 return (new IndexerAccess (this)).ResolveLValue (ec, right_side);
5067                 }
5068                 
5069                 public override void Emit (EmitContext ec)
5070                 {
5071                         throw new Exception ("Should never be reached");
5072                 }
5073         }
5074
5075         public class ArrayAccess : Expression, IStackStore {
5076                 //
5077                 // Points to our "data" repository
5078                 //
5079                 ElementAccess ea;
5080                 
5081                 public ArrayAccess (ElementAccess ea_data)
5082                 {
5083                         ea = ea_data;
5084                         eclass = ExprClass.Variable;
5085
5086                         //
5087                         // FIXME: Figure out the type here
5088                         //
5089                 }
5090
5091                 Expression CommonResolve (EmitContext ec)
5092                 {
5093                         return this;
5094                 }
5095                 
5096                 public override Expression DoResolve (EmitContext ec)
5097                 {
5098                         if (ea.Expr.ExprClass != ExprClass.Variable) {
5099                                 report118 (ea.loc, ea.Expr, "variable");
5100                                 return null;
5101                         }
5102                         
5103                         throw new Exception ("Implement me");
5104                 }
5105
5106                 public void Store (EmitContext ec)
5107                 {
5108                         throw new Exception ("Implement me !");
5109                 }
5110
5111                 public override void Emit (EmitContext ec)
5112                 {
5113                         throw new Exception ("Implement me !");
5114                 }
5115         }
5116
5117         class Indexers {
5118                 public ArrayList getters, setters;
5119                 static Hashtable map;
5120
5121                 static Indexers ()
5122                 {
5123                         map = new Hashtable ();
5124                 }
5125
5126                 Indexers (MemberInfo [] mi)
5127                 {
5128                         foreach (PropertyInfo property in mi){
5129                                 MethodInfo get, set;
5130                                 
5131                                 get = property.GetGetMethod (true);
5132                                 if (get != null){
5133                                         if (getters == null)
5134                                                 getters = new ArrayList ();
5135
5136                                         getters.Add (get);
5137                                 }
5138                                 
5139                                 set = property.GetSetMethod (true);
5140                                 if (set != null){
5141                                         if (setters == null)
5142                                                 setters = new ArrayList ();
5143                                         setters.Add (set);
5144                                 }
5145                         }
5146                 }
5147                 
5148                 static public Indexers GetIndexersForType (Type t, TypeManager tm, Location loc) 
5149                 {
5150                         Indexers ix = (Indexers) map [t];
5151                         string p_name = TypeManager.IndexerPropertyName (t);
5152                         
5153                         if (ix != null)
5154                                 return ix;
5155
5156                         MemberInfo [] mi = tm.FindMembers (
5157                                 t, MemberTypes.Property,
5158                                 BindingFlags.Public | BindingFlags.Instance,
5159                                 Type.FilterName, p_name);
5160
5161                         if (mi == null || mi.Length == 0){
5162                                 Report.Error (21, loc,
5163                                               "Type `" + TypeManager.CSharpName (t) + "' does not have " +
5164                                               "any indexers defined");
5165                                 return null;
5166                         }
5167                         
5168                         ix = new Indexers (mi);
5169                         map [t] = ix;
5170
5171                         return ix;
5172                 }
5173         }
5174         
5175         public class IndexerAccess : Expression, IAssignMethod {
5176                 //
5177                 // Points to our "data" repository
5178                 //
5179                 ElementAccess ea;
5180                 MethodInfo get, set;
5181                 Indexers ilist;
5182                 ArrayList set_arguments;
5183                 
5184                 public IndexerAccess (ElementAccess ea_data)
5185                 {
5186                         ea = ea_data;
5187                         eclass = ExprClass.Value;
5188                 }
5189
5190                 public bool VerifyAssignable (Expression source)
5191                 {
5192                         throw new Exception ("Implement me!");
5193                 }
5194
5195                 public override Expression DoResolve (EmitContext ec)
5196                 {
5197                         Type indexer_type = ea.Expr.Type;
5198                         
5199                         //
5200                         // Step 1: Query for all `Item' *properties*.  Notice
5201                         // that the actual methods are pointed from here.
5202                         //
5203                         // This is a group of properties, piles of them.  
5204
5205                         if (ilist == null)
5206                                 ilist = Indexers.GetIndexersForType (
5207                                         indexer_type, ec.TypeContainer.RootContext.TypeManager, ea.loc);
5208                         
5209                         if (ilist != null && ilist.getters != null && ilist.getters.Count > 0)
5210                                 get = (MethodInfo) Invocation.OverloadResolve (
5211                                         ec, new MethodGroupExpr (ilist.getters), ea.Arguments, ea.loc);
5212
5213                         if (get == null){
5214                                 Report.Error (154, ea.loc,
5215                                               "indexer can not be used in this context, because " +
5216                                               "it lacks a `get' accessor");
5217                                         return null;
5218                         }
5219                                 
5220                         type = get.ReturnType;
5221                         eclass = ExprClass.Value;
5222                         return this;
5223                 }
5224
5225                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
5226                 {
5227                         Type indexer_type = ea.Expr.Type;
5228                         Type right_type = right_side.Type;
5229
5230                         if (ilist == null)
5231                                 ilist = Indexers.GetIndexersForType (
5232                                         indexer_type, ec.TypeContainer.RootContext.TypeManager, ea.loc);
5233
5234                         if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
5235                                 set_arguments = (ArrayList) ea.Arguments.Clone ();
5236                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
5237
5238                                 set = (MethodInfo) Invocation.OverloadResolve (
5239                                         ec, new MethodGroupExpr (ilist.setters), set_arguments, ea.loc);
5240                         }
5241                         
5242                         if (set == null){
5243                                 Report.Error (200, ea.loc,
5244                                               "indexer X.this [" + TypeManager.CSharpName (right_type) +
5245                                               "] lacks a `set' accessor");
5246                                         return null;
5247                         }
5248
5249                         type = TypeManager.void_type;
5250                         eclass = ExprClass.IndexerAccess;
5251                         return this;
5252                 }
5253                 
5254                 public override void Emit (EmitContext ec)
5255                 {
5256                         Invocation.EmitCall (ec, false, ea.Expr, get, ea.Arguments);
5257                 }
5258
5259                 //
5260                 // source is ignored, because we already have a copy of it from the
5261                 // LValue resolution and we have already constructed a pre-cached
5262                 // version of the arguments (ea.set_arguments);
5263                 //
5264                 public void EmitAssign (EmitContext ec, Expression source)
5265                 {
5266                         Invocation.EmitCall (ec, false, ea.Expr, set, set_arguments);
5267                 }
5268         }
5269         
5270         public class BaseAccess : Expression {
5271
5272                 public enum BaseAccessType {
5273                         Member,
5274                         Indexer
5275                 };
5276                 
5277                 public readonly BaseAccessType BAType;
5278                 public readonly string         Member;
5279                 public readonly ArrayList      Arguments;
5280
5281                 public BaseAccess (BaseAccessType t, string member, ArrayList args)
5282                 {
5283                         BAType = t;
5284                         Member = member;
5285                         Arguments = args;
5286                         
5287                 }
5288
5289                 public override Expression DoResolve (EmitContext ec)
5290                 {
5291                         // FIXME: Implement;
5292                         throw new Exception ("Unimplemented");
5293                         // return this;
5294                 }
5295
5296                 public override void Emit (EmitContext ec)
5297                 {
5298                         throw new Exception ("Unimplemented");
5299                 }
5300         }
5301
5302         // <summary>
5303         //   This class exists solely to pass the Type around and to be a dummy
5304         //   that can be passed to the conversion functions (this is used by
5305         //   foreach implementation to typecast the object return value from
5306         //   get_Current into the proper type.  All code has been generated and
5307         //   we only care about the side effect conversions to be performed
5308         // </summary>
5309         
5310         public class EmptyExpression : Expression {
5311                 public EmptyExpression ()
5312                 {
5313                         type = TypeManager.object_type;
5314                         eclass = ExprClass.Value;
5315                 }
5316
5317                 public override Expression DoResolve (EmitContext ec)
5318                 {
5319                         return this;
5320                 }
5321
5322                 public override void Emit (EmitContext ec)
5323                 {
5324                         // nothing, as we only exist to not do anything.
5325                 }
5326         }
5327
5328         public class UserCast : Expression {
5329                 MethodBase method;
5330                 Expression source;
5331                 
5332                 public UserCast (MethodInfo method, Expression source)
5333                 {
5334                         this.method = method;
5335                         this.source = source;
5336                         type = method.ReturnType;
5337                         eclass = ExprClass.Value;
5338                 }
5339
5340                 public override Expression DoResolve (EmitContext ec)
5341                 {
5342                         //
5343                         // We are born fully resolved
5344                         //
5345                         return this;
5346                 }
5347
5348                 public override void Emit (EmitContext ec)
5349                 {
5350                         ILGenerator ig = ec.ig;
5351
5352                         source.Emit (ec);
5353                         
5354                         if (method is MethodInfo)
5355                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
5356                         else
5357                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5358
5359                 }
5360
5361         }
5362 }