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