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