2003-05-09 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.Reflection;
16         using System.Reflection.Emit;
17         using System.Text;
18
19         /// <summary>
20         ///   This is just a helper class, it is generated by Unary, UnaryMutator
21         ///   when an overloaded method has been found.  It just emits the code for a
22         ///   static call.
23         /// </summary>
24         public class StaticCallExpr : ExpressionStatement {
25                 ArrayList args;
26                 MethodInfo mi;
27
28                 public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
29                 {
30                         mi = m;
31                         args = a;
32
33                         type = m.ReturnType;
34                         eclass = ExprClass.Value;
35                         loc = l;
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, loc);
69                 }
70
71                 public override void EmitStatement (EmitContext ec)
72                 {
73                         Emit (ec);
74                         if (TypeManager.TypeToCoreType (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                 public Operator Oper;
95                 public Expression Expr;
96                 
97                 public Unary (Operator op, Expression expr, Location loc)
98                 {
99                         this.Oper = op;
100                         this.Expr = expr;
101                         this.loc = loc;
102                 }
103
104                 /// <summary>
105                 ///   Returns a stringified representation of the Operator
106                 /// </summary>
107                 static public string OperName (Operator oper)
108                 {
109                         switch (oper){
110                         case Operator.UnaryPlus:
111                                 return "+";
112                         case Operator.UnaryNegation:
113                                 return "-";
114                         case Operator.LogicalNot:
115                                 return "!";
116                         case Operator.OnesComplement:
117                                 return "~";
118                         case Operator.AddressOf:
119                                 return "&";
120                         case Operator.Indirection:
121                                 return "*";
122                         }
123
124                         return oper.ToString ();
125                 }
126
127                 public static readonly string [] oper_names;
128
129                 static Unary ()
130                 {
131                         oper_names = new string [(int)Operator.TOP];
132
133                         oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
134                         oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
135                         oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
136                         oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
137                         oper_names [(int) Operator.Indirection] = "op_Indirection";
138                         oper_names [(int) Operator.AddressOf] = "op_AddressOf";
139                 }
140
141                 void Error23 (Type t)
142                 {
143                         Error (
144                                 23, "Operator " + OperName (Oper) +
145                                 " cannot be applied to operand of type `" +
146                                 TypeManager.CSharpName (t) + "'");
147                 }
148
149                 /// <remarks>
150                 ///   The result has been already resolved:
151                 ///
152                 ///   FIXME: a minus constant -128 sbyte cant be turned into a
153                 ///   constant byte.
154                 /// </remarks>
155                 static Expression TryReduceNegative (Constant expr)
156                 {
157                         Expression e = null;
158
159                         if (expr is IntConstant)
160                                 e = new IntConstant (-((IntConstant) expr).Value);
161                         else if (expr is UIntConstant){
162                                 uint value = ((UIntConstant) expr).Value;
163
164                                 if (value < 2147483649)
165                                         return new IntConstant (-(int)value);
166                                 else
167                                         e = new LongConstant (-value);
168                         }
169                         else if (expr is LongConstant)
170                                 e = new LongConstant (-((LongConstant) expr).Value);
171                         else if (expr is ULongConstant){
172                                 ulong value = ((ULongConstant) expr).Value;
173
174                                 if (value < 9223372036854775809)
175                                         return new LongConstant(-(long)value);
176                         }
177                         else if (expr is FloatConstant)
178                                 e = new FloatConstant (-((FloatConstant) expr).Value);
179                         else if (expr is DoubleConstant)
180                                 e = new DoubleConstant (-((DoubleConstant) expr).Value);
181                         else if (expr is DecimalConstant)
182                                 e = new DecimalConstant (-((DecimalConstant) expr).Value);
183                         else if (expr is ShortConstant)
184                                 e = new IntConstant (-((ShortConstant) expr).Value);
185                         else if (expr is UShortConstant)
186                                 e = new IntConstant (-((UShortConstant) expr).Value);
187                         return e;
188                 }
189
190                 // <summary>
191                 //   This routine will attempt to simplify the unary expression when the
192                 //   argument is a constant.  The result is returned in `result' and the
193                 //   function returns true or false depending on whether a reduction
194                 //   was performed or not
195                 // </summary>
196                 bool Reduce (EmitContext ec, Constant e, out Expression result)
197                 {
198                         Type expr_type = e.Type;
199                         
200                         switch (Oper){
201                         case Operator.UnaryPlus:
202                                 result = e;
203                                 return true;
204                                 
205                         case Operator.UnaryNegation:
206                                 result = TryReduceNegative (e);
207                                 return true;
208                                 
209                         case Operator.LogicalNot:
210                                 if (expr_type != TypeManager.bool_type) {
211                                         result = null;
212                                         Error23 (expr_type);
213                                         return false;
214                                 }
215                                 
216                                 BoolConstant b = (BoolConstant) e;
217                                 result = new BoolConstant (!(b.Value));
218                                 return true;
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
227                                         result = null;
228                                         if (ImplicitConversionExists (ec, e, TypeManager.int32_type)){
229                                                 result = new Cast (new TypeExpr (TypeManager.int32_type, loc), e, loc);
230                                                 result = result.Resolve (ec);
231                                         } else if (ImplicitConversionExists (ec, e, TypeManager.uint32_type)){
232                                                 result = new Cast (new TypeExpr (TypeManager.uint32_type, loc), e, loc);
233                                                 result = result.Resolve (ec);
234                                         } else if (ImplicitConversionExists (ec, e, TypeManager.int64_type)){
235                                                 result = new Cast (new TypeExpr (TypeManager.int64_type, loc), e, loc);
236                                                 result = result.Resolve (ec);
237                                         } else if (ImplicitConversionExists (ec, e, TypeManager.uint64_type)){
238                                                 result = new Cast (new TypeExpr (TypeManager.uint64_type, loc), e, loc);
239                                                 result = result.Resolve (ec);
240                                         }
241
242                                         if (result == null || !(result is Constant)){
243                                                 result = null;
244                                                 Error23 (expr_type);
245                                                 return false;
246                                         }
247
248                                         expr_type = result.Type;
249                                         e = (Constant) result;
250                                 }
251
252                                 if (e is EnumConstant){
253                                         EnumConstant enum_constant = (EnumConstant) e;
254                                         Expression reduced;
255                                         
256                                         if (Reduce (ec, enum_constant.Child, out reduced)){
257                                                 result = new EnumConstant ((Constant) reduced, enum_constant.Type);
258                                                 return true;
259                                         } else {
260                                                 result = null;
261                                                 return false;
262                                         }
263                                 }
264
265                                 if (expr_type == TypeManager.int32_type){
266                                         result = new IntConstant (~ ((IntConstant) e).Value);
267                                 } else if (expr_type == TypeManager.uint32_type){
268                                         result = new UIntConstant (~ ((UIntConstant) e).Value);
269                                 } else if (expr_type == TypeManager.int64_type){
270                                         result = new LongConstant (~ ((LongConstant) e).Value);
271                                 } else if (expr_type == TypeManager.uint64_type){
272                                         result = new ULongConstant (~ ((ULongConstant) e).Value);
273                                 } else {
274                                         result = null;
275                                         Error23 (expr_type);
276                                         return false;
277                                 }
278                                 return true;
279
280                         case Operator.AddressOf:
281                                 result = this;
282                                 return false;
283
284                         case Operator.Indirection:
285                                 result = this;
286                                 return false;
287                         }
288                         throw new Exception ("Can not constant fold: " + Oper.ToString());
289                 }
290
291                 Expression ResolveOperator (EmitContext ec)
292                 {
293                         Type expr_type = Expr.Type;
294
295                         //
296                         // Step 1: Perform Operator Overload location
297                         //
298                         Expression mg;
299                         string op_name;
300                         
301                         op_name = oper_names [(int) Oper];
302
303                         mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
304                         
305                         if (mg != null) {
306                                 Expression e = StaticCallExpr.MakeSimpleCall (
307                                         ec, (MethodGroupExpr) mg, Expr, loc);
308
309                                 if (e == null){
310                                         Error23 (expr_type);
311                                         return null;
312                                 }
313                                 
314                                 return e;
315                         }
316
317                         // Only perform numeric promotions on:
318                         // +, - 
319
320                         if (expr_type == null)
321                                 return null;
322                         
323                         //
324                         // Step 2: Default operations on CLI native types.
325                         //
326
327                         // Attempt to use a constant folding operation.
328                         if (Expr is Constant){
329                                 Expression result;
330                                 
331                                 if (Reduce (ec, (Constant) Expr, out result))
332                                         return result;
333                         }
334
335                         switch (Oper){
336                         case Operator.LogicalNot:
337                                 if (expr_type != TypeManager.bool_type) {
338                                         Expr = ResolveBoolean (ec, Expr, loc);
339                                         if (Expr == null){
340                                                 Error23 (expr_type);
341                                                 return null;
342                                         }
343                                 }
344                                 
345                                 type = TypeManager.bool_type;
346                                 return this;
347
348                         case Operator.OnesComplement:
349                                 if (!((expr_type == TypeManager.int32_type) ||
350                                       (expr_type == TypeManager.uint32_type) ||
351                                       (expr_type == TypeManager.int64_type) ||
352                                       (expr_type == TypeManager.uint64_type) ||
353                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){
354                                         Expression e;
355
356                                         e = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
357                                         if (e != null){
358                                                 type = TypeManager.int32_type;
359                                                 return this;
360                                         }
361                                         e = ConvertImplicit (ec, Expr, TypeManager.uint32_type, loc);
362                                         if (e != null){
363                                                 type = TypeManager.uint32_type;
364                                                 return this;
365                                         }
366                                         e = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
367                                         if (e != null){
368                                                 type = TypeManager.int64_type;
369                                                 return this;
370                                         }
371                                         e = ConvertImplicit (ec, Expr, TypeManager.uint64_type, loc);
372                                         if (e != null){
373                                                 type = TypeManager.uint64_type;
374                                                 return this;
375                                         }
376                                         Error23 (expr_type);
377                                         return null;
378                                 }
379                                 type = expr_type;
380                                 return this;
381
382                         case Operator.AddressOf:
383                                 if (Expr.eclass != ExprClass.Variable){
384                                         Error (211, "Cannot take the address of non-variables");
385                                         return null;
386                                 }
387                                 
388                                 if (!ec.InUnsafe) {
389                                         UnsafeError (loc); 
390                                         return null;
391                                 }
392                                 
393                                 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
394                                         return null;
395                                 }
396
397                                 type = TypeManager.GetPointerType (Expr.Type);
398                                 return this;
399
400                         case Operator.Indirection:
401                                 if (!ec.InUnsafe){
402                                         UnsafeError (loc);
403                                         return null;
404                                 }
405                                 
406                                 if (!expr_type.IsPointer){
407                                         Error (193, "The * or -> operator can only be applied to pointers");
408                                         return null;
409                                 }
410                                 
411                                 //
412                                 // We create an Indirection expression, because
413                                 // it can implement the IMemoryLocation.
414                                 // 
415                                 return new Indirection (Expr, loc);
416                         
417                         case Operator.UnaryPlus:
418                                 //
419                                 // A plus in front of something is just a no-op, so return the child.
420                                 //
421                                 return Expr;
422
423                         case Operator.UnaryNegation:
424                                 //
425                                 // Deals with -literals
426                                 // int     operator- (int x)
427                                 // long    operator- (long x)
428                                 // float   operator- (float f)
429                                 // double  operator- (double d)
430                                 // decimal operator- (decimal d)
431                                 //
432                                 Expression expr = null;
433
434                                 //
435                                 // transform - - expr into expr
436                                 //
437                                 if (Expr is Unary){
438                                         Unary unary = (Unary) Expr;
439                                         
440                                         if (unary.Oper == Operator.UnaryNegation)
441                                                 return unary.Expr;
442                                 }
443
444                                 //
445                                 // perform numeric promotions to int,
446                                 // long, double.
447                                 //
448                                 //
449                                 // The following is inneficient, because we call
450                                 // ConvertImplicit too many times.
451                                 //
452                                 // It is also not clear if we should convert to Float
453                                 // or Double initially.
454                                 //
455                                 if (expr_type == TypeManager.uint32_type){
456                                         //
457                                         // FIXME: handle exception to this rule that
458                                         // permits the int value -2147483648 (-2^31) to
459                                         // bt wrote as a decimal interger literal
460                                         //
461                                         type = TypeManager.int64_type;
462                                         Expr = ConvertImplicit (ec, Expr, type, loc);
463                                         return this;
464                                 }
465
466                                 if (expr_type == TypeManager.uint64_type){
467                                         //
468                                         // FIXME: Handle exception of `long value'
469                                         // -92233720368547758087 (-2^63) to be wrote as
470                                         // decimal integer literal.
471                                         //
472                                         Error23 (expr_type);
473                                         return null;
474                                 }
475
476                                 if (expr_type == TypeManager.float_type){
477                                         type = expr_type;
478                                         return this;
479                                 }
480                                 
481                                 expr = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
482                                 if (expr != null){
483                                         Expr = expr;
484                                         type = expr.Type;
485                                         return this;
486                                 } 
487
488                                 expr = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
489                                 if (expr != null){
490                                         Expr = expr;
491                                         type = expr.Type;
492                                         return this;
493                                 }
494
495                                 expr = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
496                                 if (expr != null){
497                                         Expr = expr;
498                                         type = expr.Type;
499                                         return this;
500                                 }
501                                 
502                                 Error23 (expr_type);
503                                 return null;
504                         }
505
506                         Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
507                                TypeManager.CSharpName (expr_type) + "'");
508                         return null;
509                 }
510
511                 public override Expression DoResolve (EmitContext ec)
512                 {
513                         if (Oper == Operator.AddressOf)
514                                 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
515                         else
516                                 Expr = Expr.Resolve (ec);
517                         
518                         if (Expr == null)
519                                 return null;
520
521                         eclass = ExprClass.Value;
522                         return ResolveOperator (ec);
523                 }
524
525                 public override void Emit (EmitContext ec)
526                 {
527                         ILGenerator ig = ec.ig;
528                         Type expr_type = Expr.Type;
529                         
530                         switch (Oper) {
531                         case Operator.UnaryPlus:
532                                 throw new Exception ("This should be caught by Resolve");
533                                 
534                         case Operator.UnaryNegation:
535                                 Expr.Emit (ec);
536                                 ig.Emit (OpCodes.Neg);
537                                 break;
538                                 
539                         case Operator.LogicalNot:
540                                 Expr.Emit (ec);
541                                 ig.Emit (OpCodes.Ldc_I4_0);
542                                 ig.Emit (OpCodes.Ceq);
543                                 break;
544                                 
545                         case Operator.OnesComplement:
546                                 Expr.Emit (ec);
547                                 ig.Emit (OpCodes.Not);
548                                 break;
549                                 
550                         case Operator.AddressOf:
551                                 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
552                                 break;
553                                 
554                         default:
555                                 throw new Exception ("This should not happen: Operator = "
556                                                      + Oper.ToString ());
557                         }
558                 }
559
560                 /// <summary>
561                 ///   This will emit the child expression for `ec' avoiding the logical
562                 ///   not.  The parent will take care of changing brfalse/brtrue
563                 /// </summary>
564                 public void EmitLogicalNot (EmitContext ec)
565                 {
566                         if (Oper != Operator.LogicalNot)
567                                 throw new Exception ("EmitLogicalNot can only be called with !expr");
568
569                         Expr.Emit (ec);
570                 }
571
572                 public override string ToString ()
573                 {
574                         return "Unary (" + Oper + ", " + Expr + ")";
575                 }
576                 
577         }
578
579         //
580         // Unary operators are turned into Indirection expressions
581         // after semantic analysis (this is so we can take the address
582         // of an indirection).
583         //
584         public class Indirection : Expression, IMemoryLocation, IAssignMethod {
585                 Expression expr;
586                 LocalTemporary temporary;
587                 bool have_temporary;
588                 
589                 public Indirection (Expression expr, Location l)
590                 {
591                         this.expr = expr;
592                         this.type = TypeManager.TypeToCoreType (expr.Type.GetElementType ());
593                         eclass = ExprClass.Variable;
594                         loc = l;
595                 }
596
597                 void LoadExprValue (EmitContext ec)
598                 {
599                 }
600                 
601                 public override void Emit (EmitContext ec)
602                 {
603                         ILGenerator ig = ec.ig;
604
605                         if (temporary != null){
606                                 if (have_temporary){
607                                         temporary.Emit (ec);
608                                         return;
609                                 }
610                                 expr.Emit (ec);
611                                 ec.ig.Emit (OpCodes.Dup);
612                                 temporary.Store (ec);
613                                 have_temporary = true;
614                         } else
615                                 expr.Emit (ec);
616                         
617                         LoadFromPtr (ig, Type);
618                 }
619
620                 public void EmitAssign (EmitContext ec, Expression source)
621                 {
622                         if (temporary != null){
623                                 if (have_temporary)
624                                         temporary.Emit (ec);
625                                 else {
626                                         expr.Emit (ec);
627                                         ec.ig.Emit (OpCodes.Dup);
628                                         temporary.Store (ec);
629                                         have_temporary = true;
630                                 }
631                         } else 
632                                 expr.Emit (ec);
633
634                         source.Emit (ec);
635                         StoreFromPtr (ec.ig, type);
636                 }
637                 
638                 public void AddressOf (EmitContext ec, AddressOp Mode)
639                 {
640                         if (temporary != null){
641                                 if (have_temporary){
642                                         temporary.Emit (ec);
643                                         return;
644                                 }
645                                 expr.Emit (ec);
646                                 ec.ig.Emit (OpCodes.Dup);
647                                 temporary.Store (ec);
648                                 have_temporary = true;
649                         } else
650                                 expr.Emit (ec);
651                 }
652
653                 public override Expression DoResolve (EmitContext ec)
654                 {
655                         //
656                         // Born fully resolved
657                         //
658                         return this;
659                 }
660
661                 public new void CacheTemporaries (EmitContext ec)
662                 {
663                         temporary = new LocalTemporary (ec, type);
664                 }
665
666                 public override string ToString ()
667                 {
668                         return "*(" + expr + ")";
669                 }
670         }
671         
672         /// <summary>
673         ///   Unary Mutator expressions (pre and post ++ and --)
674         /// </summary>
675         ///
676         /// <remarks>
677         ///   UnaryMutator implements ++ and -- expressions.   It derives from
678         ///   ExpressionStatement becuase the pre/post increment/decrement
679         ///   operators can be used in a statement context.
680         ///
681         /// FIXME: Idea, we could split this up in two classes, one simpler
682         /// for the common case, and one with the extra fields for more complex
683         /// classes (indexers require temporary access;  overloaded require method)
684         ///
685         /// </remarks>
686         public class UnaryMutator : ExpressionStatement {
687                 [Flags]
688                 public enum Mode : byte {
689                         IsIncrement    = 0,
690                         IsDecrement    = 1,
691                         IsPre          = 0,
692                         IsPost         = 2,
693                         
694                         PreIncrement   = 0,
695                         PreDecrement   = IsDecrement,
696                         PostIncrement  = IsPost,
697                         PostDecrement  = IsPost | IsDecrement
698                 }
699                 
700                 Mode mode;
701                 Expression expr;
702                 LocalTemporary temp_storage;
703
704                 //
705                 // This is expensive for the simplest case.
706                 //
707                 Expression method;
708                         
709                 public UnaryMutator (Mode m, Expression e, Location l)
710                 {
711                         mode = m;
712                         loc = l;
713                         expr = e;
714                 }
715
716                 static string OperName (Mode mode)
717                 {
718                         return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
719                                 "++" : "--";
720                 }
721                 
722                 void Error23 (Type t)
723                 {
724                         Error (
725                                 23, "Operator " + OperName (mode) + 
726                                 " cannot be applied to operand of type `" +
727                                 TypeManager.CSharpName (t) + "'");
728                 }
729
730                 /// <summary>
731                 ///   Returns whether an object of type `t' can be incremented
732                 ///   or decremented with add/sub (ie, basically whether we can
733                 ///   use pre-post incr-decr operations on it, but it is not a
734                 ///   System.Decimal, which we require operator overloading to catch)
735                 /// </summary>
736                 static bool IsIncrementableNumber (Type t)
737                 {
738                         return (t == TypeManager.sbyte_type) ||
739                                 (t == TypeManager.byte_type) ||
740                                 (t == TypeManager.short_type) ||
741                                 (t == TypeManager.ushort_type) ||
742                                 (t == TypeManager.int32_type) ||
743                                 (t == TypeManager.uint32_type) ||
744                                 (t == TypeManager.int64_type) ||
745                                 (t == TypeManager.uint64_type) ||
746                                 (t == TypeManager.char_type) ||
747                                 (t.IsSubclassOf (TypeManager.enum_type)) ||
748                                 (t == TypeManager.float_type) ||
749                                 (t == TypeManager.double_type) ||
750                                 (t.IsPointer && t != TypeManager.void_ptr_type);
751                 }
752
753                 Expression ResolveOperator (EmitContext ec)
754                 {
755                         Type expr_type = expr.Type;
756
757                         //
758                         // Step 1: Perform Operator Overload location
759                         //
760                         Expression mg;
761                         string op_name;
762                         
763                         if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
764                                 op_name = "op_Increment";
765                         else 
766                                 op_name = "op_Decrement";
767
768                         mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
769
770                         if (mg == null && expr_type.BaseType != null)
771                                 mg = MemberLookup (ec, expr_type.BaseType, op_name,
772                                                    MemberTypes.Method, AllBindingFlags, loc);
773                         
774                         if (mg != null) {
775                                 method = StaticCallExpr.MakeSimpleCall (
776                                         ec, (MethodGroupExpr) mg, expr, loc);
777
778                                 type = method.Type;
779                                 return this;
780                         }
781
782                         //
783                         // The operand of the prefix/postfix increment decrement operators
784                         // should be an expression that is classified as a variable,
785                         // a property access or an indexer access
786                         //
787                         type = expr_type;
788                         if (expr.eclass == ExprClass.Variable){
789                                 if (IsIncrementableNumber (expr_type) ||
790                                     expr_type == TypeManager.decimal_type){
791                                         return this;
792                                 }
793                         } else if (expr.eclass == ExprClass.IndexerAccess){
794                                 IndexerAccess ia = (IndexerAccess) expr;
795                                 
796                                 temp_storage = new LocalTemporary (ec, expr.Type);
797                                 
798                                 expr = ia.ResolveLValue (ec, temp_storage);
799                                 if (expr == null)
800                                         return null;
801
802                                 return this;
803                         } else if (expr.eclass == ExprClass.PropertyAccess){
804                                 PropertyExpr pe = (PropertyExpr) expr;
805
806                                 if (pe.VerifyAssignable ())
807                                         return this;
808
809                                 return null;
810                         } else {
811                                 expr.Error_UnexpectedKind ("variable, indexer or property access");
812                                 return null;
813                         }
814
815                         Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
816                                TypeManager.CSharpName (expr_type) + "'");
817                         return null;
818                 }
819
820                 public override Expression DoResolve (EmitContext ec)
821                 {
822                         expr = expr.Resolve (ec);
823                         
824                         if (expr == null)
825                                 return null;
826
827                         eclass = ExprClass.Value;
828                         return ResolveOperator (ec);
829                 }
830
831                 static int PtrTypeSize (Type t)
832                 {
833                         return GetTypeSize (t.GetElementType ());
834                 }
835
836                 //
837                 // Loads the proper "1" into the stack based on the type, then it emits the
838                 // opcode for the operation requested
839                 //
840                 void LoadOneAndEmitOp (EmitContext ec, Type t)
841                 {
842                         //
843                         // Measure if getting the typecode and using that is more/less efficient
844                         // that comparing types.  t.GetTypeCode() is an internal call.
845                         //
846                         ILGenerator ig = ec.ig;
847                                                      
848                         if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
849                                 LongConstant.EmitLong (ig, 1);
850                         else if (t == TypeManager.double_type)
851                                 ig.Emit (OpCodes.Ldc_R8, 1.0);
852                         else if (t == TypeManager.float_type)
853                                 ig.Emit (OpCodes.Ldc_R4, 1.0F);
854                         else if (t.IsPointer){
855                                 int n = PtrTypeSize (t);
856                                 
857                                 if (n == 0)
858                                         ig.Emit (OpCodes.Sizeof, t);
859                                 else
860                                         IntConstant.EmitInt (ig, n);
861                         } else 
862                                 ig.Emit (OpCodes.Ldc_I4_1);
863
864                         //
865                         // Now emit the operation
866                         //
867                         if (ec.CheckState){
868                                 if (t == TypeManager.int32_type ||
869                                     t == TypeManager.int64_type){
870                                         if ((mode & Mode.IsDecrement) != 0)
871                                                 ig.Emit (OpCodes.Sub_Ovf);
872                                         else
873                                                 ig.Emit (OpCodes.Add_Ovf);
874                                 } else if (t == TypeManager.uint32_type ||
875                                            t == TypeManager.uint64_type){
876                                         if ((mode & Mode.IsDecrement) != 0)
877                                                 ig.Emit (OpCodes.Sub_Ovf_Un);
878                                         else
879                                                 ig.Emit (OpCodes.Add_Ovf_Un);
880                                 } else {
881                                         if ((mode & Mode.IsDecrement) != 0)
882                                                 ig.Emit (OpCodes.Sub_Ovf);
883                                         else
884                                                 ig.Emit (OpCodes.Add_Ovf);
885                                 }
886                         } else {
887                                 if ((mode & Mode.IsDecrement) != 0)
888                                         ig.Emit (OpCodes.Sub);
889                                 else
890                                         ig.Emit (OpCodes.Add);
891                         }
892
893                         if (t == TypeManager.sbyte_type){
894                                 if (ec.CheckState)
895                                         ig.Emit (OpCodes.Conv_Ovf_I1);
896                                 else
897                                         ig.Emit (OpCodes.Conv_I1);
898                         } else if (t == TypeManager.byte_type){
899                                 if (ec.CheckState)
900                                         ig.Emit (OpCodes.Conv_Ovf_U1);
901                                 else
902                                         ig.Emit (OpCodes.Conv_U1);
903                         } else if (t == TypeManager.short_type){
904                                 if (ec.CheckState)
905                                         ig.Emit (OpCodes.Conv_Ovf_I2);
906                                 else
907                                         ig.Emit (OpCodes.Conv_I2);
908                         } else if (t == TypeManager.ushort_type || t == TypeManager.char_type){
909                                 if (ec.CheckState)
910                                         ig.Emit (OpCodes.Conv_Ovf_U2);
911                                 else
912                                         ig.Emit (OpCodes.Conv_U2);
913                         }
914                         
915                 }
916
917                 void EmitCode (EmitContext ec, bool is_expr)
918                 {
919                         ILGenerator ig = ec.ig;
920                         IAssignMethod ia = (IAssignMethod) expr;
921                         Type expr_type = expr.Type;
922
923                         ia.CacheTemporaries (ec);
924
925                         if (temp_storage == null)
926                                 temp_storage = new LocalTemporary (ec, expr_type);
927                         
928                         switch (mode){
929                         case Mode.PreIncrement:
930                         case Mode.PreDecrement:
931                                 if (method == null){
932                                         expr.Emit (ec);
933                                         
934                                         LoadOneAndEmitOp (ec, expr_type);
935                                 } else 
936                                         method.Emit (ec);
937                                 
938                                 temp_storage.Store (ec);
939                                 ia.EmitAssign (ec, temp_storage);
940                                 if (is_expr)
941                                         temp_storage.Emit (ec);
942                                 break;
943                                 
944                         case Mode.PostIncrement:
945                         case Mode.PostDecrement:
946                                 if (is_expr)
947                                         expr.Emit (ec);
948                                 
949                                 if (method == null){
950                                         if (!is_expr)
951                                                 expr.Emit (ec);
952                                         else
953                                                 ig.Emit (OpCodes.Dup);
954                                         
955                                         LoadOneAndEmitOp (ec, expr_type);
956                                 } else {
957                                         method.Emit (ec);
958                                 }
959                                 
960                                 temp_storage.Store (ec);
961                                 ia.EmitAssign (ec, temp_storage);
962                                 break;
963                         }
964                 }
965
966                 public override void Emit (EmitContext ec)
967                 {
968                         EmitCode (ec, true);
969                         
970                 }
971                 
972                 public override void EmitStatement (EmitContext ec)
973                 {
974                         EmitCode (ec, false);
975                 }
976
977         }
978
979         /// <summary>
980         ///   Base class for the `Is' and `As' classes. 
981         /// </summary>
982         ///
983         /// <remarks>
984         ///   FIXME: Split this in two, and we get to save the `Operator' Oper
985         ///   size. 
986         /// </remarks>
987         public abstract class Probe : Expression {
988                 public readonly Expression ProbeType;
989                 protected Expression expr;
990                 protected Type probe_type;
991                 
992                 public Probe (Expression expr, Expression probe_type, Location l)
993                 {
994                         ProbeType = probe_type;
995                         loc = l;
996                         this.expr = expr;
997                 }
998
999                 public Expression Expr {
1000                         get {
1001                                 return expr;
1002                         }
1003                 }
1004
1005                 public override Expression DoResolve (EmitContext ec)
1006                 {
1007                         probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
1008
1009                         if (probe_type == null)
1010                                 return null;
1011
1012                         expr = expr.Resolve (ec);
1013                         
1014                         return this;
1015                 }
1016         }
1017
1018         /// <summary>
1019         ///   Implementation of the `is' operator.
1020         /// </summary>
1021         public class Is : Probe {
1022                 public Is (Expression expr, Expression probe_type, Location l)
1023                         : base (expr, probe_type, l)
1024                 {
1025                 }
1026
1027                 enum Action {
1028                         AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1029                 }
1030
1031                 Action action;
1032                 
1033                 public override void Emit (EmitContext ec)
1034                 {
1035                         ILGenerator ig = ec.ig;
1036
1037                         expr.Emit (ec);
1038
1039                         switch (action){
1040                         case Action.AlwaysFalse:
1041                                 ig.Emit (OpCodes.Pop);
1042                                 IntConstant.EmitInt (ig, 0);
1043                                 return;
1044                         case Action.AlwaysTrue:
1045                                 ig.Emit (OpCodes.Pop);
1046                                 IntConstant.EmitInt (ig, 1);
1047                                 return;
1048                         case Action.LeaveOnStack:
1049                                 // the `e != null' rule.
1050                                 ig.Emit (OpCodes.Ldnull);
1051                                 ig.Emit (OpCodes.Ceq);
1052                                 ig.Emit (OpCodes.Ldc_I4_0);
1053                                 ig.Emit (OpCodes.Ceq);
1054                                 return;
1055                         case Action.Probe:
1056                                 ig.Emit (OpCodes.Isinst, probe_type);
1057                                 ig.Emit (OpCodes.Ldnull);
1058                                 ig.Emit (OpCodes.Cgt_Un);
1059                                 return;
1060                         }
1061                         throw new Exception ("never reached");
1062                 }
1063
1064                 public override Expression DoResolve (EmitContext ec)
1065                 {
1066                         Expression e = base.DoResolve (ec);
1067
1068                         if ((e == null) || (expr == null))
1069                                 return null;
1070
1071                         Type etype = expr.Type;
1072                         bool warning_always_matches = false;
1073                         bool warning_never_matches = false;
1074
1075                         type = TypeManager.bool_type;
1076                         eclass = ExprClass.Value;
1077
1078                         //
1079                         // First case, if at compile time, there is an implicit conversion
1080                         // then e != null (objects) or true (value types)
1081                         //
1082                         e = ConvertImplicitStandard (ec, expr, probe_type, loc);
1083                         if (e != null){
1084                                 expr = e;
1085                                 if (etype.IsValueType)
1086                                         action = Action.AlwaysTrue;
1087                                 else
1088                                         action = Action.LeaveOnStack;
1089
1090                                 warning_always_matches = true;
1091                         } else if (ExplicitReferenceConversionExists (etype, probe_type)){
1092                                 //
1093                                 // Second case: explicit reference convresion
1094                                 //
1095                                 if (expr is NullLiteral)
1096                                         action = Action.AlwaysFalse;
1097                                 else
1098                                         action = Action.Probe;
1099                         } else {
1100                                 action = Action.AlwaysFalse;
1101                                 warning_never_matches = true;
1102                         }
1103                         
1104                         if (RootContext.WarningLevel >= 1){
1105                                 if (warning_always_matches)
1106                                         Warning (183, "The expression is always of type `" +
1107                                                  TypeManager.CSharpName (probe_type) + "'");
1108                                 else if (warning_never_matches){
1109                                         if (!(probe_type.IsInterface || expr.Type.IsInterface))
1110                                                 Warning (184,
1111                                                          "The expression is never of type `" +
1112                                                          TypeManager.CSharpName (probe_type) + "'");
1113                                 }
1114                         }
1115
1116                         return this;
1117                 }                               
1118         }
1119
1120         /// <summary>
1121         ///   Implementation of the `as' operator.
1122         /// </summary>
1123         public class As : Probe {
1124                 public As (Expression expr, Expression probe_type, Location l)
1125                         : base (expr, probe_type, l)
1126                 {
1127                 }
1128
1129                 bool do_isinst = false;
1130                 
1131                 public override void Emit (EmitContext ec)
1132                 {
1133                         ILGenerator ig = ec.ig;
1134
1135                         expr.Emit (ec);
1136
1137                         if (do_isinst)
1138                                 ig.Emit (OpCodes.Isinst, probe_type);
1139                 }
1140
1141                 static void Error_CannotConvertType (Type source, Type target, Location loc)
1142                 {
1143                         Report.Error (
1144                                 39, loc, "as operator can not convert from `" +
1145                                 TypeManager.CSharpName (source) + "' to `" +
1146                                 TypeManager.CSharpName (target) + "'");
1147                 }
1148                 
1149                 public override Expression DoResolve (EmitContext ec)
1150                 {
1151                         Expression e = base.DoResolve (ec);
1152
1153                         if (e == null)
1154                                 return null;
1155
1156                         type = probe_type;
1157                         eclass = ExprClass.Value;
1158                         Type etype = expr.Type;
1159
1160                         if (TypeManager.IsValueType (probe_type)){
1161                                 Report.Error (77, loc, "The as operator should be used with a reference type only (" +
1162                                               TypeManager.CSharpName (probe_type) + " is a value type");
1163                                 return null;
1164                         
1165                         }
1166                         
1167                         e = ConvertImplicit (ec, expr, probe_type, loc);
1168                         if (e != null){
1169                                 expr = e;
1170                                 do_isinst = false;
1171                                 return this;
1172                         }
1173
1174                         if (ExplicitReferenceConversionExists (etype, probe_type)){
1175                                 do_isinst = true;
1176                                 return this;
1177                         }
1178
1179                         Error_CannotConvertType (etype, probe_type, loc);
1180                         return null;
1181                 }                               
1182         }
1183         
1184         /// <summary>
1185         ///   This represents a typecast in the source language.
1186         ///
1187         ///   FIXME: Cast expressions have an unusual set of parsing
1188         ///   rules, we need to figure those out.
1189         /// </summary>
1190         public class Cast : Expression {
1191                 Expression target_type;
1192                 Expression expr;
1193                         
1194                 public Cast (Expression cast_type, Expression expr, Location loc)
1195                 {
1196                         this.target_type = cast_type;
1197                         this.expr = expr;
1198                         this.loc = loc;
1199                 }
1200
1201                 public Expression TargetType {
1202                         get {
1203                                 return target_type;
1204                         }
1205                 }
1206
1207                 public Expression Expr {
1208                         get {
1209                                 return expr;
1210                         }
1211                         set {
1212                                 expr = value;
1213                         }
1214                 }
1215
1216                 bool CheckRange (EmitContext ec, long value, Type type, long min, long max)
1217                 {
1218                         if (!ec.ConstantCheckState)
1219                                 return true;
1220
1221                         if ((value < min) || (value > max)) {
1222                                 Error (221, "Constant value `" + value + "' cannot be converted " +
1223                                        "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1224                                        "syntax to override)");
1225                                 return false;
1226                         }
1227
1228                         return true;
1229                 }
1230
1231                 bool CheckRange (EmitContext ec, ulong value, Type type, ulong max)
1232                 {
1233                         if (!ec.ConstantCheckState)
1234                                 return true;
1235
1236                         if (value > max) {
1237                                 Error (221, "Constant value `" + value + "' cannot be converted " +
1238                                        "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1239                                        "syntax to override)");
1240                                 return false;
1241                         }
1242
1243                         return true;
1244                 }
1245
1246                 bool CheckUnsigned (EmitContext ec, long value, Type type)
1247                 {
1248                         if (!ec.ConstantCheckState)
1249                                 return true;
1250
1251                         if (value < 0) {
1252                                 Error (221, "Constant value `" + value + "' cannot be converted " +
1253                                        "to a `" + TypeManager.CSharpName (type) + "' (use `unchecked' " +
1254                                        "syntax to override)");
1255                                 return false;
1256                         }
1257
1258                         return true;
1259                 }
1260
1261                 /// <summary>
1262                 ///   Attempts to do a compile-time folding of a constant cast.
1263                 /// </summary>
1264                 Expression TryReduce (EmitContext ec, Type target_type)
1265                 {
1266                         Expression real_expr = expr;
1267                         if (real_expr is EnumConstant)
1268                                 real_expr = ((EnumConstant) real_expr).Child;
1269                                 
1270                         if (real_expr is ByteConstant){
1271                                 byte v = ((ByteConstant) real_expr).Value;
1272         
1273                                 if (target_type == TypeManager.sbyte_type) {
1274                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1275                                                 return null;
1276                                         return new SByteConstant ((sbyte) v);
1277                                 }
1278                                 if (target_type == TypeManager.short_type)
1279                                         return new ShortConstant ((short) v);
1280                                 if (target_type == TypeManager.ushort_type)
1281                                         return new UShortConstant ((ushort) v);
1282                                 if (target_type == TypeManager.int32_type)
1283                                         return new IntConstant ((int) v);
1284                                 if (target_type == TypeManager.uint32_type)
1285                                         return new UIntConstant ((uint) v);
1286                                 if (target_type == TypeManager.int64_type)
1287                                         return new LongConstant ((long) v);
1288                                 if (target_type == TypeManager.uint64_type)
1289                                         return new ULongConstant ((ulong) v);
1290                                 if (target_type == TypeManager.float_type)
1291                                         return new FloatConstant ((float) v);
1292                                 if (target_type == TypeManager.double_type)
1293                                         return new DoubleConstant ((double) v);
1294                                 if (target_type == TypeManager.char_type)
1295                                         return new CharConstant ((char) v);
1296                                 if (target_type == TypeManager.decimal_type)
1297                                         return new DecimalConstant ((decimal) v);
1298                         }
1299                         if (real_expr is SByteConstant){
1300                                 sbyte v = ((SByteConstant) real_expr).Value;
1301         
1302                                 if (target_type == TypeManager.byte_type) {
1303                                         if (!CheckUnsigned (ec, v, target_type))
1304                                                 return null;
1305                                         return new ByteConstant ((byte) v);
1306                                 }
1307                                 if (target_type == TypeManager.short_type)
1308                                         return new ShortConstant ((short) v);
1309                                 if (target_type == TypeManager.ushort_type) {
1310                                         if (!CheckUnsigned (ec, v, target_type))
1311                                                 return null;
1312                                         return new UShortConstant ((ushort) v);
1313                                 } if (target_type == TypeManager.int32_type)
1314                                         return new IntConstant ((int) v);
1315                                 if (target_type == TypeManager.uint32_type) {
1316                                         if (!CheckUnsigned (ec, v, target_type))
1317                                                 return null;
1318                                         return new UIntConstant ((uint) v);
1319                                 } if (target_type == TypeManager.int64_type)
1320                                         return new LongConstant ((long) v);
1321                                 if (target_type == TypeManager.uint64_type) {
1322                                         if (!CheckUnsigned (ec, v, target_type))
1323                                                 return null;
1324                                         return new ULongConstant ((ulong) v);
1325                                 }
1326                                 if (target_type == TypeManager.float_type)
1327                                         return new FloatConstant ((float) v);
1328                                 if (target_type == TypeManager.double_type)
1329                                         return new DoubleConstant ((double) v);
1330                                 if (target_type == TypeManager.char_type) {
1331                                         if (!CheckUnsigned (ec, v, target_type))
1332                                                 return null;
1333                                         return new CharConstant ((char) v);
1334                                 }
1335                                 if (target_type == TypeManager.decimal_type)
1336                                         return new DecimalConstant ((decimal) v);
1337                         }
1338                         if (real_expr is ShortConstant){
1339                                 short v = ((ShortConstant) real_expr).Value;
1340         
1341                                 if (target_type == TypeManager.byte_type) {
1342                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1343                                                 return null;
1344                                         return new ByteConstant ((byte) v);
1345                                 }
1346                                 if (target_type == TypeManager.sbyte_type) {
1347                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1348                                                 return null;
1349                                         return new SByteConstant ((sbyte) v);
1350                                 }
1351                                 if (target_type == TypeManager.ushort_type) {
1352                                         if (!CheckUnsigned (ec, v, target_type))
1353                                                 return null;
1354                                         return new UShortConstant ((ushort) v);
1355                                 }
1356                                 if (target_type == TypeManager.int32_type)
1357                                         return new IntConstant ((int) v);
1358                                 if (target_type == TypeManager.uint32_type) {
1359                                         if (!CheckUnsigned (ec, v, target_type))
1360                                                 return null;
1361                                         return new UIntConstant ((uint) v);
1362                                 }
1363                                 if (target_type == TypeManager.int64_type)
1364                                         return new LongConstant ((long) v);
1365                                 if (target_type == TypeManager.uint64_type) {
1366                                         if (!CheckUnsigned (ec, v, target_type))
1367                                                 return null;
1368                                         return new ULongConstant ((ulong) v);
1369                                 }
1370                                 if (target_type == TypeManager.float_type)
1371                                         return new FloatConstant ((float) v);
1372                                 if (target_type == TypeManager.double_type)
1373                                         return new DoubleConstant ((double) v);
1374                                 if (target_type == TypeManager.char_type) {
1375                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1376                                                 return null;
1377                                         return new CharConstant ((char) v);
1378                                 }
1379                                 if (target_type == TypeManager.decimal_type)
1380                                         return new DecimalConstant ((decimal) v);
1381                         }
1382                         if (real_expr is UShortConstant){
1383                                 ushort v = ((UShortConstant) real_expr).Value;
1384         
1385                                 if (target_type == TypeManager.byte_type) {
1386                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1387                                                 return null;
1388                                         return new ByteConstant ((byte) v);
1389                                 }
1390                                 if (target_type == TypeManager.sbyte_type) {
1391                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1392                                                 return null;
1393                                         return new SByteConstant ((sbyte) v);
1394                                 }
1395                                 if (target_type == TypeManager.short_type) {
1396                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1397                                                 return null;
1398                                         return new ShortConstant ((short) v);
1399                                 }
1400                                 if (target_type == TypeManager.int32_type)
1401                                         return new IntConstant ((int) v);
1402                                 if (target_type == TypeManager.uint32_type)
1403                                         return new UIntConstant ((uint) v);
1404                                 if (target_type == TypeManager.int64_type)
1405                                         return new LongConstant ((long) v);
1406                                 if (target_type == TypeManager.uint64_type)
1407                                         return new ULongConstant ((ulong) v);
1408                                 if (target_type == TypeManager.float_type)
1409                                         return new FloatConstant ((float) v);
1410                                 if (target_type == TypeManager.double_type)
1411                                         return new DoubleConstant ((double) v);
1412                                 if (target_type == TypeManager.char_type) {
1413                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1414                                                 return null;
1415                                         return new CharConstant ((char) v);
1416                                 }
1417                                 if (target_type == TypeManager.decimal_type)
1418                                         return new DecimalConstant ((decimal) v);
1419                         }
1420                         if (real_expr is IntConstant){
1421                                 int v = ((IntConstant) real_expr).Value;
1422         
1423                                 if (target_type == TypeManager.byte_type) {
1424                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1425                                                 return null;
1426                                         return new ByteConstant ((byte) v);
1427                                 }
1428                                 if (target_type == TypeManager.sbyte_type) {
1429                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1430                                                 return null;
1431                                         return new SByteConstant ((sbyte) v);
1432                                 }
1433                                 if (target_type == TypeManager.short_type) {
1434                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1435                                                 return null;
1436                                         return new ShortConstant ((short) v);
1437                                 }
1438                                 if (target_type == TypeManager.ushort_type) {
1439                                         if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1440                                                 return null;
1441                                         return new UShortConstant ((ushort) v);
1442                                 }
1443                                 if (target_type == TypeManager.uint32_type) {
1444                                         if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1445                                                 return null;
1446                                         return new UIntConstant ((uint) v);
1447                                 }
1448                                 if (target_type == TypeManager.int64_type)
1449                                         return new LongConstant ((long) v);
1450                                 if (target_type == TypeManager.uint64_type) {
1451                                         if (!CheckUnsigned (ec, v, target_type))
1452                                                 return null;
1453                                         return new ULongConstant ((ulong) v);
1454                                 }
1455                                 if (target_type == TypeManager.float_type)
1456                                         return new FloatConstant ((float) v);
1457                                 if (target_type == TypeManager.double_type)
1458                                         return new DoubleConstant ((double) v);
1459                                 if (target_type == TypeManager.char_type) {
1460                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1461                                                 return null;
1462                                         return new CharConstant ((char) v);
1463                                 }
1464                                 if (target_type == TypeManager.decimal_type)
1465                                         return new DecimalConstant ((decimal) v);
1466                         }
1467                         if (real_expr is UIntConstant){
1468                                 uint v = ((UIntConstant) real_expr).Value;
1469         
1470                                 if (target_type == TypeManager.byte_type) {
1471                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1472                                                 return null;
1473                                         return new ByteConstant ((byte) v);
1474                                 }
1475                                 if (target_type == TypeManager.sbyte_type) {
1476                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1477                                                 return null;
1478                                         return new SByteConstant ((sbyte) v);
1479                                 }
1480                                 if (target_type == TypeManager.short_type) {
1481                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1482                                                 return null;
1483                                         return new ShortConstant ((short) v);
1484                                 }
1485                                 if (target_type == TypeManager.ushort_type) {
1486                                         if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1487                                                 return null;
1488                                         return new UShortConstant ((ushort) v);
1489                                 }
1490                                 if (target_type == TypeManager.int32_type) {
1491                                         if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1492                                                 return null;
1493                                         return new IntConstant ((int) v);
1494                                 }
1495                                 if (target_type == TypeManager.int64_type)
1496                                         return new LongConstant ((long) v);
1497                                 if (target_type == TypeManager.uint64_type)
1498                                         return new ULongConstant ((ulong) v);
1499                                 if (target_type == TypeManager.float_type)
1500                                         return new FloatConstant ((float) v);
1501                                 if (target_type == TypeManager.double_type)
1502                                         return new DoubleConstant ((double) v);
1503                                 if (target_type == TypeManager.char_type) {
1504                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1505                                                 return null;
1506                                         return new CharConstant ((char) v);
1507                                 }
1508                                 if (target_type == TypeManager.decimal_type)
1509                                         return new DecimalConstant ((decimal) v);
1510                         }
1511                         if (real_expr is LongConstant){
1512                                 long v = ((LongConstant) real_expr).Value;
1513         
1514                                 if (target_type == TypeManager.byte_type) {
1515                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1516                                                 return null;
1517                                         return new ByteConstant ((byte) v);
1518                                 }
1519                                 if (target_type == TypeManager.sbyte_type) {
1520                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1521                                                 return null;
1522                                         return new SByteConstant ((sbyte) v);
1523                                 }
1524                                 if (target_type == TypeManager.short_type) {
1525                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1526                                                 return null;
1527                                         return new ShortConstant ((short) v);
1528                                 }
1529                                 if (target_type == TypeManager.ushort_type) {
1530                                         if (!CheckRange (ec, v, target_type, UInt16.MinValue, UInt16.MaxValue))
1531                                                 return null;
1532                                         return new UShortConstant ((ushort) v);
1533                                 }
1534                                 if (target_type == TypeManager.int32_type) {
1535                                         if (!CheckRange (ec, v, target_type, Int32.MinValue, Int32.MaxValue))
1536                                                 return null;
1537                                         return new IntConstant ((int) v);
1538                                 }
1539                                 if (target_type == TypeManager.uint32_type) {
1540                                         if (!CheckRange (ec, v, target_type, UInt32.MinValue, UInt32.MaxValue))
1541                                                 return null;
1542                                         return new UIntConstant ((uint) v);
1543                                 }
1544                                 if (target_type == TypeManager.uint64_type) {
1545                                         if (!CheckUnsigned (ec, v, target_type))
1546                                                 return null;
1547                                         return new ULongConstant ((ulong) v);
1548                                 }
1549                                 if (target_type == TypeManager.float_type)
1550                                         return new FloatConstant ((float) v);
1551                                 if (target_type == TypeManager.double_type)
1552                                         return new DoubleConstant ((double) v);
1553                                 if (target_type == TypeManager.char_type) {
1554                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1555                                                 return null;
1556                                         return new CharConstant ((char) v);
1557                                 }
1558                                 if (target_type == TypeManager.decimal_type)
1559                                         return new DecimalConstant ((decimal) v);
1560                         }
1561                         if (real_expr is ULongConstant){
1562                                 ulong v = ((ULongConstant) real_expr).Value;
1563         
1564                                 if (target_type == TypeManager.byte_type) {
1565                                         if (!CheckRange (ec, v, target_type, Byte.MaxValue))
1566                                                 return null;
1567                                         return new ByteConstant ((byte) v);
1568                                 }
1569                                 if (target_type == TypeManager.sbyte_type) {
1570                                         if (!CheckRange (ec, v, target_type, (ulong) SByte.MaxValue))
1571                                                 return null;
1572                                         return new SByteConstant ((sbyte) v);
1573                                 }
1574                                 if (target_type == TypeManager.short_type) {
1575                                         if (!CheckRange (ec, v, target_type, (ulong) Int16.MaxValue))
1576                                                 return null;
1577                                         return new ShortConstant ((short) v);
1578                                 }
1579                                 if (target_type == TypeManager.ushort_type) {
1580                                         if (!CheckRange (ec, v, target_type, UInt16.MaxValue))
1581                                                 return null;
1582                                         return new UShortConstant ((ushort) v);
1583                                 }
1584                                 if (target_type == TypeManager.int32_type) {
1585                                         if (!CheckRange (ec, v, target_type, Int32.MaxValue))
1586                                                 return null;
1587                                         return new IntConstant ((int) v);
1588                                 }
1589                                 if (target_type == TypeManager.uint32_type) {
1590                                         if (!CheckRange (ec, v, target_type, UInt32.MaxValue))
1591                                                 return null;
1592                                         return new UIntConstant ((uint) v);
1593                                 }
1594                                 if (target_type == TypeManager.int64_type) {
1595                                         if (!CheckRange (ec, v, target_type, (ulong) Int64.MaxValue))
1596                                                 return null;
1597                                         return new LongConstant ((long) v);
1598                                 }
1599                                 if (target_type == TypeManager.float_type)
1600                                         return new FloatConstant ((float) v);
1601                                 if (target_type == TypeManager.double_type)
1602                                         return new DoubleConstant ((double) v);
1603                                 if (target_type == TypeManager.char_type) {
1604                                         if (!CheckRange (ec, v, target_type, Char.MaxValue))
1605                                                 return null;
1606                                         return new CharConstant ((char) v);
1607                                 }
1608                                 if (target_type == TypeManager.decimal_type)
1609                                         return new DecimalConstant ((decimal) v);
1610                         }
1611                         if (real_expr is FloatConstant){
1612                                 float v = ((FloatConstant) real_expr).Value;
1613         
1614                                 if (target_type == TypeManager.byte_type)
1615                                         return new ByteConstant ((byte) v);
1616                                 if (target_type == TypeManager.sbyte_type)
1617                                         return new SByteConstant ((sbyte) v);
1618                                 if (target_type == TypeManager.short_type)
1619                                         return new ShortConstant ((short) v);
1620                                 if (target_type == TypeManager.ushort_type)
1621                                         return new UShortConstant ((ushort) v);
1622                                 if (target_type == TypeManager.int32_type)
1623                                         return new IntConstant ((int) v);
1624                                 if (target_type == TypeManager.uint32_type)
1625                                         return new UIntConstant ((uint) v);
1626                                 if (target_type == TypeManager.int64_type)
1627                                         return new LongConstant ((long) v);
1628                                 if (target_type == TypeManager.uint64_type)
1629                                         return new ULongConstant ((ulong) v);
1630                                 if (target_type == TypeManager.double_type)
1631                                         return new DoubleConstant ((double) v);
1632                                 if (target_type == TypeManager.char_type)
1633                                         return new CharConstant ((char) v);
1634                                 if (target_type == TypeManager.decimal_type)
1635                                         return new DecimalConstant ((decimal) v);
1636                         }
1637                         if (real_expr is DoubleConstant){
1638                                 double v = ((DoubleConstant) real_expr).Value;
1639         
1640                                 if (target_type == TypeManager.byte_type)
1641                                         return new ByteConstant ((byte) v);
1642                                 if (target_type == TypeManager.sbyte_type)
1643                                         return new SByteConstant ((sbyte) v);
1644                                 if (target_type == TypeManager.short_type)
1645                                         return new ShortConstant ((short) v);
1646                                 if (target_type == TypeManager.ushort_type)
1647                                         return new UShortConstant ((ushort) v);
1648                                 if (target_type == TypeManager.int32_type)
1649                                         return new IntConstant ((int) v);
1650                                 if (target_type == TypeManager.uint32_type)
1651                                         return new UIntConstant ((uint) v);
1652                                 if (target_type == TypeManager.int64_type)
1653                                         return new LongConstant ((long) v);
1654                                 if (target_type == TypeManager.uint64_type)
1655                                         return new ULongConstant ((ulong) v);
1656                                 if (target_type == TypeManager.float_type)
1657                                         return new FloatConstant ((float) v);
1658                                 if (target_type == TypeManager.char_type)
1659                                         return new CharConstant ((char) v);
1660                                 if (target_type == TypeManager.decimal_type)
1661                                         return new DecimalConstant ((decimal) v);
1662                         }
1663
1664                         if (real_expr is CharConstant){
1665                                 char v = ((CharConstant) real_expr).Value;
1666                                 
1667                                 if (target_type == TypeManager.byte_type) {
1668                                         if (!CheckRange (ec, v, target_type, Byte.MinValue, Byte.MaxValue))
1669                                                 return null;
1670                                         return new ByteConstant ((byte) v);
1671                                 }
1672                                 if (target_type == TypeManager.sbyte_type) {
1673                                         if (!CheckRange (ec, v, target_type, SByte.MinValue, SByte.MaxValue))
1674                                                 return null;
1675                                         return new SByteConstant ((sbyte) v);
1676                                 }
1677                                 if (target_type == TypeManager.short_type) {
1678                                         if (!CheckRange (ec, v, target_type, Int16.MinValue, Int16.MaxValue))
1679                                                 return null;
1680                                         return new ShortConstant ((short) v);
1681                                 }
1682                                 if (target_type == TypeManager.int32_type)
1683                                         return new IntConstant ((int) v);
1684                                 if (target_type == TypeManager.uint32_type)
1685                                         return new UIntConstant ((uint) v);
1686                                 if (target_type == TypeManager.int64_type)
1687                                         return new LongConstant ((long) v);
1688                                 if (target_type == TypeManager.uint64_type)
1689                                         return new ULongConstant ((ulong) v);
1690                                 if (target_type == TypeManager.float_type)
1691                                         return new FloatConstant ((float) v);
1692                                 if (target_type == TypeManager.double_type)
1693                                         return new DoubleConstant ((double) v);
1694                                 if (target_type == TypeManager.char_type) {
1695                                         if (!CheckRange (ec, v, target_type, Char.MinValue, Char.MaxValue))
1696                                                 return null;
1697                                         return new CharConstant ((char) v);
1698                                 }
1699                                 if (target_type == TypeManager.decimal_type)
1700                                         return new DecimalConstant ((decimal) v);
1701                         }
1702
1703                         return null;
1704                 }
1705                 
1706                 public override Expression DoResolve (EmitContext ec)
1707                 {
1708                         expr = expr.Resolve (ec);
1709                         if (expr == null)
1710                                 return null;
1711
1712                         int errors = Report.Errors;
1713
1714                         type = ec.DeclSpace.ResolveType (target_type, false, Location);
1715                         
1716                         if (type == null)
1717                                 return null;
1718
1719                         eclass = ExprClass.Value;
1720
1721                         if (expr is Constant){
1722                                 Expression e = TryReduce (ec, type);
1723
1724                                 if (e != null)
1725                                         return e;
1726                         }
1727                         
1728                         expr = ConvertExplicit (ec, expr, type, loc);
1729                         return expr;
1730                 }
1731
1732                 public override void Emit (EmitContext ec)
1733                 {
1734                         //
1735                         // This one will never happen
1736                         //
1737                         throw new Exception ("Should not happen");
1738                 }
1739         }
1740
1741         /// <summary>
1742         ///   Binary operators
1743         /// </summary>
1744         public class Binary : Expression {
1745                 public enum Operator : byte {
1746                         Multiply, Division, Modulus,
1747                         Addition, Subtraction,
1748                         LeftShift, RightShift,
1749                         LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, 
1750                         Equality, Inequality,
1751                         BitwiseAnd,
1752                         ExclusiveOr,
1753                         BitwiseOr,
1754                         LogicalAnd,
1755                         LogicalOr,
1756                         TOP
1757                 }
1758
1759                 Operator oper;
1760                 Expression left, right;
1761
1762                 //
1763                 // After resolution, method might contain the operator overload
1764                 // method.
1765                 //
1766                 protected MethodBase method;
1767                 ArrayList  Arguments;
1768
1769                 bool DelegateOperation;
1770
1771                 // This must be kept in sync with Operator!!!
1772                 public static readonly string [] oper_names;
1773                 
1774                 static Binary ()
1775                 {
1776                         oper_names = new string [(int) Operator.TOP];
1777
1778                         oper_names [(int) Operator.Multiply] = "op_Multiply";
1779                         oper_names [(int) Operator.Division] = "op_Division";
1780                         oper_names [(int) Operator.Modulus] = "op_Modulus";
1781                         oper_names [(int) Operator.Addition] = "op_Addition";
1782                         oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1783                         oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1784                         oper_names [(int) Operator.RightShift] = "op_RightShift";
1785                         oper_names [(int) Operator.LessThan] = "op_LessThan";
1786                         oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1787                         oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1788                         oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1789                         oper_names [(int) Operator.Equality] = "op_Equality";
1790                         oper_names [(int) Operator.Inequality] = "op_Inequality";
1791                         oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1792                         oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1793                         oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1794                         oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1795                         oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1796                 }
1797
1798                 public Binary (Operator oper, Expression left, Expression right, Location loc)
1799                 {
1800                         this.oper = oper;
1801                         this.left = left;
1802                         this.right = right;
1803                         this.loc = loc;
1804                 }
1805
1806                 public Operator Oper {
1807                         get {
1808                                 return oper;
1809                         }
1810                         set {
1811                                 oper = value;
1812                         }
1813                 }
1814                 
1815                 public Expression Left {
1816                         get {
1817                                 return left;
1818                         }
1819                         set {
1820                                 left = value;
1821                         }
1822                 }
1823
1824                 public Expression Right {
1825                         get {
1826                                 return right;
1827                         }
1828                         set {
1829                                 right = value;
1830                         }
1831                 }
1832
1833
1834                 /// <summary>
1835                 ///   Returns a stringified representation of the Operator
1836                 /// </summary>
1837                 static string OperName (Operator oper)
1838                 {
1839                         switch (oper){
1840                         case Operator.Multiply:
1841                                 return "*";
1842                         case Operator.Division:
1843                                 return "/";
1844                         case Operator.Modulus:
1845                                 return "%";
1846                         case Operator.Addition:
1847                                 return "+";
1848                         case Operator.Subtraction:
1849                                 return "-";
1850                         case Operator.LeftShift:
1851                                 return "<<";
1852                         case Operator.RightShift:
1853                                 return ">>";
1854                         case Operator.LessThan:
1855                                 return "<";
1856                         case Operator.GreaterThan:
1857                                 return ">";
1858                         case Operator.LessThanOrEqual:
1859                                 return "<=";
1860                         case Operator.GreaterThanOrEqual:
1861                                 return ">=";
1862                         case Operator.Equality:
1863                                 return "==";
1864                         case Operator.Inequality:
1865                                 return "!=";
1866                         case Operator.BitwiseAnd:
1867                                 return "&";
1868                         case Operator.BitwiseOr:
1869                                 return "|";
1870                         case Operator.ExclusiveOr:
1871                                 return "^";
1872                         case Operator.LogicalOr:
1873                                 return "||";
1874                         case Operator.LogicalAnd:
1875                                 return "&&";
1876                         }
1877
1878                         return oper.ToString ();
1879                 }
1880
1881                 public override string ToString ()
1882                 {
1883                         return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1884                                 right.ToString () + ")";
1885                 }
1886                 
1887                 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1888                 {
1889                         if (expr.Type == target_type)
1890                                 return expr;
1891
1892                         return ConvertImplicit (ec, expr, target_type, loc);
1893                 }
1894
1895                 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1896                 {
1897                         Report.Error (
1898                                 34, loc, "Operator `" + OperName (oper) 
1899                                 + "' is ambiguous on operands of type `"
1900                                 + TypeManager.CSharpName (l) + "' "
1901                                 + "and `" + TypeManager.CSharpName (r)
1902                                 + "'");
1903                 }
1904
1905                 bool IsOfType (EmitContext ec, Type l, Type r, Type t, bool check_user_conversions)
1906                 {
1907                         if ((l == t) || (r == t))
1908                                 return true;
1909
1910                         if (!check_user_conversions)
1911                                 return false;
1912
1913                         if (ImplicitUserConversionExists (ec, l, t))
1914                                 return true;
1915                         else if (ImplicitUserConversionExists (ec, r, t))
1916                                 return true;
1917                         else
1918                                 return false;
1919                 }
1920
1921                 //
1922                 // Note that handling the case l == Decimal || r == Decimal
1923                 // is taken care of by the Step 1 Operator Overload resolution.
1924                 //
1925                 // If `check_user_conv' is true, we also check whether a user-defined conversion
1926                 // exists.  Note that we only need to do this if both arguments are of a user-defined
1927                 // type, otherwise ConvertImplict() already finds the user-defined conversion for us,
1928                 // so we don't explicitly check for performance reasons.
1929                 //
1930                 bool DoNumericPromotions (EmitContext ec, Type l, Type r, bool check_user_conv)
1931                 {
1932                         if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){
1933                                 //
1934                                 // If either operand is of type double, the other operand is
1935                                 // conveted to type double.
1936                                 //
1937                                 if (r != TypeManager.double_type)
1938                                         right = ConvertImplicit (ec, right, TypeManager.double_type, loc);
1939                                 if (l != TypeManager.double_type)
1940                                         left = ConvertImplicit (ec, left, TypeManager.double_type, loc);
1941                                 
1942                                 type = TypeManager.double_type;
1943                         } else if (IsOfType (ec, l, r, TypeManager.float_type, check_user_conv)){
1944                                 //
1945                                 // if either operand is of type float, the other operand is
1946                                 // converted to type float.
1947                                 //
1948                                 if (r != TypeManager.double_type)
1949                                         right = ConvertImplicit (ec, right, TypeManager.float_type, loc);
1950                                 if (l != TypeManager.double_type)
1951                                         left = ConvertImplicit (ec, left, TypeManager.float_type, loc);
1952                                 type = TypeManager.float_type;
1953                         } else if (IsOfType (ec, l, r, TypeManager.uint64_type, check_user_conv)){
1954                                 Expression e;
1955                                 Type other;
1956                                 //
1957                                 // If either operand is of type ulong, the other operand is
1958                                 // converted to type ulong.  or an error ocurrs if the other
1959                                 // operand is of type sbyte, short, int or long
1960                                 //
1961                                 if (l == TypeManager.uint64_type){
1962                                         if (r != TypeManager.uint64_type){
1963                                                 if (right is IntConstant){
1964                                                         IntConstant ic = (IntConstant) right;
1965                                                         
1966                                                         e = TryImplicitIntConversion (l, ic);
1967                                                         if (e != null)
1968                                                                 right = e;
1969                                                 } else if (right is LongConstant){
1970                                                         long ll = ((LongConstant) right).Value;
1971
1972                                                         if (ll > 0)
1973                                                                 right = new ULongConstant ((ulong) ll);
1974                                                 } else {
1975                                                         e = ImplicitNumericConversion (ec, right, l, loc);
1976                                                         if (e != null)
1977                                                                 right = e;
1978                                                 }
1979                                         }
1980                                         other = right.Type;
1981                                 } else {
1982                                         if (left is IntConstant){
1983                                                 e = TryImplicitIntConversion (r, (IntConstant) left);
1984                                                 if (e != null)
1985                                                         left = e;
1986                                         } else if (left is LongConstant){
1987                                                 long ll = ((LongConstant) left).Value;
1988                                                 
1989                                                 if (ll > 0)
1990                                                         left = new ULongConstant ((ulong) ll);
1991                                         } else {
1992                                                 e = ImplicitNumericConversion (ec, left, r, loc);
1993                                                 if (e != null)
1994                                                         left = e;
1995                                         }
1996                                         other = left.Type;
1997                                 }
1998
1999                                 if ((other == TypeManager.sbyte_type) ||
2000                                     (other == TypeManager.short_type) ||
2001                                     (other == TypeManager.int32_type) ||
2002                                     (other == TypeManager.int64_type))
2003                                         Error_OperatorAmbiguous (loc, oper, l, r);
2004                                 type = TypeManager.uint64_type;
2005                         } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){
2006                                 //
2007                                 // If either operand is of type long, the other operand is converted
2008                                 // to type long.
2009                                 //
2010                                 if (l != TypeManager.int64_type)
2011                                         left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);
2012                                 if (r != TypeManager.int64_type)
2013                                         right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);
2014                                 
2015                                 type = TypeManager.int64_type;
2016                         } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){
2017                                 //
2018                                 // If either operand is of type uint, and the other
2019                                 // operand is of type sbyte, short or int, othe operands are
2020                                 // converted to type long.
2021                                 //
2022                                 Type other = null;
2023                                 
2024                                 if (l == TypeManager.uint32_type){
2025                                         if (right is IntConstant){
2026                                                 IntConstant ic = (IntConstant) right;
2027                                                 int val = ic.Value;
2028                                                 
2029                                                 if (val >= 0)
2030                                                         right = new UIntConstant ((uint) val);
2031
2032                                                 type = l;
2033                                                 return true;
2034                                         }
2035                                         other = r;
2036                                 } 
2037                                 else if (r == TypeManager.uint32_type){
2038                                         if (left is IntConstant){
2039                                                 IntConstant ic = (IntConstant) left;
2040                                                 int val = ic.Value;
2041                                                 
2042                                                 if (val >= 0)
2043                                                         left = new UIntConstant ((uint) val);
2044
2045                                                 type = r;
2046                                                 return true;
2047                                         }
2048                                         
2049                                         other = l;
2050                                 }
2051
2052                                 if ((other == TypeManager.sbyte_type) ||
2053                                     (other == TypeManager.short_type) ||
2054                                     (other == TypeManager.int32_type)){
2055                                         left = ForceConversion (ec, left, TypeManager.int64_type);
2056                                         right = ForceConversion (ec, right, TypeManager.int64_type);
2057                                         type = TypeManager.int64_type;
2058                                 } else {
2059                                         //
2060                                         // if either operand is of type uint, the other
2061                                         // operand is converd to type uint
2062                                         //
2063                                         left = ForceConversion (ec, left, TypeManager.uint32_type);
2064                                         right = ForceConversion (ec, right, TypeManager.uint32_type);
2065                                         type = TypeManager.uint32_type;
2066                                 } 
2067                         } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
2068                                 if (l != TypeManager.decimal_type)
2069                                         left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);
2070
2071                                 if (r != TypeManager.decimal_type)
2072                                         right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);
2073                                 type = TypeManager.decimal_type;
2074                         } else {
2075                                 left = ForceConversion (ec, left, TypeManager.int32_type);
2076                                 right = ForceConversion (ec, right, TypeManager.int32_type);
2077
2078                                 type = TypeManager.int32_type;
2079                         }
2080
2081                         return (left != null) && (right != null);
2082                 }
2083
2084                 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
2085                 {
2086                         Report.Error (19, loc,
2087                                "Operator " + name + " cannot be applied to operands of type `" +
2088                                TypeManager.CSharpName (l) + "' and `" +
2089                                TypeManager.CSharpName (r) + "'");
2090                 }
2091                 
2092                 void Error_OperatorCannotBeApplied ()
2093                 {
2094                         Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
2095                 }
2096
2097                 static bool is_32_or_64 (Type t)
2098                 {
2099                         return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
2100                                 t == TypeManager.int64_type || t == TypeManager.uint64_type);
2101                 }
2102
2103                 static bool is_unsigned (Type t)
2104                 {
2105                         return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
2106                                 t == TypeManager.short_type || t == TypeManager.byte_type);
2107                 }
2108
2109                 static bool is_user_defined (Type t)
2110                 {
2111                         if (t.IsSubclassOf (TypeManager.value_type) &&
2112                             (!TypeManager.IsBuiltinType (t) || t == TypeManager.decimal_type))
2113                                 return true;
2114                         else
2115                                 return false;
2116                 }
2117                                         
2118                 Expression CheckShiftArguments (EmitContext ec)
2119                 {
2120                         Expression e;
2121                         Type l = left.Type;
2122                         Type r = right.Type;
2123
2124                         e = ForceConversion (ec, right, TypeManager.int32_type);
2125                         if (e == null){
2126                                 Error_OperatorCannotBeApplied ();
2127                                 return null;
2128                         }
2129                         right = e;
2130
2131                         if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
2132                             ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
2133                             ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
2134                             ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){
2135                                 left = e;
2136                                 type = e.Type;
2137
2138                                 return this;
2139                         }
2140                         Error_OperatorCannotBeApplied ();
2141                         return null;
2142                 }
2143
2144                 Expression ResolveOperator (EmitContext ec)
2145                 {
2146                         Type l = left.Type;
2147                         Type r = right.Type;
2148
2149                         bool overload_failed = false;
2150
2151                         //
2152                         // Special cases: string comapred to null
2153                         //
2154                         if (oper == Operator.Equality || oper == Operator.Inequality){
2155                                 if ((l == TypeManager.string_type && (right is NullLiteral)) ||
2156                                     (r == TypeManager.string_type && (left is NullLiteral))){
2157                                         Type = TypeManager.bool_type;
2158                                         
2159                                         return this;
2160                                 }
2161                         }
2162
2163                         //
2164                         // Do not perform operator overload resolution when both sides are
2165                         // built-in types
2166                         //
2167                         if (!(TypeManager.IsCLRType (l) && TypeManager.IsCLRType (r))){
2168                                 //
2169                                 // Step 1: Perform Operator Overload location
2170                                 //
2171                                 Expression left_expr, right_expr;
2172                                 
2173                                 string op = oper_names [(int) oper];
2174                                 
2175                                 MethodGroupExpr union;
2176                                 left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
2177                                 if (r != l){
2178                                         right_expr = MemberLookup (
2179                                                 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
2180                                         union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
2181                                 } else
2182                                         union = (MethodGroupExpr) left_expr;
2183                                 
2184                                 if (union != null) {
2185                                         Arguments = new ArrayList ();
2186                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
2187                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
2188                                         
2189                                         method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
2190                                         if (method != null) {
2191                                                 MethodInfo mi = (MethodInfo) method;
2192                                                 
2193                                                 type = mi.ReturnType;
2194                                                 return this;
2195                                         } else {
2196                                                 overload_failed = true;
2197                                         }
2198                                 }
2199                         }
2200                         
2201                         //
2202                         // Step 2: Default operations on CLI native types.
2203                         //
2204
2205                         //
2206                         // Step 0: String concatenation (because overloading will get this wrong)
2207                         //
2208                         if (oper == Operator.Addition){
2209                                 //
2210                                 // If any of the arguments is a string, cast to string
2211                                 //
2212                                 
2213                                 if (l == TypeManager.string_type){
2214                                         
2215                                         if (r == TypeManager.void_type) {
2216                                                 Error_OperatorCannotBeApplied ();
2217                                                 return null;
2218                                         }
2219                                         
2220                                         if (r == TypeManager.string_type){
2221                                                 if (left is Constant && right is Constant){
2222                                                         StringConstant ls = (StringConstant) left;
2223                                                         StringConstant rs = (StringConstant) right;
2224                                                         
2225                                                         return new StringConstant (
2226                                                                 ls.Value + rs.Value);
2227                                                 }
2228
2229                                                 if (left is Binary){
2230                                                         Binary b = (Binary) left;
2231
2232                                                         //
2233                                                         // Call String.Concat (string, string, string) or
2234                                                         // String.Concat (string, string, string, string)
2235                                                         // if possible.
2236                                                         //
2237                                                         if (b.oper == Operator.Addition &&
2238                                                             (b.method == TypeManager.string_concat_string_string_string ||
2239                                                              b.method == TypeManager.string_concat_string_string_string_string)){
2240                                                                 ArrayList bargs = b.Arguments;
2241                                                                 int count = bargs.Count;
2242                                                                 
2243                                                                 if (count == 2){
2244                                                                         Arguments = bargs;
2245                                                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
2246                                                                         type = TypeManager.string_type;
2247                                                                         method = TypeManager.string_concat_string_string_string;
2248                                                                         
2249                                                                         return this;
2250                                                                 } else if (count == 3){
2251                                                                         Arguments = bargs;
2252                                                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
2253                                                                         type = TypeManager.string_type;
2254                                                                         method = TypeManager.string_concat_string_string_string_string;                                                                 
2255                                                                         return this;
2256                                                                 }
2257                                                         }
2258                                                 }
2259
2260                                                 // string + string
2261                                                 method = TypeManager.string_concat_string_string;
2262                                         } else {
2263                                                 // string + object
2264                                                 method = TypeManager.string_concat_object_object;
2265                                                 right = ConvertImplicit (ec, right,
2266                                                                          TypeManager.object_type, loc);
2267                                                 if (right == null){
2268                                                         Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2269                                                         return null;
2270                                                 }
2271                                         }
2272                                         type = TypeManager.string_type;
2273
2274                                         Arguments = new ArrayList ();
2275                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
2276                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
2277
2278                                         return this;
2279                                         
2280                                 } else if (r == TypeManager.string_type){
2281                                         // object + string
2282
2283                                         if (l == TypeManager.void_type) {
2284                                                 Error_OperatorCannotBeApplied ();
2285                                                 return null;
2286                                         }
2287                                         
2288                                         method = TypeManager.string_concat_object_object;
2289                                         left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
2290                                         if (left == null){
2291                                                 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2292                                                 return null;
2293                                         }
2294                                         Arguments = new ArrayList ();
2295                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
2296                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
2297
2298                                         type = TypeManager.string_type;
2299
2300                                         return this;
2301                                 }
2302
2303                                 //
2304                                 // Transform a + ( - b) into a - b
2305                                 //
2306                                 if (right is Unary){
2307                                         Unary right_unary = (Unary) right;
2308
2309                                         if (right_unary.Oper == Unary.Operator.UnaryNegation){
2310                                                 oper = Operator.Subtraction;
2311                                                 right = right_unary.Expr;
2312                                                 r = right.Type;
2313                                         }
2314                                 }
2315                         }
2316
2317                         if (oper == Operator.Equality || oper == Operator.Inequality){
2318                                 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
2319                                         if (r != TypeManager.bool_type || l != TypeManager.bool_type){
2320                                                 Error_OperatorCannotBeApplied ();
2321                                                 return null;
2322                                         }
2323                                         
2324                                         type = TypeManager.bool_type;
2325                                         return this;
2326                                 }
2327
2328                                 //
2329                                 // operator != (object a, object b)
2330                                 // operator == (object a, object b)
2331                                 //
2332                                 // For this to be used, both arguments have to be reference-types.
2333                                 // Read the rationale on the spec (14.9.6)
2334                                 //
2335                                 // Also, if at compile time we know that the classes do not inherit
2336                                 // one from the other, then we catch the error there.
2337                                 //
2338                                 if (!(l.IsValueType || r.IsValueType)){
2339                                         type = TypeManager.bool_type;
2340
2341                                         if (l == r)
2342                                                 return this;
2343                                         
2344                                         if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
2345                                                 return this;
2346
2347                                         //
2348                                         // Also, a standard conversion must exist from either one
2349                                         //
2350                                         if (!(StandardConversionExists (left, r) ||
2351                                               StandardConversionExists (right, l))){
2352                                                 Error_OperatorCannotBeApplied ();
2353                                                 return null;
2354                                         }
2355                                         //
2356                                         // We are going to have to convert to an object to compare
2357                                         //
2358                                         if (l != TypeManager.object_type)
2359                                                 left = new EmptyCast (left, TypeManager.object_type);
2360                                         if (r != TypeManager.object_type)
2361                                                 right = new EmptyCast (right, TypeManager.object_type);
2362
2363                                         //
2364                                         // FIXME: CSC here catches errors cs254 and cs252
2365                                         //
2366                                         return this;
2367                                 }
2368
2369                                 //
2370                                 // One of them is a valuetype, but the other one is not.
2371                                 //
2372                                 if (!l.IsValueType || !r.IsValueType) {
2373                                         Error_OperatorCannotBeApplied ();
2374                                         return null;
2375                                 }
2376                         }
2377
2378                         // Only perform numeric promotions on:
2379                         // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2380                         //
2381                         if (oper == Operator.Addition || oper == Operator.Subtraction) {
2382                                 if (l.IsSubclassOf (TypeManager.delegate_type) &&
2383                                     r.IsSubclassOf (TypeManager.delegate_type)) {
2384                                         
2385                                         Arguments = new ArrayList ();
2386                                         Arguments.Add (new Argument (left, Argument.AType.Expression));
2387                                         Arguments.Add (new Argument (right, Argument.AType.Expression));
2388                                         
2389                                         if (oper == Operator.Addition)
2390                                                 method = TypeManager.delegate_combine_delegate_delegate;
2391                                         else
2392                                                 method = TypeManager.delegate_remove_delegate_delegate;
2393
2394                                         if (l != r) {
2395                                                 Error_OperatorCannotBeApplied ();
2396                                                 return null;
2397                                         }
2398
2399                                         DelegateOperation = true;
2400                                         type = l;
2401                                         return this;
2402                                 }
2403
2404                                 //
2405                                 // Pointer arithmetic:
2406                                 //
2407                                 // T* operator + (T* x, int y);
2408                                 // T* operator + (T* x, uint y);
2409                                 // T* operator + (T* x, long y);
2410                                 // T* operator + (T* x, ulong y);
2411                                 //
2412                                 // T* operator + (int y,   T* x);
2413                                 // T* operator + (uint y,  T *x);
2414                                 // T* operator + (long y,  T *x);
2415                                 // T* operator + (ulong y, T *x);
2416                                 //
2417                                 // T* operator - (T* x, int y);
2418                                 // T* operator - (T* x, uint y);
2419                                 // T* operator - (T* x, long y);
2420                                 // T* operator - (T* x, ulong y);
2421                                 //
2422                                 // long operator - (T* x, T *y)
2423                                 //
2424                                 if (l.IsPointer){
2425                                         if (r.IsPointer && oper == Operator.Subtraction){
2426                                                 if (r == l)
2427                                                         return new PointerArithmetic (
2428                                                                 false, left, right, TypeManager.int64_type,
2429                                                                 loc);
2430                                         } else if (is_32_or_64 (r))
2431                                                 return new PointerArithmetic (
2432                                                         oper == Operator.Addition, left, right, l, loc);
2433                                 } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
2434                                         return new PointerArithmetic (
2435                                                 true, right, left, r, loc);
2436                         }
2437                         
2438                         //
2439                         // Enumeration operators
2440                         //
2441                         bool lie = TypeManager.IsEnumType (l);
2442                         bool rie = TypeManager.IsEnumType (r);
2443                         if (lie || rie){
2444                                 Expression temp;
2445
2446                                 // U operator - (E e, E f)
2447                                 if (lie && rie && oper == Operator.Subtraction){
2448                                         if (l == r){
2449                                                 type = TypeManager.EnumToUnderlying (l);
2450                                                 return this;
2451                                         } 
2452                                         Error_OperatorCannotBeApplied ();
2453                                         return null;
2454                                 }
2455                                         
2456                                 //
2457                                 // operator + (E e, U x)
2458                                 // operator - (E e, U x)
2459                                 //
2460                                 if (oper == Operator.Addition || oper == Operator.Subtraction){
2461                                         Type enum_type = lie ? l : r;
2462                                         Type other_type = lie ? r : l;
2463                                         Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2464 ;
2465                                         
2466                                         if (underlying_type != other_type){
2467                                                 Error_OperatorCannotBeApplied ();
2468                                                 return null;
2469                                         }
2470
2471                                         type = enum_type;
2472                                         return this;
2473                                 }
2474                                 
2475                                 if (!rie){
2476                                         temp = ConvertImplicit (ec, right, l, loc);
2477                                         if (temp != null)
2478                                                 right = temp;
2479                                         else {
2480                                                 Error_OperatorCannotBeApplied ();
2481                                                 return null;
2482                                         }
2483                                 } if (!lie){
2484                                         temp = ConvertImplicit (ec, left, r, loc);
2485                                         if (temp != null){
2486                                                 left = temp;
2487                                                 l = r;
2488                                         } else {
2489                                                 Error_OperatorCannotBeApplied ();
2490                                                 return null;
2491                                         }
2492                                 }
2493
2494                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
2495                                     oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2496                                     oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2497                                         if (left.Type != right.Type){
2498                                                 Error_OperatorCannotBeApplied ();
2499                                                 return null;
2500                                         }
2501                                         type = TypeManager.bool_type;
2502                                         return this;
2503                                 }
2504
2505                                 if (oper == Operator.BitwiseAnd ||
2506                                     oper == Operator.BitwiseOr ||
2507                                     oper == Operator.ExclusiveOr){
2508                                         type = l;
2509                                         return this;
2510                                 }
2511                                 Error_OperatorCannotBeApplied ();
2512                                 return null;
2513                         }
2514                         
2515                         if (oper == Operator.LeftShift || oper == Operator.RightShift)
2516                                 return CheckShiftArguments (ec);
2517
2518                         if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2519                                 if (l != TypeManager.bool_type || r != TypeManager.bool_type){
2520                                         Error_OperatorCannotBeApplied ();
2521                                         return null;
2522                                 }
2523
2524                                 type = TypeManager.bool_type;
2525                                 return this;
2526                         } 
2527
2528                         //
2529                         // operator & (bool x, bool y)
2530                         // operator | (bool x, bool y)
2531                         // operator ^ (bool x, bool y)
2532                         //
2533                         if (l == TypeManager.bool_type && r == TypeManager.bool_type){
2534                                 if (oper == Operator.BitwiseAnd ||
2535                                     oper == Operator.BitwiseOr ||
2536                                     oper == Operator.ExclusiveOr){
2537                                         type = l;
2538                                         return this;
2539                                 }
2540                         }
2541                         
2542                         //
2543                         // Pointer comparison
2544                         //
2545                         if (l.IsPointer && r.IsPointer){
2546                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
2547                                     oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2548                                     oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2549                                         type = TypeManager.bool_type;
2550                                         return this;
2551                                 }
2552                         }
2553                         
2554                         //
2555                         // We are dealing with numbers
2556                         //
2557                         if (overload_failed){
2558                                 Error_OperatorCannotBeApplied ();
2559                                 return null;
2560                         }
2561
2562                         //
2563                         // This will leave left or right set to null if there is an error
2564                         //
2565                         bool check_user_conv = is_user_defined (l) && is_user_defined (r);
2566                         DoNumericPromotions (ec, l, r, check_user_conv);
2567                         if (left == null || right == null){
2568                                 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2569                                 return null;
2570                         }
2571
2572                         //
2573                         // reload our cached types if required
2574                         //
2575                         l = left.Type;
2576                         r = right.Type;
2577                         
2578                         if (oper == Operator.BitwiseAnd ||
2579                             oper == Operator.BitwiseOr ||
2580                             oper == Operator.ExclusiveOr){
2581                                 if (l == r){
2582                                         if (!((l == TypeManager.int32_type) ||
2583                                               (l == TypeManager.uint32_type) ||
2584                                               (l == TypeManager.int64_type) ||
2585                                               (l == TypeManager.uint64_type)))
2586                                                 type = l;
2587                                 } else {
2588                                         Error_OperatorCannotBeApplied ();
2589                                         return null;
2590                                 }
2591                         }
2592
2593                         if (oper == Operator.Equality ||
2594                             oper == Operator.Inequality ||
2595                             oper == Operator.LessThanOrEqual ||
2596                             oper == Operator.LessThan ||
2597                             oper == Operator.GreaterThanOrEqual ||
2598                             oper == Operator.GreaterThan){
2599                                 type = TypeManager.bool_type;
2600                         }
2601
2602                         return this;
2603                 }
2604
2605                 public override Expression DoResolve (EmitContext ec)
2606                 {
2607                         left = left.Resolve (ec);
2608                         right = right.Resolve (ec);
2609
2610                         if (left == null || right == null)
2611                                 return null;
2612
2613                         eclass = ExprClass.Value;
2614
2615                         Constant rc = right as Constant;
2616                         Constant lc = left as Constant;
2617
2618                         if (rc != null & lc != null){
2619                                 Expression e = ConstantFold.BinaryFold (
2620                                         ec, oper, lc, rc, loc);
2621                                         if (e != null)
2622                                                 return e;
2623                         }
2624
2625                         return ResolveOperator (ec);
2626                 }
2627
2628                 /// <remarks>
2629                 ///   EmitBranchable is called from Statement.EmitBoolExpression in the
2630                 ///   context of a conditional bool expression.  This function will return
2631                 ///   false if it is was possible to use EmitBranchable, or true if it was.
2632                 ///
2633                 ///   The expression's code is generated, and we will generate a branch to `target'
2634                 ///   if the resulting expression value is equal to isTrue
2635                 /// </remarks>
2636                 public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)
2637                 {
2638                         if (method != null)
2639                                 return false;
2640
2641                         ILGenerator ig = ec.ig;
2642
2643                         //
2644                         // This is more complicated than it looks, but its just to avoid
2645                         // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2646                         // but on top of that we want for == and != to use a special path
2647                         // if we are comparing against null
2648                         //
2649                         if (oper == Operator.Equality || oper == Operator.Inequality){
2650                                 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2651
2652                                 if (left is NullLiteral){
2653                                         right.Emit (ec);
2654                                         if (my_on_true)
2655                                                 ig.Emit (OpCodes.Brtrue, target);
2656                                         else
2657                                                 ig.Emit (OpCodes.Brfalse, target);
2658                                         return true;
2659                                 } else if (right is NullLiteral){
2660                                         left.Emit (ec);
2661                                         if (my_on_true)
2662                                                 ig.Emit (OpCodes.Brtrue, target);
2663                                         else
2664                                                 ig.Emit (OpCodes.Brfalse, target);
2665                                         return true;
2666                                 } else if (left is BoolConstant){
2667                                         right.Emit (ec);
2668                                         if (my_on_true != ((BoolConstant) left).Value)
2669                                                 ig.Emit (OpCodes.Brtrue, target);
2670                                         else
2671                                                 ig.Emit (OpCodes.Brfalse, target);
2672                                         return true;
2673                                 } else if (right is BoolConstant){
2674                                         left.Emit (ec);
2675                                         if (my_on_true != ((BoolConstant) right).Value)
2676                                                 ig.Emit (OpCodes.Brtrue, target);
2677                                         else
2678                                                 ig.Emit (OpCodes.Brfalse, target);
2679                                         return true;
2680                                 }
2681
2682                         } else if (oper == Operator.LogicalAnd){
2683                                 if (left is Binary){
2684                                         Binary left_binary = (Binary) left;
2685
2686                                         if (onTrue){
2687                                                 Label tests_end = ig.DefineLabel ();
2688                                                 
2689                                                 if (left_binary.EmitBranchable (ec, tests_end, false)){
2690                                                         if (right is Binary){
2691                                                                 Binary right_binary = (Binary) right;
2692
2693                                                                 if (right_binary.EmitBranchable (ec, target, true)){
2694                                                                         ig.MarkLabel (tests_end);
2695                                                                         return true;
2696                                                                 }
2697                                                         }
2698                                                         right.Emit (ec);
2699                                                         ig.Emit (OpCodes.Brtrue, target);
2700                                                         ig.MarkLabel (tests_end);
2701                                                         return true;
2702                                                 }
2703                                         } else {
2704                                                 if (left_binary.EmitBranchable (ec, target, false)){
2705                                                         if (right is Binary){
2706                                                                 Binary right_binary = (Binary) right;
2707                                                                 
2708                                                                 if (right_binary.EmitBranchable (ec, target, false))
2709                                                                         return true;
2710                                                         }
2711                                                         right.Emit (ec);
2712                                                         if (onTrue)
2713                                                                 ig.Emit (OpCodes.Brtrue, target);
2714                                                         else
2715                                                                 ig.Emit (OpCodes.Brfalse, target);
2716                                                         return true;
2717                                                 }
2718                                         }
2719                                         //
2720                                         // Give up, and let the regular Emit work, but we could
2721                                         // also optimize the left-non-Branchable, but-right-Branchable
2722                                         //
2723                                 }
2724                                 return false;
2725                         } else if (oper == Operator.LogicalOr){
2726                                 if (left is Binary){
2727                                         Binary left_binary = (Binary) left;
2728
2729                                         if (onTrue){
2730                                                 if (left_binary.EmitBranchable (ec, target, true)){
2731                                                         if (right is Binary){
2732                                                                 Binary right_binary = (Binary) right;
2733                                                                 
2734                                                                 if (right_binary.EmitBranchable (ec, target, true))
2735                                                                         return true;
2736                                                         }
2737                                                         right.Emit (ec);
2738                                                         ig.Emit (OpCodes.Brtrue, target);
2739                                                         return true;
2740                                                 }
2741                                                 
2742                                                 //
2743                                                 // Give up, and let the regular Emit work, but we could
2744                                                 // also optimize the left-non-Branchable, but-right-Branchable
2745                                                 //
2746                                         } else {
2747                                                 Label tests_end = ig.DefineLabel ();
2748                                                 
2749                                                 if (left_binary.EmitBranchable (ec, tests_end, true)){
2750                                                         if (right is Binary){
2751                                                                 Binary right_binary = (Binary) right;
2752
2753                                                                 if (right_binary.EmitBranchable (ec, target, false)){
2754                                                                         ig.MarkLabel (tests_end);
2755                                                                         return true;
2756                                                                 }
2757                                                         }
2758                                                         right.Emit (ec);
2759                                                         ig.Emit (OpCodes.Brfalse, target);
2760                                                         ig.MarkLabel (tests_end);
2761                                                         return true;
2762                                                 }
2763                                         }
2764                                 }
2765                                 
2766                                 return false;
2767                         } else if (!(oper == Operator.LessThan ||
2768                                 oper == Operator.GreaterThan ||
2769                                 oper == Operator.LessThanOrEqual ||
2770                                 oper == Operator.GreaterThanOrEqual))
2771                                 return false;
2772                         
2773                         left.Emit (ec);
2774                         right.Emit (ec);
2775
2776                         Type t = left.Type;
2777                         bool isUnsigned = is_unsigned (t);
2778
2779                         switch (oper){
2780                         case Operator.Equality:
2781                                 if (onTrue)
2782                                         ig.Emit (OpCodes.Beq, target);
2783                                 else
2784                                         ig.Emit (OpCodes.Bne_Un, target);
2785                                 break;
2786
2787                         case Operator.Inequality:
2788                                 if (onTrue)
2789                                         ig.Emit (OpCodes.Bne_Un, target);
2790                                 else
2791                                         ig.Emit (OpCodes.Beq, target);
2792                                 break;
2793
2794                         case Operator.LessThan:
2795                                 if (onTrue)
2796                                         if (isUnsigned)
2797                                                 ig.Emit (OpCodes.Blt_Un, target);
2798                                         else
2799                                                 ig.Emit (OpCodes.Blt, target);
2800                                 else
2801                                         if (isUnsigned)
2802                                                 ig.Emit (OpCodes.Bge_Un, target);
2803                                         else
2804                                                 ig.Emit (OpCodes.Bge, target);
2805                                 break;
2806
2807                         case Operator.GreaterThan:
2808                                 if (onTrue)
2809                                         if (isUnsigned)
2810                                                 ig.Emit (OpCodes.Bgt_Un, target);
2811                                         else
2812                                                 ig.Emit (OpCodes.Bgt, target);
2813                                 else
2814                                         if (isUnsigned)
2815                                                 ig.Emit (OpCodes.Ble_Un, target);
2816                                         else
2817                                                 ig.Emit (OpCodes.Ble, target);
2818                                 break;
2819
2820                         case Operator.LessThanOrEqual:
2821                                 if (t == TypeManager.double_type || t == TypeManager.float_type)
2822                                         isUnsigned = true;
2823
2824                                 if (onTrue)
2825                                         if (isUnsigned)
2826                                                 ig.Emit (OpCodes.Ble_Un, target);
2827                                         else
2828                                                 ig.Emit (OpCodes.Ble, target);
2829                                 else
2830                                         if (isUnsigned)
2831                                                 ig.Emit (OpCodes.Bgt_Un, target);
2832                                         else
2833                                                 ig.Emit (OpCodes.Bgt, target);
2834                                 break;
2835
2836
2837                         case Operator.GreaterThanOrEqual:
2838                                 if (t == TypeManager.double_type || t == TypeManager.float_type)
2839                                         isUnsigned = true;
2840                                 if (onTrue)
2841                                         if (isUnsigned)
2842                                                 ig.Emit (OpCodes.Bge_Un, target);
2843                                         else
2844                                                 ig.Emit (OpCodes.Bge, target);
2845                                 else
2846                                         if (isUnsigned)
2847                                                 ig.Emit (OpCodes.Blt_Un, target);
2848                                         else
2849                                                 ig.Emit (OpCodes.Blt, target);
2850                                 break;
2851
2852                         default:
2853                                 return false;
2854                         }
2855                         
2856                         return true;
2857                 }
2858                 
2859                 public override void Emit (EmitContext ec)
2860                 {
2861                         ILGenerator ig = ec.ig;
2862                         Type l = left.Type;
2863                         Type r = right.Type;
2864                         OpCode opcode;
2865
2866                         if (method != null) {
2867
2868                                 // Note that operators are static anyway
2869                                 
2870                                 if (Arguments != null) 
2871                                         Invocation.EmitArguments (ec, method, Arguments);
2872                                 
2873                                 if (method is MethodInfo)
2874                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
2875                                 else
2876                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2877
2878                                 if (DelegateOperation)
2879                                         ig.Emit (OpCodes.Castclass, type);
2880                                         
2881                                 return;
2882                         }
2883
2884                         //
2885                         // Handle short-circuit operators differently
2886                         // than the rest
2887                         //
2888                         if (oper == Operator.LogicalAnd){
2889                                 Label load_zero = ig.DefineLabel ();
2890                                 Label end = ig.DefineLabel ();
2891                                 bool process = true;
2892
2893                                 if (left is Binary){
2894                                         Binary left_binary = (Binary) left;
2895
2896                                         if (left_binary.EmitBranchable (ec, load_zero, false)){
2897                                                 right.Emit (ec);
2898                                                 ig.Emit (OpCodes.Br, end);
2899                                                 process = false;
2900                                         }
2901                                 }
2902
2903                                 if (process){
2904                                         left.Emit (ec);
2905                                         ig.Emit (OpCodes.Brfalse, load_zero);
2906                                         right.Emit (ec);
2907                                         ig.Emit (OpCodes.Br, end);
2908                                 }
2909                                 ig.MarkLabel (load_zero);
2910                                 ig.Emit (OpCodes.Ldc_I4_0);
2911                                 ig.MarkLabel (end);
2912                                 return;
2913                         } else if (oper == Operator.LogicalOr){
2914                                 Label load_one = ig.DefineLabel ();
2915                                 Label end = ig.DefineLabel ();
2916                                 bool process = true;
2917                                 
2918                                 if (left is Binary){
2919                                         Binary left_binary = (Binary) left;
2920
2921                                         if (left_binary.EmitBranchable (ec, load_one, true)){
2922                                                 right.Emit (ec);
2923                                                 ig.Emit (OpCodes.Br, end);
2924                                                 process = false;
2925                                         } 
2926                                 }
2927
2928                                 if (process){
2929                                         left.Emit (ec);
2930                                         ig.Emit (OpCodes.Brtrue, load_one);
2931                                         right.Emit (ec);
2932                                         ig.Emit (OpCodes.Br, end);
2933                                 }
2934                                 ig.MarkLabel (load_one);
2935                                 ig.Emit (OpCodes.Ldc_I4_1);
2936                                 ig.MarkLabel (end);
2937                                 return;
2938                         }
2939                         
2940                         left.Emit (ec);
2941                         right.Emit (ec);
2942
2943                         bool isUnsigned = is_unsigned (left.Type);
2944
2945                         switch (oper){
2946                         case Operator.Multiply:
2947                                 if (ec.CheckState){
2948                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2949                                                 opcode = OpCodes.Mul_Ovf;
2950                                         else if (isUnsigned)
2951                                                 opcode = OpCodes.Mul_Ovf_Un;
2952                                         else
2953                                                 opcode = OpCodes.Mul;
2954                                 } else
2955                                         opcode = OpCodes.Mul;
2956
2957                                 break;
2958
2959                         case Operator.Division:
2960                                 if (isUnsigned)
2961                                         opcode = OpCodes.Div_Un;
2962                                 else
2963                                         opcode = OpCodes.Div;
2964                                 break;
2965
2966                         case Operator.Modulus:
2967                                 if (isUnsigned)
2968                                         opcode = OpCodes.Rem_Un;
2969                                 else
2970                                         opcode = OpCodes.Rem;
2971                                 break;
2972
2973                         case Operator.Addition:
2974                                 if (ec.CheckState){
2975                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2976                                                 opcode = OpCodes.Add_Ovf;
2977                                         else if (isUnsigned)
2978                                                 opcode = OpCodes.Add_Ovf_Un;
2979                                         else
2980                                                 opcode = OpCodes.Add;
2981                                 } else
2982                                         opcode = OpCodes.Add;
2983                                 break;
2984
2985                         case Operator.Subtraction:
2986                                 if (ec.CheckState){
2987                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2988                                                 opcode = OpCodes.Sub_Ovf;
2989                                         else if (isUnsigned)
2990                                                 opcode = OpCodes.Sub_Ovf_Un;
2991                                         else
2992                                                 opcode = OpCodes.Sub;
2993                                 } else
2994                                         opcode = OpCodes.Sub;
2995                                 break;
2996
2997                         case Operator.RightShift:
2998                                 if (isUnsigned)
2999                                         opcode = OpCodes.Shr_Un;
3000                                 else
3001                                         opcode = OpCodes.Shr;
3002                                 break;
3003                                 
3004                         case Operator.LeftShift:
3005                                 opcode = OpCodes.Shl;
3006                                 break;
3007
3008                         case Operator.Equality:
3009                                 opcode = OpCodes.Ceq;
3010                                 break;
3011
3012                         case Operator.Inequality:
3013                                 ig.Emit (OpCodes.Ceq);
3014                                 ig.Emit (OpCodes.Ldc_I4_0);
3015                                 
3016                                 opcode = OpCodes.Ceq;
3017                                 break;
3018
3019                         case Operator.LessThan:
3020                                 if (isUnsigned)
3021                                         opcode = OpCodes.Clt_Un;
3022                                 else
3023                                         opcode = OpCodes.Clt;
3024                                 break;
3025
3026                         case Operator.GreaterThan:
3027                                 if (isUnsigned)
3028                                         opcode = OpCodes.Cgt_Un;
3029                                 else
3030                                         opcode = OpCodes.Cgt;
3031                                 break;
3032
3033                         case Operator.LessThanOrEqual:
3034                                 Type lt = left.Type;
3035                                 
3036                                 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
3037                                         ig.Emit (OpCodes.Cgt_Un);
3038                                 else
3039                                         ig.Emit (OpCodes.Cgt);
3040                                 ig.Emit (OpCodes.Ldc_I4_0);
3041                                 
3042                                 opcode = OpCodes.Ceq;
3043                                 break;
3044
3045                         case Operator.GreaterThanOrEqual:
3046                                 Type le = left.Type;
3047                                 
3048                                 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
3049                                         ig.Emit (OpCodes.Clt_Un);
3050                                 else
3051                                         ig.Emit (OpCodes.Clt);
3052                                 
3053                                 ig.Emit (OpCodes.Ldc_I4_1);
3054                                 
3055                                 opcode = OpCodes.Sub;
3056                                 break;
3057
3058                         case Operator.BitwiseOr:
3059                                 opcode = OpCodes.Or;
3060                                 break;
3061
3062                         case Operator.BitwiseAnd:
3063                                 opcode = OpCodes.And;
3064                                 break;
3065
3066                         case Operator.ExclusiveOr:
3067                                 opcode = OpCodes.Xor;
3068                                 break;
3069
3070                         default:
3071                                 throw new Exception ("This should not happen: Operator = "
3072                                                      + oper.ToString ());
3073                         }
3074
3075                         ig.Emit (opcode);
3076                 }
3077
3078                 public bool IsBuiltinOperator {
3079                         get {
3080                                 return method == null;
3081                         }
3082                 }
3083         }
3084
3085         public class PointerArithmetic : Expression {
3086                 Expression left, right;
3087                 bool is_add;
3088
3089                 //
3090                 // We assume that `l' is always a pointer
3091                 //
3092                 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t,
3093                                           Location loc)
3094                 {
3095                         type = t;
3096                         eclass = ExprClass.Variable;
3097                         this.loc = loc;
3098                         left = l;
3099                         right = r;
3100                         is_add = is_addition;
3101                 }
3102
3103                 public override Expression DoResolve (EmitContext ec)
3104                 {
3105                         //
3106                         // We are born fully resolved
3107                         //
3108                         return this;
3109                 }
3110
3111                 public override void Emit (EmitContext ec)
3112                 {
3113                         Type op_type = left.Type;
3114                         ILGenerator ig = ec.ig;
3115                         int size = GetTypeSize (op_type.GetElementType ());
3116                         
3117                         if (right.Type.IsPointer){
3118                                 //
3119                                 // handle (pointer - pointer)
3120                                 //
3121                                 left.Emit (ec);
3122                                 right.Emit (ec);
3123                                 ig.Emit (OpCodes.Sub);
3124
3125                                 if (size != 1){
3126                                         if (size == 0)
3127                                                 ig.Emit (OpCodes.Sizeof, op_type);
3128                                         else 
3129                                                 IntLiteral.EmitInt (ig, size);
3130                                         ig.Emit (OpCodes.Div);
3131                                 }
3132                                 ig.Emit (OpCodes.Conv_I8);
3133                         } else {
3134                                 //
3135                                 // handle + and - on (pointer op int)
3136                                 //
3137                                 left.Emit (ec);
3138                                 ig.Emit (OpCodes.Conv_I);
3139                                 right.Emit (ec);
3140                                 if (size != 1){
3141                                         if (size == 0)
3142                                                 ig.Emit (OpCodes.Sizeof, op_type);
3143                                         else 
3144                                                 IntLiteral.EmitInt (ig, size);
3145                                         ig.Emit (OpCodes.Mul);
3146                                 }
3147                                 if (is_add)
3148                                         ig.Emit (OpCodes.Add);
3149                                 else
3150                                         ig.Emit (OpCodes.Sub);
3151                         }
3152                 }
3153         }
3154         
3155         /// <summary>
3156         ///   Implements the ternary conditional operator (?:)
3157         /// </summary>
3158         public class Conditional : Expression {
3159                 Expression expr, trueExpr, falseExpr;
3160                 
3161                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3162                 {
3163                         this.expr = expr;
3164                         this.trueExpr = trueExpr;
3165                         this.falseExpr = falseExpr;
3166                         this.loc = l;
3167                 }
3168
3169                 public Expression Expr {
3170                         get {
3171                                 return expr;
3172                         }
3173                 }
3174
3175                 public Expression TrueExpr {
3176                         get {
3177                                 return trueExpr;
3178                         }
3179                 }
3180
3181                 public Expression FalseExpr {
3182                         get {
3183                                 return falseExpr;
3184                         }
3185                 }
3186
3187                 public override Expression DoResolve (EmitContext ec)
3188                 {
3189                         expr = expr.Resolve (ec);
3190
3191                         if (expr == null)
3192                                 return null;
3193                         
3194                         if (expr.Type != TypeManager.bool_type){
3195                                 expr = Expression.ResolveBoolean (
3196                                         ec, expr, loc);
3197                                 
3198                                 if (expr == null)
3199                                         return null;
3200                         }
3201                         
3202                         trueExpr = trueExpr.Resolve (ec);
3203                         falseExpr = falseExpr.Resolve (ec);
3204
3205                         if (trueExpr == null || falseExpr == null)
3206                                 return null;
3207
3208                         eclass = ExprClass.Value;
3209                         if (trueExpr.Type == falseExpr.Type)
3210                                 type = trueExpr.Type;
3211                         else {
3212                                 Expression conv;
3213                                 Type true_type = trueExpr.Type;
3214                                 Type false_type = falseExpr.Type;
3215
3216                                 if (trueExpr is NullLiteral){
3217                                         type = false_type;
3218                                         return this;
3219                                 } else if (falseExpr is NullLiteral){
3220                                         type = true_type;
3221                                         return this;
3222                                 }
3223                                 
3224                                 //
3225                                 // First, if an implicit conversion exists from trueExpr
3226                                 // to falseExpr, then the result type is of type falseExpr.Type
3227                                 //
3228                                 conv = ConvertImplicit (ec, trueExpr, false_type, loc);
3229                                 if (conv != null){
3230                                         //
3231                                         // Check if both can convert implicitl to each other's type
3232                                         //
3233                                         if (ConvertImplicit (ec, falseExpr, true_type, loc) != null){
3234                                                 Error (172,
3235                                                        "Can not compute type of conditional expression " +
3236                                                        "as `" + TypeManager.CSharpName (trueExpr.Type) +
3237                                                        "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3238                                                        "' convert implicitly to each other");
3239                                                 return null;
3240                                         }
3241                                         type = false_type;
3242                                         trueExpr = conv;
3243                                 } else if ((conv = ConvertImplicit(ec, falseExpr, true_type,loc))!= null){
3244                                         type = true_type;
3245                                         falseExpr = conv;
3246                                 } else {
3247                                         Error (173, "The type of the conditional expression can " +
3248                                                "not be computed because there is no implicit conversion" +
3249                                                " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +
3250                                                " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");
3251                                         return null;
3252                                 }
3253                         }
3254
3255                         if (expr is BoolConstant){
3256                                 BoolConstant bc = (BoolConstant) expr;
3257
3258                                 if (bc.Value)
3259                                         return trueExpr;
3260                                 else
3261                                         return falseExpr;
3262                         }
3263
3264                         return this;
3265                 }
3266
3267                 public override void Emit (EmitContext ec)
3268                 {
3269                         ILGenerator ig = ec.ig;
3270                         Label false_target = ig.DefineLabel ();
3271                         Label end_target = ig.DefineLabel ();
3272
3273                         Statement.EmitBoolExpression (ec, expr, false_target, false);
3274                         trueExpr.Emit (ec);
3275                         ig.Emit (OpCodes.Br, end_target);
3276                         ig.MarkLabel (false_target);
3277                         falseExpr.Emit (ec);
3278                         ig.MarkLabel (end_target);
3279                 }
3280
3281         }
3282
3283         /// <summary>
3284         ///   Local variables
3285         /// </summary>
3286         public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3287                 public readonly string Name;
3288                 public readonly Block Block;
3289                 VariableInfo variable_info;
3290                 bool is_readonly;
3291                 
3292                 public LocalVariableReference (Block block, string name, Location l)
3293                 {
3294                         Block = block;
3295                         Name = name;
3296                         loc = l;
3297                         eclass = ExprClass.Variable;
3298                 }
3299
3300                 // Setting `is_readonly' to false will allow you to create a writable
3301                 // reference to a read-only variable.  This is used by foreach and using.
3302                 public LocalVariableReference (Block block, string name, Location l,
3303                                                VariableInfo variable_info, bool is_readonly)
3304                         : this (block, name, l)
3305                 {
3306                         this.variable_info = variable_info;
3307                         this.is_readonly = is_readonly;
3308                 }
3309
3310                 public VariableInfo VariableInfo {
3311                         get {
3312                                 if (variable_info == null) {
3313                                         variable_info = Block.GetVariableInfo (Name);
3314                                         is_readonly = variable_info.ReadOnly;
3315                                 }
3316                                 return variable_info;
3317                         }
3318                 }
3319
3320                 public bool IsAssigned (EmitContext ec, Location loc)
3321                 {
3322                         return VariableInfo.IsAssigned (ec, loc);
3323                 }
3324
3325                 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
3326                 {
3327                         return VariableInfo.IsFieldAssigned (ec, name, loc);
3328                 }
3329
3330                 public void SetAssigned (EmitContext ec)
3331                 {
3332                         VariableInfo.SetAssigned (ec);
3333                 }
3334
3335                 public void SetFieldAssigned (EmitContext ec, string name)
3336                 {
3337                         VariableInfo.SetFieldAssigned (ec, name);
3338                 }
3339
3340                 public bool IsReadOnly {
3341                         get {
3342                                 if (variable_info == null) {
3343                                         variable_info = Block.GetVariableInfo (Name);
3344                                         is_readonly = variable_info.ReadOnly;
3345                                 }
3346                                 return is_readonly;
3347                         }
3348                 }
3349                 
3350                 public override Expression DoResolve (EmitContext ec)
3351                 {
3352                         VariableInfo vi = VariableInfo;
3353                         Expression e;
3354                         
3355                         e = Block.GetConstantExpression (Name);
3356                         if (e != null) {
3357                                 vi.Used = true;
3358                                 type = vi.VariableType;
3359                                 eclass = ExprClass.Value;
3360                                 return e;
3361                         }
3362
3363                         if (ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3364                                 return null;
3365
3366                         type = vi.VariableType;
3367                         return this;
3368                 }
3369
3370                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3371                 {
3372                         VariableInfo vi = VariableInfo;
3373
3374                         if (ec.DoFlowAnalysis)
3375                                 ec.SetVariableAssigned (vi);
3376
3377                         Expression e = DoResolve (ec);
3378
3379                         if (e == null)
3380                                 return null;
3381
3382                         if (is_readonly){
3383                                 Error (1604, "cannot assign to `" + Name + "' because it is readonly");
3384                                 return null;
3385                         }
3386                         
3387                         return this;
3388                 }
3389
3390                 public override void Emit (EmitContext ec)
3391                 {
3392                         VariableInfo vi = VariableInfo;
3393                         ILGenerator ig = ec.ig;
3394
3395                         if (vi.LocalBuilder == null){
3396                                 ec.EmitThis ();
3397                                 ig.Emit (OpCodes.Ldfld, vi.FieldBuilder);
3398                         } else 
3399                                 ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
3400                         
3401                         vi.Used = true;
3402                 }
3403                 
3404                 public void EmitAssign (EmitContext ec, Expression source)
3405                 {
3406                         ILGenerator ig = ec.ig;
3407                         VariableInfo vi = VariableInfo;
3408
3409                         vi.Assigned = true;
3410
3411                         if (vi.LocalBuilder == null){
3412                                 ec.EmitThis ();
3413                                 source.Emit (ec);
3414                                 ig.Emit (OpCodes.Stfld, vi.FieldBuilder);
3415                         } else {
3416                                 source.Emit (ec);
3417                                 ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
3418                         }
3419                 }
3420                 
3421                 public void AddressOf (EmitContext ec, AddressOp mode)
3422                 {
3423                         VariableInfo vi = VariableInfo;
3424
3425                         if (vi.LocalBuilder == null){
3426                                 ec.EmitThis ();
3427                                 ec.ig.Emit (OpCodes.Ldflda, vi.FieldBuilder);
3428                         } else
3429                                 ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);
3430                 }
3431         }
3432
3433         /// <summary>
3434         ///   This represents a reference to a parameter in the intermediate
3435         ///   representation.
3436         /// </summary>
3437         public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3438                 Parameters pars;
3439                 String name;
3440                 int idx;
3441                 public Parameter.Modifier mod;
3442                 public bool is_ref, is_out;
3443                 
3444                 public ParameterReference (Parameters pars, int idx, string name, Location loc)
3445                 {
3446                         this.pars = pars;
3447                         this.idx  = idx;
3448                         this.name = name;
3449                         this.loc = loc;
3450                         eclass = ExprClass.Variable;
3451                 }
3452
3453                 public bool IsAssigned (EmitContext ec, Location loc)
3454                 {
3455                         if (!is_out || !ec.DoFlowAnalysis)
3456                                 return true;
3457
3458                         if (!ec.CurrentBranching.IsParameterAssigned (idx)) {
3459                                 Report.Error (165, loc,
3460                                               "Use of unassigned local variable `" + name + "'");
3461                                 return false;
3462                         }
3463
3464                         return true;
3465                 }
3466
3467                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3468                 {
3469                         if (!is_out || !ec.DoFlowAnalysis)
3470                                 return true;
3471
3472                         if (ec.CurrentBranching.IsParameterAssigned (idx))
3473                                 return true;
3474
3475                         if (!ec.CurrentBranching.IsParameterAssigned (idx, field_name)) {
3476                                 Report.Error (170, loc,
3477                                               "Use of possibly unassigned field `" + field_name + "'");
3478                                 return false;
3479                         }
3480
3481                         return true;
3482                 }
3483
3484                 public void SetAssigned (EmitContext ec)
3485                 {
3486                         if (is_out && ec.DoFlowAnalysis)
3487                                 ec.CurrentBranching.SetParameterAssigned (idx);
3488                 }
3489
3490                 public void SetFieldAssigned (EmitContext ec, string field_name)
3491                 {
3492                         if (is_out && ec.DoFlowAnalysis)
3493                                 ec.CurrentBranching.SetParameterAssigned (idx, field_name);
3494                 }
3495
3496                 //
3497                 // Notice that for ref/out parameters, the type exposed is not the
3498                 // same type exposed externally.
3499                 //
3500                 // for "ref int a":
3501                 //   externally we expose "int&"
3502                 //   here we expose       "int".
3503                 //
3504                 // We record this in "is_ref".  This means that the type system can treat
3505                 // the type as it is expected, but when we generate the code, we generate
3506                 // the alternate kind of code.
3507                 //
3508                 public override Expression DoResolve (EmitContext ec)
3509                 {
3510                         type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
3511                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3512                         is_out = (mod & Parameter.Modifier.OUT) != 0;
3513                         eclass = ExprClass.Variable;
3514
3515                         if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3516                                 return null;
3517
3518                         return this;
3519                 }
3520
3521                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3522                 {
3523                         type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
3524                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3525                         is_out = (mod & Parameter.Modifier.OUT) != 0;
3526                         eclass = ExprClass.Variable;
3527
3528                         if (is_out && ec.DoFlowAnalysis)
3529                                 ec.SetParameterAssigned (idx);
3530
3531                         return this;
3532                 }
3533
3534                 static public void EmitLdArg (ILGenerator ig, int x)
3535                 {
3536                         if (x <= 255){
3537                                 switch (x){
3538                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3539                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3540                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3541                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3542                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3543                                 }
3544                         } else
3545                                 ig.Emit (OpCodes.Ldarg, x);
3546                 }
3547                 
3548                 //
3549                 // This method is used by parameters that are references, that are
3550                 // being passed as references:  we only want to pass the pointer (that
3551                 // is already stored in the parameter, not the address of the pointer,
3552                 // and not the value of the variable).
3553                 //
3554                 public void EmitLoad (EmitContext ec)
3555                 {
3556                         ILGenerator ig = ec.ig;
3557                         int arg_idx = idx;
3558
3559                         if (!ec.IsStatic)
3560                                 arg_idx++;
3561
3562                         EmitLdArg (ig, arg_idx);
3563                 }
3564                 
3565                 public override void Emit (EmitContext ec)
3566                 {
3567                         ILGenerator ig = ec.ig;
3568                         
3569                         if (ec.RemapToProxy){
3570                                 ig.Emit (OpCodes.Ldarg_0);
3571                                 ec.EmitArgument (idx);
3572                                 return;
3573                         }
3574                         
3575                         int arg_idx = idx;
3576
3577                         if (!ec.IsStatic)
3578                                 arg_idx++;
3579
3580                         EmitLdArg (ig, arg_idx);
3581
3582                         if (!is_ref)
3583                                 return;
3584
3585                         //
3586                         // If we are a reference, we loaded on the stack a pointer
3587                         // Now lets load the real value
3588                         //
3589                         LoadFromPtr (ig, type);
3590                 }
3591
3592                 public void EmitAssign (EmitContext ec, Expression source)
3593                 {
3594                         ILGenerator ig = ec.ig;
3595                         
3596                         if (ec.RemapToProxy){
3597                                 ig.Emit (OpCodes.Ldarg_0);
3598                                 source.Emit (ec);
3599                                 ec.EmitStoreArgument (idx);
3600                                 return;
3601                         }
3602                         
3603                         int arg_idx = idx;
3604
3605                         if (!ec.IsStatic)
3606                                 arg_idx++;
3607
3608                         if (is_ref)
3609                                 EmitLdArg (ig, arg_idx);
3610                         
3611                         source.Emit (ec);
3612
3613                         if (is_ref)
3614                                 StoreFromPtr (ig, type);
3615                         else {
3616                                 if (arg_idx <= 255)
3617                                         ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
3618                                 else
3619                                         ig.Emit (OpCodes.Starg, arg_idx);
3620                         }
3621                 }
3622
3623                 public void AddressOf (EmitContext ec, AddressOp mode)
3624                 {
3625                         if (ec.RemapToProxy){
3626                                 Report.Error (-1, "Report this: Taking the address of a remapped parameter not supported");
3627                                 return;
3628                         }
3629                         
3630                         int arg_idx = idx;
3631
3632                         if (!ec.IsStatic)
3633                                 arg_idx++;
3634
3635                         if (is_ref){
3636                                 if (arg_idx <= 255)
3637                                         ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
3638                                 else
3639                                         ec.ig.Emit (OpCodes.Ldarg, arg_idx);
3640                         } else {
3641                                 if (arg_idx <= 255)
3642                                         ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
3643                                 else
3644                                         ec.ig.Emit (OpCodes.Ldarga, arg_idx);
3645                         }
3646                 }
3647
3648         }
3649         
3650         /// <summary>
3651         ///   Used for arguments to New(), Invocation()
3652         /// </summary>
3653         public class Argument {
3654                 public enum AType : byte {
3655                         Expression,
3656                         Ref,
3657                         Out
3658                 };
3659
3660                 public readonly AType ArgType;
3661                 public Expression Expr;
3662                 
3663                 public Argument (Expression expr, AType type)
3664                 {
3665                         this.Expr = expr;
3666                         this.ArgType = type;
3667                 }
3668
3669                 public Type Type {
3670                         get {
3671                                 if (ArgType == AType.Ref || ArgType == AType.Out)
3672                                         return TypeManager.GetReferenceType (Expr.Type);
3673                                 else
3674                                         return Expr.Type;
3675                         }
3676                 }
3677
3678                 public Parameter.Modifier GetParameterModifier ()
3679                 {
3680                         switch (ArgType) {
3681                         case AType.Out:
3682                                 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
3683
3684                         case AType.Ref:
3685                                 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
3686
3687                         default:
3688                                 return Parameter.Modifier.NONE;
3689                         }
3690                 }
3691
3692                 public static string FullDesc (Argument a)
3693                 {
3694                         return (a.ArgType == AType.Ref ? "ref " :
3695                                 (a.ArgType == AType.Out ? "out " : "")) +
3696                                 TypeManager.CSharpName (a.Expr.Type);
3697                 }
3698
3699                 public bool ResolveMethodGroup (EmitContext ec, Location loc)
3700                 {
3701                         // FIXME: csc doesn't report any error if you try to use `ref' or
3702                         //        `out' in a delegate creation expression.
3703                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3704                         if (Expr == null)
3705                                 return false;
3706
3707                         return true;
3708                 }
3709                 
3710                 public bool Resolve (EmitContext ec, Location loc)
3711                 {
3712                         if (ArgType == AType.Ref) {
3713                                 Expr = Expr.Resolve (ec);
3714                                 if (Expr == null)
3715                                         return false;
3716
3717                                 Expr = Expr.ResolveLValue (ec, Expr);
3718                         } else if (ArgType == AType.Out)
3719                                 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
3720                         else
3721                                 Expr = Expr.Resolve (ec);
3722
3723                         if (Expr == null)
3724                                 return false;
3725
3726                         if (ArgType == AType.Expression)
3727                                 return true;
3728
3729                         if (Expr.eclass != ExprClass.Variable){
3730                                 //
3731                                 // We just probe to match the CSC output
3732                                 //
3733                                 if (Expr.eclass == ExprClass.PropertyAccess ||
3734                                     Expr.eclass == ExprClass.IndexerAccess){
3735                                         Report.Error (
3736                                                 206, loc,
3737                                                 "A property or indexer can not be passed as an out or ref " +
3738                                                 "parameter");
3739                                 } else {
3740                                         Report.Error (
3741                                                 1510, loc,
3742                                                 "An lvalue is required as an argument to out or ref");
3743                                 }
3744                                 return false;
3745                         }
3746                                 
3747                         return true;
3748                 }
3749
3750                 public void Emit (EmitContext ec)
3751                 {
3752                         //
3753                         // Ref and Out parameters need to have their addresses taken.
3754                         //
3755                         // ParameterReferences might already be references, so we want
3756                         // to pass just the value
3757                         //
3758                         if (ArgType == AType.Ref || ArgType == AType.Out){
3759                                 AddressOp mode = AddressOp.Store;
3760
3761                                 if (ArgType == AType.Ref)
3762                                         mode |= AddressOp.Load;
3763                                 
3764                                 if (Expr is ParameterReference){
3765                                         ParameterReference pr = (ParameterReference) Expr;
3766
3767                                         if (pr.is_ref)
3768                                                 pr.EmitLoad (ec);
3769                                         else {
3770                                                 
3771                                                 pr.AddressOf (ec, mode);
3772                                         }
3773                                 } else
3774                                         ((IMemoryLocation)Expr).AddressOf (ec, mode);
3775                         } else
3776                                 Expr.Emit (ec);
3777                 }
3778         }
3779
3780         /// <summary>
3781         ///   Invocation of methods or delegates.
3782         /// </summary>
3783         public class Invocation : ExpressionStatement {
3784                 public readonly ArrayList Arguments;
3785
3786                 Expression expr;
3787                 MethodBase method = null;
3788                 bool is_base;
3789                 
3790                 static Hashtable method_parameter_cache;
3791
3792                 static Invocation ()
3793                 {
3794                         method_parameter_cache = new PtrHashtable ();
3795                 }
3796                         
3797                 //
3798                 // arguments is an ArrayList, but we do not want to typecast,
3799                 // as it might be null.
3800                 //
3801                 // FIXME: only allow expr to be a method invocation or a
3802                 // delegate invocation (7.5.5)
3803                 //
3804                 public Invocation (Expression expr, ArrayList arguments, Location l)
3805                 {
3806                         this.expr = expr;
3807                         Arguments = arguments;
3808                         loc = l;
3809                 }
3810
3811                 public Expression Expr {
3812                         get {
3813                                 return expr;
3814                         }
3815                 }
3816
3817                 /// <summary>
3818                 ///   Returns the Parameters (a ParameterData interface) for the
3819                 ///   Method `mb'
3820                 /// </summary>
3821                 public static ParameterData GetParameterData (MethodBase mb)
3822                 {
3823                         object pd = method_parameter_cache [mb];
3824                         object ip;
3825                         
3826                         if (pd != null)
3827                                 return (ParameterData) pd;
3828
3829                         
3830                         ip = TypeManager.LookupParametersByBuilder (mb);
3831                         if (ip != null){
3832                                 method_parameter_cache [mb] = ip;
3833
3834                                 return (ParameterData) ip;
3835                         } else {
3836                                 ParameterInfo [] pi = mb.GetParameters ();
3837                                 ReflectionParameters rp = new ReflectionParameters (pi);
3838                                 method_parameter_cache [mb] = rp;
3839
3840                                 return (ParameterData) rp;
3841                         }
3842                 }
3843
3844                 /// <summary>
3845                 ///  Determines "better conversion" as specified in 7.4.2.3
3846                 ///  Returns : 1 if a->p is better
3847                 ///            0 if a->q or neither is better 
3848                 /// </summary>
3849                 static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
3850                 {
3851                         Type argument_type = a.Type;
3852                         Expression argument_expr = a.Expr;
3853
3854                         if (argument_type == null)
3855                                 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
3856
3857                         //
3858                         // This is a special case since csc behaves this way. I can't find
3859                         // it anywhere in the spec but oh well ...
3860                         //
3861                         if (argument_expr is NullLiteral && p == TypeManager.string_type && q == TypeManager.object_type)
3862                                 return 1;
3863                         else if (argument_expr is NullLiteral && p == TypeManager.object_type && q == TypeManager.string_type)
3864                                 return 0;
3865                         
3866                         if (p == q)
3867                                 return 0;
3868                         
3869                         if (argument_type == p)
3870                                 return 1;
3871
3872                         if (argument_type == q)
3873                                 return 0;
3874
3875                         //
3876                         // Now probe whether an implicit constant expression conversion
3877                         // can be used.
3878                         //
3879                         // An implicit constant expression conversion permits the following
3880                         // conversions:
3881                         //
3882                         //    * A constant-expression of type `int' can be converted to type
3883                         //      sbyte, byute, short, ushort, uint, ulong provided the value of
3884                         //      of the expression is withing the range of the destination type.
3885                         //
3886                         //    * A constant-expression of type long can be converted to type
3887                         //      ulong, provided the value of the constant expression is not negative
3888                         //
3889                         // FIXME: Note that this assumes that constant folding has
3890                         // taken place.  We dont do constant folding yet.
3891                         //
3892
3893                         if (argument_expr is IntConstant){
3894                                 IntConstant ei = (IntConstant) argument_expr;
3895                                 int value = ei.Value;
3896
3897                                 if (p == TypeManager.sbyte_type){
3898                                         if (value >= SByte.MinValue && value <= SByte.MaxValue)
3899                                                 return 1;
3900                                 } else if (p == TypeManager.byte_type){
3901                                         if (q == TypeManager.sbyte_type &&
3902                                             value >= SByte.MinValue && value <= SByte.MaxValue)
3903                                                 return 0;
3904                                         else if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
3905                                                 return 1;
3906                                 } else if (p == TypeManager.short_type){
3907                                         if (value >= Int16.MinValue && value <= Int16.MaxValue)
3908                                                 return 1;
3909                                 } else if (p == TypeManager.ushort_type){
3910                                         if (q == TypeManager.short_type &&
3911                                             value >= Int16.MinValue && value <= Int16.MaxValue)
3912                                                 return 0;
3913                                         else if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
3914                                                 return 1;
3915                                 } else if (p == TypeManager.int32_type){
3916                                         if (value >= Int32.MinValue && value <= Int32.MaxValue)
3917                                                 return 1;
3918                                 } else if (p == TypeManager.uint32_type){
3919                                         //
3920                                         // we can optimize this case: a positive int32
3921                                         // always fits on a uint32
3922                                         //
3923                                         if (value >= 0)
3924                                                 return 1;
3925                                 } else if (p == TypeManager.uint64_type){
3926                                         //
3927                                         // we can optimize this case: a positive int32
3928                                         // always fits on a uint64
3929                                         //
3930                                         if (q == TypeManager.int64_type)
3931                                                 return 0;
3932                                         else if (value >= 0)
3933                                                 return 1;
3934                                 } else if (p == TypeManager.int64_type){
3935                                         return 1;
3936                                 }
3937                         } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
3938                                 LongConstant lc = (LongConstant) argument_expr;
3939                                 
3940                                 if (p == TypeManager.uint64_type){
3941                                         if (lc.Value > 0)
3942                                                 return 1;
3943                                 }
3944                         }
3945
3946                         if (q == null) {
3947                                 Expression tmp = ConvertImplicit (ec, argument_expr, p, loc);
3948                                 
3949                                 if (tmp != null)
3950                                         return 1;
3951                                 else
3952                                         return 0;
3953                         }
3954
3955                         Expression p_tmp = new EmptyExpression (p);
3956                         Expression q_tmp = new EmptyExpression (q);
3957                         
3958                         if (ImplicitConversionExists (ec, p_tmp, q) == true &&
3959                             ImplicitConversionExists (ec, q_tmp, p) == false)
3960                                 return 1;
3961
3962                         if (p == TypeManager.sbyte_type)
3963                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
3964                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3965                                         return 1;
3966
3967                         if (p == TypeManager.short_type)
3968                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
3969                                     q == TypeManager.uint64_type)
3970                                         return 1;
3971
3972                         if (p == TypeManager.int32_type)
3973                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
3974                                         return 1;
3975
3976                         if (p == TypeManager.int64_type)
3977                                 if (q == TypeManager.uint64_type)
3978                                         return 1;
3979
3980                         return 0;
3981                 }
3982                 
3983                 /// <summary>
3984                 ///  Determines "Better function"
3985                 /// </summary>
3986                 /// <remarks>
3987                 ///    and returns an integer indicating :
3988                 ///    0 if candidate ain't better
3989                 ///    1 if candidate is better than the current best match
3990                 /// </remarks>
3991                 static int BetterFunction (EmitContext ec, ArrayList args,
3992                                            MethodBase candidate, MethodBase best,
3993                                            bool expanded_form, Location loc)
3994                 {
3995                         ParameterData candidate_pd = GetParameterData (candidate);
3996                         ParameterData best_pd;
3997                         int argument_count;
3998                 
3999                         if (args == null)
4000                                 argument_count = 0;
4001                         else
4002                                 argument_count = args.Count;
4003
4004                         int cand_count = candidate_pd.Count;
4005
4006                         if (cand_count == 0 && argument_count == 0)
4007                                 return 1;
4008
4009                         if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
4010                                 if (cand_count != argument_count)
4011                                         return 0;
4012                         
4013                         if (best == null) {
4014                                 int x = 0;
4015
4016                                 if (argument_count == 0 && cand_count == 1 &&
4017                                     candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
4018                                         return 1;
4019                                 
4020                                 for (int j = argument_count; j > 0;) {
4021                                         j--;
4022
4023                                         Argument a = (Argument) args [j];
4024                                         Type t = candidate_pd.ParameterType (j);
4025
4026                                         if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4027                                                 if (expanded_form)
4028                                                         t = t.GetElementType ();
4029
4030                                         x = BetterConversion (ec, a, t, null, loc);
4031                                         
4032                                         if (x <= 0)
4033                                                 break;
4034                                 }
4035
4036                                 if (x > 0)
4037                                         return 1;
4038                                 else
4039                                         return 0;
4040                         }
4041
4042                         best_pd = GetParameterData (best);
4043
4044                         int rating1 = 0, rating2 = 0;
4045                         
4046                         for (int j = 0; j < argument_count; ++j) {
4047                                 int x, y;
4048                                 
4049                                 Argument a = (Argument) args [j];
4050
4051                                 Type ct = candidate_pd.ParameterType (j);
4052                                 Type bt = best_pd.ParameterType (j);
4053
4054                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4055                                         if (expanded_form)
4056                                                 ct = ct.GetElementType ();
4057
4058                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4059                                         if (expanded_form)
4060                                                 bt = bt.GetElementType ();
4061                                 
4062                                 x = BetterConversion (ec, a, ct, bt, loc);
4063                                 y = BetterConversion (ec, a, bt, ct, loc);
4064
4065                                 if (x < y)
4066                                         return 0;
4067                                 
4068                                 rating1 += x;
4069                                 rating2 += y;
4070                         }
4071
4072                         if (rating1 > rating2)
4073                                 return 1;
4074                         else
4075                                 return 0;
4076                 }
4077
4078                 public static string FullMethodDesc (MethodBase mb)
4079                 {
4080                         string ret_type = "";
4081
4082                         if (mb is MethodInfo)
4083                                 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
4084                         
4085                         StringBuilder sb = new StringBuilder (ret_type);
4086                         sb.Append (" ");
4087                         sb.Append (mb.ReflectedType.ToString ());
4088                         sb.Append (".");
4089                         sb.Append (mb.Name);
4090                         
4091                         ParameterData pd = GetParameterData (mb);
4092
4093                         int count = pd.Count;
4094                         sb.Append (" (");
4095                         
4096                         for (int i = count; i > 0; ) {
4097                                 i--;
4098
4099                                 sb.Append (pd.ParameterDesc (count - i - 1));
4100                                 if (i != 0)
4101                                         sb.Append (", ");
4102                         }
4103                         
4104                         sb.Append (")");
4105                         return sb.ToString ();
4106                 }
4107
4108                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4109                 {
4110                         MemberInfo [] miset;
4111                         MethodGroupExpr union;
4112
4113                         if (mg1 == null){
4114                                 if (mg2 == null)
4115                                         return null;
4116                                 return (MethodGroupExpr) mg2;
4117                         } else {
4118                                 if (mg2 == null)
4119                                         return (MethodGroupExpr) mg1;
4120                         }
4121                         
4122                         MethodGroupExpr left_set = null, right_set = null;
4123                         int length1 = 0, length2 = 0;
4124                         
4125                         left_set = (MethodGroupExpr) mg1;
4126                         length1 = left_set.Methods.Length;
4127                         
4128                         right_set = (MethodGroupExpr) mg2;
4129                         length2 = right_set.Methods.Length;
4130                         
4131                         ArrayList common = new ArrayList ();
4132
4133                         foreach (MethodBase l in left_set.Methods){
4134                                 foreach (MethodBase r in right_set.Methods){
4135                                         if (l != r)
4136                                                 continue;
4137                                         common.Add (r);
4138                                         break;
4139                                 }
4140                         }
4141                         
4142                         miset = new MemberInfo [length1 + length2 - common.Count];
4143                         left_set.Methods.CopyTo (miset, 0);
4144                         
4145                         int k = length1;
4146
4147                         foreach (MemberInfo mi in right_set.Methods){
4148                                 if (!common.Contains (mi))
4149                                         miset [k++] = mi;
4150                         }
4151                         
4152                         union = new MethodGroupExpr (miset, loc);
4153                         
4154                         return union;
4155                 }
4156
4157                 /// <summary>
4158                 ///  Determines is the candidate method, if a params method, is applicable
4159                 ///  in its expanded form to the given set of arguments
4160                 /// </summary>
4161                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
4162                 {
4163                         int arg_count;
4164                         
4165                         if (arguments == null)
4166                                 arg_count = 0;
4167                         else
4168                                 arg_count = arguments.Count;
4169                         
4170                         ParameterData pd = GetParameterData (candidate);
4171                         
4172                         int pd_count = pd.Count;
4173
4174                         if (pd_count == 0)
4175                                 return false;
4176                         
4177                         if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
4178                                 return false;
4179                         
4180                         if (pd_count - 1 > arg_count)
4181                                 return false;
4182                         
4183                         if (pd_count == 1 && arg_count == 0)
4184                                 return true;
4185
4186                         //
4187                         // If we have come this far, the case which remains is when the number of parameters
4188                         // is less than or equal to the argument count.
4189                         //
4190                         for (int i = 0; i < pd_count - 1; ++i) {
4191
4192                                 Argument a = (Argument) arguments [i];
4193
4194                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4195                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4196                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4197                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4198
4199                                 if (a_mod == p_mod) {
4200
4201                                         if (a_mod == Parameter.Modifier.NONE)
4202                                                 if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
4203                                                         return false;
4204                                                                                 
4205                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4206                                                 Type pt = pd.ParameterType (i);
4207
4208                                                 if (!pt.IsByRef)
4209                                                         pt = TypeManager.GetReferenceType (pt);
4210                                                 
4211                                                 if (pt != a.Type)
4212                                                         return false;
4213                                         }
4214                                 } else
4215                                         return false;
4216                                 
4217                         }
4218
4219                         Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
4220
4221                         for (int i = pd_count - 1; i < arg_count; i++) {
4222                                 Argument a = (Argument) arguments [i];
4223                                 
4224                                 if (!StandardConversionExists (a.Expr, element_type))
4225                                         return false;
4226                         }
4227                         
4228                         return true;
4229                 }
4230
4231                 /// <summary>
4232                 ///  Determines if the candidate method is applicable (section 14.4.2.1)
4233                 ///  to the given set of arguments
4234                 /// </summary>
4235                 static bool IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
4236                 {
4237                         int arg_count;
4238
4239                         if (arguments == null)
4240                                 arg_count = 0;
4241                         else
4242                                 arg_count = arguments.Count;
4243
4244                         ParameterData pd = GetParameterData (candidate);
4245
4246                         int pd_count = pd.Count;
4247
4248                         if (arg_count != pd.Count)
4249                                 return false;
4250                         
4251                         for (int i = arg_count; i > 0; ) {
4252                                 i--;
4253
4254                                 Argument a = (Argument) arguments [i];
4255
4256                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4257                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4258                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4259                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4260
4261                                 if (a_mod == p_mod ||
4262                                     (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
4263                                         if (a_mod == Parameter.Modifier.NONE)
4264                                                 if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
4265                                                         return false;
4266                                         
4267                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4268                                                 Type pt = pd.ParameterType (i);
4269
4270                                                 if (!pt.IsByRef)
4271                                                         pt = TypeManager.GetReferenceType (pt);
4272
4273                                                 if (pt != a.Type)
4274                                                         return false;
4275                                         }
4276                                 } else
4277                                         return false;
4278                         }
4279
4280                         return true;
4281                 }
4282                 
4283                 
4284
4285                 /// <summary>
4286                 ///   Find the Applicable Function Members (7.4.2.1)
4287                 ///
4288                 ///   me: Method Group expression with the members to select.
4289                 ///       it might contain constructors or methods (or anything
4290                 ///       that maps to a method).
4291                 ///
4292                 ///   Arguments: ArrayList containing resolved Argument objects.
4293                 ///
4294                 ///   loc: The location if we want an error to be reported, or a Null
4295                 ///        location for "probing" purposes.
4296                 ///
4297                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4298                 ///            that is the best match of me on Arguments.
4299                 ///
4300                 /// </summary>
4301                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4302                                                           ArrayList Arguments, Location loc)
4303                 {
4304                         MethodBase method = null;
4305                         Type current_type = null;
4306                         int argument_count;
4307                         ArrayList candidates = new ArrayList ();
4308                         
4309
4310                         foreach (MethodBase candidate in me.Methods){
4311                                 int x;
4312
4313                                 // If we're going one level higher in the class hierarchy, abort if
4314                                 // we already found an applicable method.
4315                                 if (candidate.DeclaringType != current_type) {
4316                                         current_type = candidate.DeclaringType;
4317                                         if (method != null)
4318                                                 break;
4319                                 }
4320
4321                                 // Check if candidate is applicable (section 14.4.2.1)
4322                                 if (!IsApplicable (ec, Arguments, candidate))
4323                                         continue;
4324
4325                                 candidates.Add (candidate);
4326                                 x = BetterFunction (ec, Arguments, candidate, method, false, loc);
4327                                 
4328                                 if (x == 0)
4329                                         continue;
4330
4331                                 method = candidate;
4332                         }
4333
4334                         if (Arguments == null)
4335                                 argument_count = 0;
4336                         else
4337                                 argument_count = Arguments.Count;
4338                         
4339                         //
4340                         // Now we see if we can find params functions, applicable in their expanded form
4341                         // since if they were applicable in their normal form, they would have been selected
4342                         // above anyways
4343                         //
4344                         bool chose_params_expanded = false;
4345                         
4346                         if (method == null) {
4347                                 candidates = new ArrayList ();
4348                                 foreach (MethodBase candidate in me.Methods){
4349                                         if (!IsParamsMethodApplicable (ec, Arguments, candidate))
4350                                                 continue;
4351
4352                                         candidates.Add (candidate);
4353
4354                                         int x = BetterFunction (ec, Arguments, candidate, method, true, loc);
4355                                         if (x == 0)
4356                                                 continue;
4357
4358                                         method = candidate; 
4359                                         chose_params_expanded = true;
4360                                 }
4361                         }
4362
4363                         if (method == null) {
4364                                 //
4365                                 // Okay so we have failed to find anything so we
4366                                 // return by providing info about the closest match
4367                                 //
4368                                 for (int i = 0; i < me.Methods.Length; ++i) {
4369
4370                                         MethodBase c = (MethodBase) me.Methods [i];
4371                                         ParameterData pd = GetParameterData (c);
4372
4373                                         if (pd.Count != argument_count)
4374                                                 continue;
4375
4376                                         VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
4377                                                                null, loc);
4378                                 }
4379                                 
4380                                 return null;
4381                         }
4382
4383                         //
4384                         // Now check that there are no ambiguities i.e the selected method
4385                         // should be better than all the others
4386                         //
4387
4388                         foreach (MethodBase candidate in candidates){
4389                                 if (candidate == method)
4390                                         continue;
4391
4392                                 //
4393                                 // If a normal method is applicable in the sense that it has the same
4394                                 // number of arguments, then the expanded params method is never applicable
4395                                 // so we debar the params method.
4396                                 //
4397                                 if (IsParamsMethodApplicable (ec, Arguments, candidate) &&
4398                                     IsApplicable (ec, Arguments, method))
4399                                         continue;
4400                                         
4401                                 int x = BetterFunction (ec, Arguments, method, candidate,
4402                                                         chose_params_expanded, loc);
4403
4404                                 if (x != 1) {
4405                                         Report.Error (
4406                                                 121, loc,
4407                                                 "Ambiguous call when selecting function due to implicit casts");
4408                                         return null;
4409                                 }
4410                         }
4411
4412                         //
4413                         // And now check if the arguments are all compatible, perform conversions
4414                         // if necessary etc. and return if everything is all right
4415                         //
4416
4417                         if (!VerifyArgumentsCompat (ec, Arguments, argument_count, method,
4418                                                    chose_params_expanded, null, loc))
4419                                 return null;
4420
4421                         return method;
4422                 }
4423
4424                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method, Type delegate_type, string arg_sig, string par_desc)
4425                 {
4426                         if (delegate_type == null) 
4427                                 Report.Error (1502, loc,
4428                                               "The best overloaded match for method '" +
4429                                               FullMethodDesc (method) +
4430                                               "' has some invalid arguments");
4431                         else
4432                                 Report.Error (1594, loc,
4433                                               "Delegate '" + delegate_type.ToString () +
4434                                               "' has some invalid arguments.");
4435                         Report.Error (1503, loc,
4436                                       String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
4437                                                      idx, arg_sig, par_desc));
4438                 }
4439                 
4440                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4441                                                           int argument_count,
4442                                                           MethodBase method, 
4443                                                           bool chose_params_expanded,
4444                                                           Type delegate_type,
4445                                                           Location loc)
4446                 {
4447                         ParameterData pd = GetParameterData (method);
4448                         int pd_count = pd.Count;
4449                         
4450                         for (int j = 0; j < argument_count; j++) {
4451                                 Argument a = (Argument) Arguments [j];
4452                                 Expression a_expr = a.Expr;
4453                                 Type parameter_type = pd.ParameterType (j);
4454                                 Parameter.Modifier pm = pd.ParameterModifier (j);
4455                                 
4456                                 if (pm == Parameter.Modifier.PARAMS){
4457                                         if (chose_params_expanded)
4458                                                 parameter_type = TypeManager.TypeToCoreType (parameter_type.GetElementType ());
4459                                 } else {
4460                                         //
4461                                         // Check modifiers
4462                                         //
4463                                         if (pd.ParameterModifier (j) != a.GetParameterModifier ()){
4464                                                 if (!Location.IsNull (loc))
4465                                                         Error_InvalidArguments (
4466                                                                 loc, j, method, delegate_type,
4467                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4468                                                 return false;
4469                                         }
4470                                 }
4471
4472                                 //
4473                                 // Check Type
4474                                 //
4475                                 if (a.Type != parameter_type){
4476                                         Expression conv;
4477                                         
4478                                         conv = ConvertImplicit (ec, a_expr, parameter_type, loc);
4479
4480                                         if (conv == null) {
4481                                                 if (!Location.IsNull (loc)) 
4482                                                         Error_InvalidArguments (
4483                                                                 loc, j, method, delegate_type,
4484                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4485                                                 return false;
4486                                         }
4487                                         
4488                                         //
4489                                         // Update the argument with the implicit conversion
4490                                         //
4491                                         if (a_expr != conv)
4492                                                 a.Expr = conv;
4493                                 }
4494
4495                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4496                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4497                                 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
4498                                         ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
4499
4500                                 
4501                                 if (a_mod != p_mod &&
4502                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
4503                                         if (!Location.IsNull (loc)) {
4504                                                 Console.WriteLine ("A:P: " + a.GetParameterModifier ());
4505                                                 Console.WriteLine ("PP:: " + pd.ParameterModifier (j));
4506                                                 Console.WriteLine ("PT:  " + parameter_type.IsByRef);
4507                                                 Report.Error (1502, loc,
4508                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
4509                                                        "' has some invalid arguments");
4510                                                 Report.Error (1503, loc,
4511                                                        "Argument " + (j+1) +
4512                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
4513                                                        + "' to '" + pd.ParameterDesc (j) + "'");
4514                                         }
4515                                         
4516                                         return false;
4517                                 }
4518                         }
4519
4520                         return true;
4521                 }
4522
4523                 public override Expression DoResolve (EmitContext ec)
4524                 {
4525                         //
4526                         // First, resolve the expression that is used to
4527                         // trigger the invocation
4528                         //
4529                         if (expr is BaseAccess)
4530                                 is_base = true;
4531
4532                         Expression old = expr;
4533                         
4534                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4535                         if (expr == null)
4536                                 return null;
4537
4538                         if (!(expr is MethodGroupExpr)) {
4539                                 Type expr_type = expr.Type;
4540
4541                                 if (expr_type != null){
4542                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
4543                                         if (IsDelegate)
4544                                                 return (new DelegateInvocation (
4545                                                         this.expr, Arguments, loc)).Resolve (ec);
4546                                 }
4547                         }
4548
4549                         if (!(expr is MethodGroupExpr)){
4550                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup);
4551                                 return null;
4552                         }
4553
4554                         //
4555                         // Next, evaluate all the expressions in the argument list
4556                         //
4557                         if (Arguments != null){
4558                                 foreach (Argument a in Arguments){
4559                                         if (!a.Resolve (ec, loc))
4560                                                 return null;
4561                                 }
4562                         }
4563
4564                         MethodGroupExpr mg = (MethodGroupExpr) expr;
4565                         method = OverloadResolve (ec, mg, Arguments, loc);
4566
4567                         if (method == null){
4568                                 Error (-6,
4569                                        "Could not find any applicable function for this argument list");
4570                                 return null;
4571                         }
4572
4573                         MethodInfo mi = method as MethodInfo;
4574                         if (mi != null) {
4575                                 type = TypeManager.TypeToCoreType (mi.ReturnType);
4576                                 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
4577                                         SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
4578                         }
4579
4580                         if (type.IsPointer){
4581                                 if (!ec.InUnsafe){
4582                                         UnsafeError (loc);
4583                                         return null;
4584                                 }
4585                         }
4586                         
4587                         //
4588                         // Only base will allow this invocation to happen.
4589                         //
4590                         if (is_base && method.IsAbstract){
4591                                 Report.Error (205, loc, "Cannot call an abstract base member: " +
4592                                               FullMethodDesc (method));
4593                                 return null;
4594                         }
4595
4596                         if ((method.Attributes & MethodAttributes.SpecialName) != 0){
4597                                 if (TypeManager.IsSpecialMethod (method))
4598                                         Report.Error (571, loc, method.Name + ": can not call operator or accessor");
4599                         }
4600                         
4601                         eclass = ExprClass.Value;
4602                         return this;
4603                 }
4604
4605                 // <summary>
4606                 //   Emits the list of arguments as an array
4607                 // </summary>
4608                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
4609                 {
4610                         ILGenerator ig = ec.ig;
4611                         int count = arguments.Count - idx;
4612                         Argument a = (Argument) arguments [idx];
4613                         Type t = a.Expr.Type;
4614                         string array_type = t.FullName + "[]";
4615                         LocalBuilder array;
4616
4617                         array = ig.DeclareLocal (TypeManager.LookupType (array_type));
4618                         IntConstant.EmitInt (ig, count);
4619                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4620                         ig.Emit (OpCodes.Stloc, array);
4621
4622                         int top = arguments.Count;
4623                         for (int j = idx; j < top; j++){
4624                                 a = (Argument) arguments [j];
4625                                 
4626                                 ig.Emit (OpCodes.Ldloc, array);
4627                                 IntConstant.EmitInt (ig, j - idx);
4628
4629                                 bool is_stobj;
4630                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj);
4631                                 if (is_stobj)
4632                                         ig.Emit (OpCodes.Ldelema, t);
4633
4634                                 a.Emit (ec);
4635
4636                                 if (is_stobj)
4637                                         ig.Emit (OpCodes.Stobj, t);
4638                                 else
4639                                         ig.Emit (op);
4640                         }
4641                         ig.Emit (OpCodes.Ldloc, array);
4642                 }
4643                 
4644                 /// <summary>
4645                 ///   Emits a list of resolved Arguments that are in the arguments
4646                 ///   ArrayList.
4647                 /// 
4648                 ///   The MethodBase argument might be null if the
4649                 ///   emission of the arguments is known not to contain
4650                 ///   a `params' field (for example in constructors or other routines
4651                 ///   that keep their arguments in this structure)
4652                 /// </summary>
4653                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
4654                 {
4655                         ParameterData pd;
4656                         if (mb != null)
4657                                 pd = GetParameterData (mb);
4658                         else
4659                                 pd = null;
4660
4661                         //
4662                         // If we are calling a params method with no arguments, special case it
4663                         //
4664                         if (arguments == null){
4665                                 if (pd != null && pd.Count > 0 &&
4666                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
4667                                         ILGenerator ig = ec.ig;
4668
4669                                         IntConstant.EmitInt (ig, 0);
4670                                         ig.Emit (OpCodes.Newarr, pd.ParameterType (0).GetElementType ());
4671                                 }
4672
4673                                 return;
4674                         }
4675
4676                         int top = arguments.Count;
4677
4678                         for (int i = 0; i < top; i++){
4679                                 Argument a = (Argument) arguments [i];
4680
4681                                 if (pd != null){
4682                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4683                                                 //
4684                                                 // Special case if we are passing the same data as the
4685                                                 // params argument, do not put it in an array.
4686                                                 //
4687                                                 if (pd.ParameterType (i) == a.Type)
4688                                                         a.Emit (ec);
4689                                                 else
4690                                                         EmitParams (ec, i, arguments);
4691                                                 return;
4692                                         }
4693                                 }
4694                                             
4695                                 a.Emit (ec);
4696                         }
4697
4698                         if (pd != null && pd.Count > top &&
4699                             pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
4700                                 ILGenerator ig = ec.ig;
4701
4702                                 IntConstant.EmitInt (ig, 0);
4703                                 ig.Emit (OpCodes.Newarr, pd.ParameterType (top).GetElementType ());
4704                         }
4705                 }
4706
4707                 /// <remarks>
4708                 ///   is_base tells whether we want to force the use of the `call'
4709                 ///   opcode instead of using callvirt.  Call is required to call
4710                 ///   a specific method, while callvirt will always use the most
4711                 ///   recent method in the vtable.
4712                 ///
4713                 ///   is_static tells whether this is an invocation on a static method
4714                 ///
4715                 ///   instance_expr is an expression that represents the instance
4716                 ///   it must be non-null if is_static is false.
4717                 ///
4718                 ///   method is the method to invoke.
4719                 ///
4720                 ///   Arguments is the list of arguments to pass to the method or constructor.
4721                 /// </remarks>
4722                 public static void EmitCall (EmitContext ec, bool is_base,
4723                                              bool is_static, Expression instance_expr,
4724                                              MethodBase method, ArrayList Arguments, Location loc)
4725                 {
4726                         ILGenerator ig = ec.ig;
4727                         bool struct_call = false;
4728
4729                         Type decl_type = method.DeclaringType;
4730
4731                         if (!RootContext.StdLib) {
4732                                 // Replace any calls to the system's System.Array type with calls to
4733                                 // the newly created one.
4734                                 if (method == TypeManager.system_int_array_get_length)
4735                                         method = TypeManager.int_array_get_length;
4736                                 else if (method == TypeManager.system_int_array_get_rank)
4737                                         method = TypeManager.int_array_get_rank;
4738                                 else if (method == TypeManager.system_object_array_clone)
4739                                         method = TypeManager.object_array_clone;
4740                                 else if (method == TypeManager.system_int_array_get_length_int)
4741                                         method = TypeManager.int_array_get_length_int;
4742                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4743                                         method = TypeManager.int_array_get_lower_bound_int;
4744                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4745                                         method = TypeManager.int_array_get_upper_bound_int;
4746                                 else if (method == TypeManager.system_void_array_copyto_array_int)
4747                                         method = TypeManager.void_array_copyto_array_int;
4748                         }
4749
4750                         //
4751                         // This checks the `ConditionalAttribute' on the method, and the
4752                         // ObsoleteAttribute
4753                         //
4754                         TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);
4755                         if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)
4756                                 return;
4757                         if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
4758                                 return;
4759                         
4760                         if (!is_static){
4761                                 if (decl_type.IsValueType)
4762                                         struct_call = true;
4763                                 //
4764                                 // If this is ourselves, push "this"
4765                                 //
4766                                 if (instance_expr == null){
4767                                         ig.Emit (OpCodes.Ldarg_0);
4768                                 } else {
4769                                         //
4770                                         // Push the instance expression
4771                                         //
4772                                         if (instance_expr.Type.IsValueType){
4773                                                 //
4774                                                 // Special case: calls to a function declared in a 
4775                                                 // reference-type with a value-type argument need
4776                                                 // to have their value boxed.  
4777
4778                                                 struct_call = true;
4779                                                 if (decl_type.IsValueType){
4780                                                         //
4781                                                         // If the expression implements IMemoryLocation, then
4782                                                         // we can optimize and use AddressOf on the
4783                                                         // return.
4784                                                         //
4785                                                         // If not we have to use some temporary storage for
4786                                                         // it.
4787                                                         if (instance_expr is IMemoryLocation){
4788                                                                 ((IMemoryLocation)instance_expr).
4789                                                                         AddressOf (ec, AddressOp.LoadStore);
4790                                                         }
4791                                                         else {
4792                                                                 Type t = instance_expr.Type;
4793                                                                 
4794                                                                 instance_expr.Emit (ec);
4795                                                                 LocalBuilder temp = ig.DeclareLocal (t);
4796                                                                 ig.Emit (OpCodes.Stloc, temp);
4797                                                                 ig.Emit (OpCodes.Ldloca, temp);
4798                                                         }
4799                                                 } else {
4800                                                         instance_expr.Emit (ec);
4801                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
4802                                                 } 
4803                                         } else
4804                                                 instance_expr.Emit (ec);
4805                                 }
4806                         }
4807
4808                         EmitArguments (ec, method, Arguments);
4809
4810                         if (is_static || struct_call || is_base){
4811                                 if (method is MethodInfo) {
4812                                         ig.Emit (OpCodes.Call, (MethodInfo) method);
4813                                 } else
4814                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
4815                         } else {
4816                                 if (method is MethodInfo)
4817                                         ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
4818                                 else
4819                                         ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
4820                         }
4821                 }
4822                 
4823                 public override void Emit (EmitContext ec)
4824                 {
4825                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
4826
4827                         EmitCall (ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
4828                 }
4829                 
4830                 public override void EmitStatement (EmitContext ec)
4831                 {
4832                         Emit (ec);
4833
4834                         // 
4835                         // Pop the return value if there is one
4836                         //
4837                         if (method is MethodInfo){
4838                                 Type ret = ((MethodInfo)method).ReturnType;
4839                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
4840                                         ec.ig.Emit (OpCodes.Pop);
4841                         }
4842                 }
4843         }
4844
4845         //
4846         // This class is used to "disable" the code generation for the
4847         // temporary variable when initializing value types.
4848         //
4849         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4850                 public void AddressOf (EmitContext ec, AddressOp Mode)
4851                 {
4852                         // nothing
4853                 }
4854         }
4855         
4856         /// <summary>
4857         ///    Implements the new expression 
4858         /// </summary>
4859         public class New : ExpressionStatement, IMemoryLocation {
4860                 public readonly ArrayList Arguments;
4861                 public readonly Expression RequestedType;
4862
4863                 MethodBase method = null;
4864
4865                 //
4866                 // If set, the new expression is for a value_target, and
4867                 // we will not leave anything on the stack.
4868                 //
4869                 Expression value_target;
4870                 bool value_target_set = false;
4871                 
4872                 public New (Expression requested_type, ArrayList arguments, Location l)
4873                 {
4874                         RequestedType = requested_type;
4875                         Arguments = arguments;
4876                         loc = l;
4877                 }
4878
4879                 public Expression ValueTypeVariable {
4880                         get {
4881                                 return value_target;
4882                         }
4883
4884                         set {
4885                                 value_target = value;
4886                                 value_target_set = true;
4887                         }
4888                 }
4889
4890                 //
4891                 // This function is used to disable the following code sequence for
4892                 // value type initialization:
4893                 //
4894                 // AddressOf (temporary)
4895                 // Construct/Init
4896                 // LoadTemporary
4897                 //
4898                 // Instead the provide will have provided us with the address on the
4899                 // stack to store the results.
4900                 //
4901                 static Expression MyEmptyExpression;
4902                 
4903                 public void DisableTemporaryValueType ()
4904                 {
4905                         if (MyEmptyExpression == null)
4906                                 MyEmptyExpression = new EmptyAddressOf ();
4907
4908                         //
4909                         // To enable this, look into:
4910                         // test-34 and test-89 and self bootstrapping.
4911                         //
4912                         // For instance, we can avoid a copy by using `newobj'
4913                         // instead of Call + Push-temp on value types.
4914 //                      value_target = MyEmptyExpression;
4915                 }
4916
4917                 public override Expression DoResolve (EmitContext ec)
4918                 {
4919                         //
4920                         // The New DoResolve might be called twice when initializing field
4921                         // expressions (see EmitFieldInitializers, the call to
4922                         // GetInitializerExpression will perform a resolve on the expression,
4923                         // and later the assign will trigger another resolution
4924                         //
4925                         // This leads to bugs (#37014)
4926                         //
4927                         if (type != null)
4928                                 return this;
4929                         
4930                         type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
4931                         
4932                         if (type == null)
4933                                 return null;
4934                         
4935                         bool IsDelegate = TypeManager.IsDelegateType (type);
4936                         
4937                         if (IsDelegate)
4938                                 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
4939
4940                         if (type.IsInterface || type.IsAbstract){
4941                                 Error (144, "It is not possible to create instances of interfaces or abstract classes");
4942                                 return null;
4943                         }
4944                         
4945                         bool is_struct = false;
4946                         is_struct = type.IsValueType;
4947                         eclass = ExprClass.Value;
4948
4949                         //
4950                         // SRE returns a match for .ctor () on structs (the object constructor), 
4951                         // so we have to manually ignore it.
4952                         //
4953                         if (is_struct && Arguments == null)
4954                                 return this;
4955                         
4956                         Expression ml;
4957                         ml = MemberLookupFinal (ec, null, type, ".ctor",
4958                                                 MemberTypes.Constructor,
4959                                                 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
4960
4961                         if (ml == null)
4962                                 return null;
4963                         
4964                         if (! (ml is MethodGroupExpr)){
4965                                 if (!is_struct){
4966                                         ml.Error_UnexpectedKind ("method group");
4967                                         return null;
4968                                 }
4969                         }
4970
4971                         if (ml != null) {
4972                                 if (Arguments != null){
4973                                         foreach (Argument a in Arguments){
4974                                                 if (!a.Resolve (ec, loc))
4975                                                         return null;
4976                                         }
4977                                 }
4978
4979                                 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
4980                                                                      Arguments, loc);
4981                                 
4982                         }
4983
4984                         if (method == null) { 
4985                                 if (!is_struct || Arguments.Count > 0) {
4986                                         Error (1501, String.Format (
4987                                             "New invocation: Can not find a constructor in `{0}' for this argument list",
4988                                             TypeManager.CSharpName (type)));
4989                                         return null;
4990                                 }
4991                         }
4992                         return this;
4993                 }
4994
4995                 //
4996                 // This DoEmit can be invoked in two contexts:
4997                 //    * As a mechanism that will leave a value on the stack (new object)
4998                 //    * As one that wont (init struct)
4999                 //
5000                 // You can control whether a value is required on the stack by passing
5001                 // need_value_on_stack.  The code *might* leave a value on the stack
5002                 // so it must be popped manually
5003                 //
5004                 // If we are dealing with a ValueType, we have a few
5005                 // situations to deal with:
5006                 //
5007                 //    * The target is a ValueType, and we have been provided
5008                 //      the instance (this is easy, we are being assigned).
5009                 //
5010                 //    * The target of New is being passed as an argument,
5011                 //      to a boxing operation or a function that takes a
5012                 //      ValueType.
5013                 //
5014                 //      In this case, we need to create a temporary variable
5015                 //      that is the argument of New.
5016                 //
5017                 // Returns whether a value is left on the stack
5018                 //
5019                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5020                 {
5021                         bool is_value_type = type.IsValueType;
5022                         ILGenerator ig = ec.ig;
5023
5024                         if (is_value_type){
5025                                 IMemoryLocation ml;
5026
5027                                 // Allow DoEmit() to be called multiple times.
5028                                 // We need to create a new LocalTemporary each time since
5029                                 // you can't share LocalBuilders among ILGeneators.
5030                                 if (!value_target_set)
5031                                         value_target = new LocalTemporary (ec, type);
5032                                         
5033                                 ml = (IMemoryLocation) value_target;
5034                                 ml.AddressOf (ec, AddressOp.Store);
5035                         }
5036
5037                         if (method != null)
5038                                 Invocation.EmitArguments (ec, method, Arguments);
5039
5040                         if (is_value_type){
5041                                 if (method == null)
5042                                         ig.Emit (OpCodes.Initobj, type);
5043                                 else 
5044                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5045                                 if (need_value_on_stack){
5046                                         value_target.Emit (ec);
5047                                         return true;
5048                                 }
5049                                 return false;
5050                         } else {
5051                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5052                                 return true;
5053                         }
5054                 }
5055
5056                 public override void Emit (EmitContext ec)
5057                 {
5058                         DoEmit (ec, true);
5059                 }
5060                 
5061                 public override void EmitStatement (EmitContext ec)
5062                 {
5063                         if (DoEmit (ec, false))
5064                                 ec.ig.Emit (OpCodes.Pop);
5065                 }
5066
5067                 public void AddressOf (EmitContext ec, AddressOp Mode)
5068                 {
5069                         if (!type.IsValueType){
5070                                 //
5071                                 // We throw an exception.  So far, I believe we only need to support
5072                                 // value types:
5073                                 // foreach (int j in new StructType ())
5074                                 // see bug 42390
5075                                 //
5076                                 throw new Exception ("AddressOf should not be used for classes");
5077                         }
5078
5079                         if (!value_target_set)
5080                                 value_target = new LocalTemporary (ec, type);
5081                                         
5082                         IMemoryLocation ml = (IMemoryLocation) value_target;
5083                         ml.AddressOf (ec, AddressOp.Store);
5084                         if (method != null)
5085                                 Invocation.EmitArguments (ec, method, Arguments);
5086
5087                         if (method == null)
5088                                 ec.ig.Emit (OpCodes.Initobj, type);
5089                         else 
5090                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5091                         
5092                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5093                 }
5094         }
5095
5096         /// <summary>
5097         ///   14.5.10.2: Represents an array creation expression.
5098         /// </summary>
5099         ///
5100         /// <remarks>
5101         ///   There are two possible scenarios here: one is an array creation
5102         ///   expression that specifies the dimensions and optionally the
5103         ///   initialization data and the other which does not need dimensions
5104         ///   specified but where initialization data is mandatory.
5105         /// </remarks>
5106         public class ArrayCreation : ExpressionStatement {
5107                 Expression requested_base_type;
5108                 ArrayList initializers;
5109
5110                 //
5111                 // The list of Argument types.
5112                 // This is used to construct the `newarray' or constructor signature
5113                 //
5114                 ArrayList arguments;
5115
5116                 //
5117                 // Method used to create the array object.
5118                 //
5119                 MethodBase new_method = null;
5120                 
5121                 Type array_element_type;
5122                 Type underlying_type;
5123                 bool is_one_dimensional = false;
5124                 bool is_builtin_type = false;
5125                 bool expect_initializers = false;
5126                 int num_arguments = 0;
5127                 int dimensions = 0;
5128                 string rank;
5129
5130                 ArrayList array_data;
5131
5132                 Hashtable bounds;
5133
5134                 //
5135                 // The number of array initializers that we can handle
5136                 // via the InitializeArray method - through EmitStaticInitializers
5137                 //
5138                 int num_automatic_initializers;
5139
5140                 const int max_automatic_initializers = 6;
5141                 
5142                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5143                 {
5144                         this.requested_base_type = requested_base_type;
5145                         this.initializers = initializers;
5146                         this.rank = rank;
5147                         loc = l;
5148
5149                         arguments = new ArrayList ();
5150
5151                         foreach (Expression e in exprs) {
5152                                 arguments.Add (new Argument (e, Argument.AType.Expression));
5153                                 num_arguments++;
5154                         }
5155                 }
5156
5157                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5158                 {
5159                         this.requested_base_type = requested_base_type;
5160                         this.initializers = initializers;
5161                         this.rank = rank;
5162                         loc = l;
5163
5164                         //this.rank = rank.Substring (0, rank.LastIndexOf ("["));
5165                         //
5166                         //string tmp = rank.Substring (rank.LastIndexOf ("["));
5167                         //
5168                         //dimensions = tmp.Length - 1;
5169                         expect_initializers = true;
5170                 }
5171
5172                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5173                 {
5174                         StringBuilder sb = new StringBuilder (rank);
5175                         
5176                         sb.Append ("[");
5177                         for (int i = 1; i < idx_count; i++)
5178                                 sb.Append (",");
5179                         
5180                         sb.Append ("]");
5181
5182                         return new ComposedCast (base_type, sb.ToString (), loc);
5183                 }
5184
5185                 void Error_IncorrectArrayInitializer ()
5186                 {
5187                         Error (178, "Incorrectly structured array initializer");
5188                 }
5189                 
5190                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5191                 {
5192                         if (specified_dims) { 
5193                                 Argument a = (Argument) arguments [idx];
5194                                 
5195                                 if (!a.Resolve (ec, loc))
5196                                         return false;
5197                                 
5198                                 if (!(a.Expr is Constant)) {
5199                                         Error (150, "A constant value is expected");
5200                                         return false;
5201                                 }
5202                                 
5203                                 int value = (int) ((Constant) a.Expr).GetValue ();
5204                                 
5205                                 if (value != probe.Count) {
5206                                         Error_IncorrectArrayInitializer ();
5207                                         return false;
5208                                 }
5209                                 
5210                                 bounds [idx] = value;
5211                         }
5212
5213                         int child_bounds = -1;
5214                         foreach (object o in probe) {
5215                                 if (o is ArrayList) {
5216                                         int current_bounds = ((ArrayList) o).Count;
5217                                         
5218                                         if (child_bounds == -1) 
5219                                                 child_bounds = current_bounds;
5220
5221                                         else if (child_bounds != current_bounds){
5222                                                 Error_IncorrectArrayInitializer ();
5223                                                 return false;
5224                                         }
5225                                         if (specified_dims && (idx + 1 >= arguments.Count)){
5226                                                 Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
5227                                                 return false;
5228                                         }
5229                                         
5230                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
5231                                         if (!ret)
5232                                                 return false;
5233                                 } else {
5234                                         if (child_bounds != -1){
5235                                                 Error_IncorrectArrayInitializer ();
5236                                                 return false;
5237                                         }
5238                                         
5239                                         Expression tmp = (Expression) o;
5240                                         tmp = tmp.Resolve (ec);
5241                                         if (tmp == null)
5242                                                 continue;
5243
5244                                         // Console.WriteLine ("I got: " + tmp);
5245                                         // Handle initialization from vars, fields etc.
5246
5247                                         Expression conv = ConvertImplicitRequired (
5248                                                 ec, tmp, underlying_type, loc);
5249                                         
5250                                         if (conv == null) 
5251                                                 return false;
5252
5253                                         if (conv is StringConstant)
5254                                                 array_data.Add (conv);
5255                                         else if (conv is Constant) {
5256                                                 array_data.Add (conv);
5257                                                 num_automatic_initializers++;
5258                                         } else
5259                                                 array_data.Add (conv);
5260                                 }
5261                         }
5262
5263                         return true;
5264                 }
5265                 
5266                 public void UpdateIndices (EmitContext ec)
5267                 {
5268                         int i = 0;
5269                         for (ArrayList probe = initializers; probe != null;) {
5270                                 if (probe.Count > 0 && probe [0] is ArrayList) {
5271                                         Expression e = new IntConstant (probe.Count);
5272                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5273
5274                                         bounds [i++] =  probe.Count;
5275                                         
5276                                         probe = (ArrayList) probe [0];
5277                                         
5278                                 } else {
5279                                         Expression e = new IntConstant (probe.Count);
5280                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5281
5282                                         bounds [i++] = probe.Count;
5283                                         probe = null;
5284                                 }
5285                         }
5286
5287                 }
5288                 
5289                 public bool ValidateInitializers (EmitContext ec, Type array_type)
5290                 {
5291                         if (initializers == null) {
5292                                 if (expect_initializers)
5293                                         return false;
5294                                 else
5295                                         return true;
5296                         }
5297                         
5298                         if (underlying_type == null)
5299                                 return false;
5300                         
5301                         //
5302                         // We use this to store all the date values in the order in which we
5303                         // will need to store them in the byte blob later
5304                         //
5305                         array_data = new ArrayList ();
5306                         bounds = new Hashtable ();
5307                         
5308                         bool ret;
5309
5310                         if (arguments != null) {
5311                                 ret = CheckIndices (ec, initializers, 0, true);
5312                                 return ret;
5313                         } else {
5314                                 arguments = new ArrayList ();
5315
5316                                 ret = CheckIndices (ec, initializers, 0, false);
5317                                 
5318                                 if (!ret)
5319                                         return false;
5320                                 
5321                                 UpdateIndices (ec);
5322                                 
5323                                 if (arguments.Count != dimensions) {
5324                                         Error_IncorrectArrayInitializer ();
5325                                         return false;
5326                                 }
5327
5328                                 return ret;
5329                         }
5330                 }
5331
5332                 void Error_NegativeArrayIndex ()
5333                 {
5334                         Error (284, "Can not create array with a negative size");
5335                 }
5336                 
5337                 //
5338                 // Converts `source' to an int, uint, long or ulong.
5339                 //
5340                 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
5341                 {
5342                         Expression target;
5343                         
5344                         bool old_checked = ec.CheckState;
5345                         ec.CheckState = true;
5346                         
5347                         target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
5348                         if (target == null){
5349                                 target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
5350                                 if (target == null){
5351                                         target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
5352                                         if (target == null){
5353                                                 target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
5354                                                 if (target == null)
5355                                                         Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);
5356                                         }
5357                                 }
5358                         } 
5359                         ec.CheckState = old_checked;
5360
5361                         //
5362                         // Only positive constants are allowed at compile time
5363                         //
5364                         if (target is Constant){
5365                                 if (target is IntConstant){
5366                                         if (((IntConstant) target).Value < 0){
5367                                                 Error_NegativeArrayIndex ();
5368                                                 return null;
5369                                         }
5370                                 }
5371
5372                                 if (target is LongConstant){
5373                                         if (((LongConstant) target).Value < 0){
5374                                                 Error_NegativeArrayIndex ();
5375                                                 return null;
5376                                         }
5377                                 }
5378                                 
5379                         }
5380
5381                         return target;
5382                 }
5383
5384                 //
5385                 // Creates the type of the array
5386                 //
5387                 bool LookupType (EmitContext ec)
5388                 {
5389                         StringBuilder array_qualifier = new StringBuilder (rank);
5390
5391                         //
5392                         // `In the first form allocates an array instace of the type that results
5393                         // from deleting each of the individual expression from the expression list'
5394                         //
5395                         if (num_arguments > 0) {
5396                                 array_qualifier.Append ("[");
5397                                 for (int i = num_arguments-1; i > 0; i--)
5398                                         array_qualifier.Append (",");
5399                                 array_qualifier.Append ("]");                           
5400                         }
5401
5402                         //
5403                         // Lookup the type
5404                         //
5405                         Expression array_type_expr;
5406                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5407                         type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
5408
5409                         if (type == null)
5410                                 return false;
5411
5412                         underlying_type = type;
5413                         if (underlying_type.IsArray)
5414                                 underlying_type = TypeManager.TypeToCoreType (underlying_type.GetElementType ());
5415                         dimensions = type.GetArrayRank ();
5416
5417                         return true;
5418                 }
5419                 
5420                 public override Expression DoResolve (EmitContext ec)
5421                 {
5422                         int arg_count;
5423
5424                         if (!LookupType (ec))
5425                                 return null;
5426                         
5427                         //
5428                         // First step is to validate the initializers and fill
5429                         // in any missing bits
5430                         //
5431                         if (!ValidateInitializers (ec, type))
5432                                 return null;
5433
5434                         if (arguments == null)
5435                                 arg_count = 0;
5436                         else {
5437                                 arg_count = arguments.Count;
5438                                 foreach (Argument a in arguments){
5439                                         if (!a.Resolve (ec, loc))
5440                                                 return null;
5441
5442                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5443                                         if (real_arg == null)
5444                                                 return null;
5445
5446                                         a.Expr = real_arg;
5447                                 }
5448                         }
5449                         
5450                         array_element_type = TypeManager.TypeToCoreType (type.GetElementType ());
5451
5452                         if (arg_count == 1) {
5453                                 is_one_dimensional = true;
5454                                 eclass = ExprClass.Value;
5455                                 return this;
5456                         }
5457
5458                         is_builtin_type = TypeManager.IsBuiltinType (type);
5459
5460                         if (is_builtin_type) {
5461                                 Expression ml;
5462                                 
5463                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
5464                                                    AllBindingFlags, loc);
5465                                 
5466                                 if (!(ml is MethodGroupExpr)) {
5467                                         ml.Error_UnexpectedKind ("method group");
5468                                         return null;
5469                                 }
5470                                 
5471                                 if (ml == null) {
5472                                         Error (-6, "New invocation: Can not find a constructor for " +
5473                                                       "this argument list");
5474                                         return null;
5475                                 }
5476                                 
5477                                 new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);
5478
5479                                 if (new_method == null) {
5480                                         Error (-6, "New invocation: Can not find a constructor for " +
5481                                                       "this argument list");
5482                                         return null;
5483                                 }
5484                                 
5485                                 eclass = ExprClass.Value;
5486                                 return this;
5487                         } else {
5488                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
5489                                 ArrayList args = new ArrayList ();
5490                                 
5491                                 if (arguments != null) {
5492                                         for (int i = 0; i < arg_count; i++)
5493                                                 args.Add (TypeManager.int32_type);
5494                                 }
5495                                 
5496                                 Type [] arg_types = null;
5497
5498                                 if (args.Count > 0)
5499                                         arg_types = new Type [args.Count];
5500                                 
5501                                 args.CopyTo (arg_types, 0);
5502                                 
5503                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5504                                                             arg_types);
5505
5506                                 if (new_method == null) {
5507                                         Error (-6, "New invocation: Can not find a constructor for " +
5508                                                       "this argument list");
5509                                         return null;
5510                                 }
5511                                 
5512                                 eclass = ExprClass.Value;
5513                                 return this;
5514                         }
5515                 }
5516
5517                 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
5518                 {
5519                         int factor;
5520                         byte [] data;
5521                         byte [] element;
5522                         int count = array_data.Count;
5523
5524                         if (underlying_type.IsEnum)
5525                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
5526                         
5527                         factor = GetTypeSize (underlying_type);
5528                         if (factor == 0)
5529                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
5530
5531                         data = new byte [(count * factor + 4) & ~3];
5532                         int idx = 0;
5533                         
5534                         for (int i = 0; i < count; ++i) {
5535                                 object v = array_data [i];
5536
5537                                 if (v is EnumConstant)
5538                                         v = ((EnumConstant) v).Child;
5539                                 
5540                                 if (v is Constant && !(v is StringConstant))
5541                                         v = ((Constant) v).GetValue ();
5542                                 else {
5543                                         idx += factor;
5544                                         continue;
5545                                 }
5546                                 
5547                                 if (underlying_type == TypeManager.int64_type){
5548                                         if (!(v is Expression)){
5549                                                 long val = (long) v;
5550                                                 
5551                                                 for (int j = 0; j < factor; ++j) {
5552                                                         data [idx + j] = (byte) (val & 0xFF);
5553                                                         val = (val >> 8);
5554                                                 }
5555                                         }
5556                                 } else if (underlying_type == TypeManager.uint64_type){
5557                                         if (!(v is Expression)){
5558                                                 ulong val = (ulong) v;
5559
5560                                                 for (int j = 0; j < factor; ++j) {
5561                                                         data [idx + j] = (byte) (val & 0xFF);
5562                                                         val = (val >> 8);
5563                                                 }
5564                                         }
5565                                 } else if (underlying_type == TypeManager.float_type) {
5566                                         if (!(v is Expression)){
5567                                                 element = BitConverter.GetBytes ((float) v);
5568                                                         
5569                                                 for (int j = 0; j < factor; ++j)
5570                                                         data [idx + j] = element [j];
5571                                         }
5572                                 } else if (underlying_type == TypeManager.double_type) {
5573                                         if (!(v is Expression)){
5574                                                 element = BitConverter.GetBytes ((double) v);
5575
5576                                                 for (int j = 0; j < factor; ++j)
5577                                                         data [idx + j] = element [j];
5578                                         }
5579                                 } else if (underlying_type == TypeManager.char_type){
5580                                         if (!(v is Expression)){
5581                                                 int val = (int) ((char) v);
5582                                                 
5583                                                 data [idx] = (byte) (val & 0xff);
5584                                                 data [idx+1] = (byte) (val >> 8);
5585                                         }
5586                                 } else if (underlying_type == TypeManager.short_type){
5587                                         if (!(v is Expression)){
5588                                                 int val = (int) ((short) v);
5589                                         
5590                                                 data [idx] = (byte) (val & 0xff);
5591                                                 data [idx+1] = (byte) (val >> 8);
5592                                         }
5593                                 } else if (underlying_type == TypeManager.ushort_type){
5594                                         if (!(v is Expression)){
5595                                                 int val = (int) ((ushort) v);
5596                                         
5597                                                 data [idx] = (byte) (val & 0xff);
5598                                                 data [idx+1] = (byte) (val >> 8);
5599                                         }
5600                                 } else if (underlying_type == TypeManager.int32_type) {
5601                                         if (!(v is Expression)){
5602                                                 int val = (int) v;
5603                                         
5604                                                 data [idx]   = (byte) (val & 0xff);
5605                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
5606                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
5607                                                 data [idx+3] = (byte) (val >> 24);
5608                                         }
5609                                 } else if (underlying_type == TypeManager.uint32_type) {
5610                                         if (!(v is Expression)){
5611                                                 uint val = (uint) v;
5612                                         
5613                                                 data [idx]   = (byte) (val & 0xff);
5614                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
5615                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
5616                                                 data [idx+3] = (byte) (val >> 24);
5617                                         }
5618                                 } else if (underlying_type == TypeManager.sbyte_type) {
5619                                         if (!(v is Expression)){
5620                                                 sbyte val = (sbyte) v;
5621                                                 data [idx] = (byte) val;
5622                                         }
5623                                 } else if (underlying_type == TypeManager.byte_type) {
5624                                         if (!(v is Expression)){
5625                                                 byte val = (byte) v;
5626                                                 data [idx] = (byte) val;
5627                                         }
5628                                 } else if (underlying_type == TypeManager.bool_type) {
5629                                         if (!(v is Expression)){
5630                                                 bool val = (bool) v;
5631                                                 data [idx] = (byte) (val ? 1 : 0);
5632                                         }
5633                                 } else if (underlying_type == TypeManager.decimal_type){
5634                                         if (!(v is Expression)){
5635                                                 int [] bits = Decimal.GetBits ((decimal) v);
5636                                                 int p = idx;
5637                                                 
5638                                                 for (int j = 0; j < 4; j++){
5639                                                         data [p++] = (byte) (bits [j] & 0xff);
5640                                                         data [p++] = (byte) ((bits [j] >> 8) & 0xff);
5641                                                         data [p++] = (byte) ((bits [j] >> 16) & 0xff);
5642                                                         data [p++] = (byte) (bits [j] >> 24);
5643                                                 }
5644                                         }
5645                                 } else
5646                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
5647
5648                                 idx += factor;
5649                         }
5650
5651                         return data;
5652                 }
5653
5654                 //
5655                 // Emits the initializers for the array
5656                 //
5657                 void EmitStaticInitializers (EmitContext ec, bool is_expression)
5658                 {
5659                         //
5660                         // First, the static data
5661                         //
5662                         FieldBuilder fb;
5663                         ILGenerator ig = ec.ig;
5664                         
5665                         byte [] data = MakeByteBlob (array_data, underlying_type, loc);
5666
5667                         fb = RootContext.MakeStaticData (data);
5668
5669                         if (is_expression)
5670                                 ig.Emit (OpCodes.Dup);
5671                         ig.Emit (OpCodes.Ldtoken, fb);
5672                         ig.Emit (OpCodes.Call,
5673                                  TypeManager.void_initializearray_array_fieldhandle);
5674                 }
5675                 
5676                 //
5677                 // Emits pieces of the array that can not be computed at compile
5678                 // time (variables and string locations).
5679                 //
5680                 // This always expect the top value on the stack to be the array
5681                 //
5682                 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
5683                 {
5684                         ILGenerator ig = ec.ig;
5685                         int dims = bounds.Count;
5686                         int [] current_pos = new int [dims];
5687                         int top = array_data.Count;
5688                         LocalBuilder temp = ig.DeclareLocal (type);
5689
5690                         ig.Emit (OpCodes.Stloc, temp);
5691
5692                         MethodInfo set = null;
5693
5694                         if (dims != 1){
5695                                 Type [] args;
5696                                 ModuleBuilder mb = null;
5697                                 mb = CodeGen.ModuleBuilder;
5698                                 args = new Type [dims + 1];
5699
5700                                 int j;
5701                                 for (j = 0; j < dims; j++)
5702                                         args [j] = TypeManager.int32_type;
5703
5704                                 args [j] = array_element_type;
5705                                 
5706                                 set = mb.GetArrayMethod (
5707                                         type, "Set",
5708                                         CallingConventions.HasThis | CallingConventions.Standard,
5709                                         TypeManager.void_type, args);
5710                         }
5711                         
5712                         for (int i = 0; i < top; i++){
5713
5714                                 Expression e = null;
5715
5716                                 if (array_data [i] is Expression)
5717                                         e = (Expression) array_data [i];
5718
5719                                 if (e != null) {
5720                                         //
5721                                         // Basically we do this for string literals and
5722                                         // other non-literal expressions
5723                                         //
5724                                         if (e is EnumConstant){
5725                                                 e = ((EnumConstant) e).Child;
5726                                         }
5727                                         
5728                                         if (e is StringConstant || !(e is Constant) ||
5729                                             num_automatic_initializers <= max_automatic_initializers) {
5730                                                 Type etype = e.Type;
5731                                                 
5732                                                 ig.Emit (OpCodes.Ldloc, temp);
5733
5734                                                 for (int idx = 0; idx < dims; idx++) 
5735                                                         IntConstant.EmitInt (ig, current_pos [idx]);
5736
5737                                                 //
5738                                                 // If we are dealing with a struct, get the
5739                                                 // address of it, so we can store it.
5740                                                 //
5741                                                 if ((dims == 1) &&
5742                                                     etype.IsSubclassOf (TypeManager.value_type) &&
5743                                                     (!TypeManager.IsBuiltinType (etype) ||
5744                                                      etype == TypeManager.decimal_type)) {
5745                                                         if (e is New){
5746                                                                 New n = (New) e;
5747
5748                                                                 //
5749                                                                 // Let new know that we are providing
5750                                                                 // the address where to store the results
5751                                                                 //
5752                                                                 n.DisableTemporaryValueType ();
5753                                                         }
5754                                                                              
5755                                                         ig.Emit (OpCodes.Ldelema, etype);
5756                                                 }
5757
5758                                                 e.Emit (ec);
5759                                                 
5760                                                 if (dims == 1)
5761                                                         ArrayAccess.EmitStoreOpcode (ig, array_element_type);
5762                                                 else 
5763                                                         ig.Emit (OpCodes.Call, set);
5764                                         }
5765                                 }
5766                                 
5767                                 //
5768                                 // Advance counter
5769                                 //
5770                                 for (int j = dims - 1; j >= 0; j--){
5771                                         current_pos [j]++;
5772                                         if (current_pos [j] < (int) bounds [j])
5773                                                 break;
5774                                         current_pos [j] = 0;
5775                                 }
5776                         }
5777
5778                         if (is_expression)
5779                                 ig.Emit (OpCodes.Ldloc, temp);
5780                 }
5781
5782                 void EmitArrayArguments (EmitContext ec)
5783                 {
5784                         ILGenerator ig = ec.ig;
5785                         
5786                         foreach (Argument a in arguments) {
5787                                 Type atype = a.Type;
5788                                 a.Emit (ec);
5789
5790                                 if (atype == TypeManager.uint64_type)
5791                                         ig.Emit (OpCodes.Conv_Ovf_U4);
5792                                 else if (atype == TypeManager.int64_type)
5793                                         ig.Emit (OpCodes.Conv_Ovf_I4);
5794                         }
5795                 }
5796                 
5797                 void DoEmit (EmitContext ec, bool is_statement)
5798                 {
5799                         ILGenerator ig = ec.ig;
5800                         
5801                         EmitArrayArguments (ec);
5802                         if (is_one_dimensional)
5803                                 ig.Emit (OpCodes.Newarr, array_element_type);
5804                         else {
5805                                 if (is_builtin_type) 
5806                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
5807                                 else 
5808                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
5809                         }
5810                         
5811                         if (initializers != null){
5812                                 //
5813                                 // FIXME: Set this variable correctly.
5814                                 // 
5815                                 bool dynamic_initializers = true;
5816
5817                                 if (underlying_type != TypeManager.string_type &&
5818                                     underlying_type != TypeManager.object_type) {
5819                                         if (num_automatic_initializers > max_automatic_initializers)
5820                                                 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
5821                                 }
5822                                 
5823                                 if (dynamic_initializers)
5824                                         EmitDynamicInitializers (ec, !is_statement);
5825                         }
5826                 }
5827                 
5828                 public override void Emit (EmitContext ec)
5829                 {
5830                         DoEmit (ec, false);
5831                 }
5832
5833                 public override void EmitStatement (EmitContext ec)
5834                 {
5835                         DoEmit (ec, true);
5836                 }
5837
5838                 public object EncodeAsAttribute ()
5839                 {
5840                         if (!is_one_dimensional){
5841                                 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
5842                                 return null;
5843                         }
5844
5845                         if (array_data == null){
5846                                 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
5847                                 return null;
5848                         }
5849                         
5850                         object [] ret = new object [array_data.Count];
5851                         int i = 0;
5852                         foreach (Expression e in array_data){
5853                                 object v;
5854                                 
5855                                 if (e is NullLiteral)
5856                                         v = null;
5857                                 else {
5858                                         if (!Attribute.GetAttributeArgumentExpression (e, Location, out v))
5859                                                 return null;
5860                                 }
5861                                 ret [i++] = v;
5862                         }
5863                         return ret;
5864                 }
5865         }
5866         
5867         /// <summary>
5868         ///   Represents the `this' construct
5869         /// </summary>
5870         public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
5871
5872                 Block block;
5873                 VariableInfo vi;
5874                 
5875                 public This (Block block, Location loc)
5876                 {
5877                         this.loc = loc;
5878                         this.block = block;
5879                 }
5880
5881                 public This (Location loc)
5882                 {
5883                         this.loc = loc;
5884                 }
5885
5886                 public bool IsAssigned (EmitContext ec, Location loc)
5887                 {
5888                         if (vi == null)
5889                                 return true;
5890
5891                         return vi.IsAssigned (ec, loc);
5892                 }
5893
5894                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
5895                 {
5896                         if (vi == null)
5897                                 return true;
5898
5899                         return vi.IsFieldAssigned (ec, field_name, loc);
5900                 }
5901
5902                 public void SetAssigned (EmitContext ec)
5903                 {
5904                         if (vi != null)
5905                                 vi.SetAssigned (ec);
5906                 }
5907
5908                 public void SetFieldAssigned (EmitContext ec, string field_name)
5909                 {       
5910                         if (vi != null)
5911                                 vi.SetFieldAssigned (ec, field_name);
5912                 }
5913
5914                 public override Expression DoResolve (EmitContext ec)
5915                 {
5916                         eclass = ExprClass.Variable;
5917                         type = ec.ContainerType;
5918
5919                         if (ec.IsStatic){
5920                                 Error (26, "Keyword this not valid in static code");
5921                                 return null;
5922                         }
5923
5924                         if (block != null)
5925                                 vi = block.ThisVariable;
5926
5927                         return this;
5928                 }
5929
5930                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5931                 {
5932                         DoResolve (ec);
5933
5934                         VariableInfo vi = ec.CurrentBlock.ThisVariable;
5935                         if (vi != null)
5936                                 vi.SetAssigned (ec);
5937                         
5938                         if (ec.TypeContainer is Class){
5939                                 Error (1604, "Cannot assign to `this'");
5940                                 return null;
5941                         }
5942
5943                         return this;
5944                 }
5945
5946                 public override void Emit (EmitContext ec)
5947                 {
5948                         ILGenerator ig = ec.ig;
5949                         
5950                         ig.Emit (OpCodes.Ldarg_0);
5951                         if (ec.TypeContainer is Struct)
5952                                 ig.Emit (OpCodes.Ldobj, type);
5953                 }
5954
5955                 public void EmitAssign (EmitContext ec, Expression source)
5956                 {
5957                         ILGenerator ig = ec.ig;
5958                         
5959                         if (ec.TypeContainer is Struct){
5960                                 ig.Emit (OpCodes.Ldarg_0);
5961                                 source.Emit (ec);
5962                                 ig.Emit (OpCodes.Stobj, type);
5963                         } else {
5964                                 source.Emit (ec);
5965                                 ig.Emit (OpCodes.Starg, 0);
5966                         }
5967                 }
5968
5969                 public void AddressOf (EmitContext ec, AddressOp mode)
5970                 {
5971                         ec.ig.Emit (OpCodes.Ldarg_0);
5972
5973                         // FIMXE
5974                         // FIGURE OUT WHY LDARG_S does not work
5975                         //
5976                         // consider: struct X { int val; int P { set { val = value; }}}
5977                         //
5978                         // Yes, this looks very bad. Look at `NOTAS' for
5979                         // an explanation.
5980                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
5981                 }
5982         }
5983
5984         /// <summary>
5985         ///   Implements the typeof operator
5986         /// </summary>
5987         public class TypeOf : Expression {
5988                 public readonly Expression QueriedType;
5989                 Type typearg;
5990                 
5991                 public TypeOf (Expression queried_type, Location l)
5992                 {
5993                         QueriedType = queried_type;
5994                         loc = l;
5995                 }
5996
5997                 public override Expression DoResolve (EmitContext ec)
5998                 {
5999                         typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6000
6001                         if (typearg == null)
6002                                 return null;
6003
6004                         type = TypeManager.type_type;
6005                         eclass = ExprClass.Type;
6006                         return this;
6007                 }
6008
6009                 public override void Emit (EmitContext ec)
6010                 {
6011                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
6012                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6013                 }
6014
6015                 public Type TypeArg { 
6016                         get { return typearg; }
6017                 }
6018         }
6019
6020         /// <summary>
6021         ///   Implements the sizeof expression
6022         /// </summary>
6023         public class SizeOf : Expression {
6024                 public readonly Expression QueriedType;
6025                 Type type_queried;
6026                 
6027                 public SizeOf (Expression queried_type, Location l)
6028                 {
6029                         this.QueriedType = queried_type;
6030                         loc = l;
6031                 }
6032
6033                 public override Expression DoResolve (EmitContext ec)
6034                 {
6035                         if (!ec.InUnsafe) {
6036                                 Report.Error (
6037                                         233, loc, "Sizeof may only be used in an unsafe context " +
6038                                         "(consider using System.Runtime.InteropServices.Marshal.Sizeof");
6039                                 return null;
6040                         }
6041                                 
6042                         type_queried = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6043                         if (type_queried == null)
6044                                 return null;
6045
6046                         if (!TypeManager.IsUnmanagedType (type_queried)){
6047                                 Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
6048                                 return null;
6049                         }
6050                         
6051                         type = TypeManager.int32_type;
6052                         eclass = ExprClass.Value;
6053                         return this;
6054                 }
6055
6056                 public override void Emit (EmitContext ec)
6057                 {
6058                         int size = GetTypeSize (type_queried);
6059
6060                         if (size == 0)
6061                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6062                         else
6063                                 IntConstant.EmitInt (ec.ig, size);
6064                 }
6065         }
6066
6067         /// <summary>
6068         ///   Implements the member access expression
6069         /// </summary>
6070         public class MemberAccess : Expression {
6071                 public readonly string Identifier;
6072                 Expression expr;
6073                 
6074                 public MemberAccess (Expression expr, string id, Location l)
6075                 {
6076                         this.expr = expr;
6077                         Identifier = id;
6078                         loc = l;
6079                 }
6080
6081                 public Expression Expr {
6082                         get {
6083                                 return expr;
6084                         }
6085                 }
6086
6087                 static void error176 (Location loc, string name)
6088                 {
6089                         Report.Error (176, loc, "Static member `" +
6090                                       name + "' cannot be accessed " +
6091                                       "with an instance reference, qualify with a " +
6092                                       "type name instead");
6093                 }
6094
6095                 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
6096                 {
6097                         if (left_original == null)
6098                                 return false;
6099
6100                         if (!(left_original is SimpleName))
6101                                 return false;
6102
6103                         SimpleName sn = (SimpleName) left_original;
6104
6105                         Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
6106                         if (t != null)
6107                                 return true;
6108
6109                         return false;
6110                 }
6111                 
6112                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
6113                                                               Expression left, Location loc,
6114                                                               Expression left_original)
6115                 {
6116                         bool left_is_type, left_is_explicit;
6117
6118                         // If `left' is null, then we're called from SimpleNameResolve and this is
6119                         // a member in the currently defining class.
6120                         if (left == null) {
6121                                 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
6122                                 left_is_explicit = false;
6123
6124                                 // Implicitly default to `this' unless we're static.
6125                                 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
6126                                         left = ec.This;
6127                         } else {
6128                                 left_is_type = left is TypeExpr;
6129                                 left_is_explicit = true;
6130                         }
6131
6132                         if (member_lookup is FieldExpr){
6133                                 FieldExpr fe = (FieldExpr) member_lookup;
6134                                 FieldInfo fi = fe.FieldInfo;
6135                                 Type decl_type = fi.DeclaringType;
6136                                 
6137                                 if (fi is FieldBuilder) {
6138                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
6139                                         
6140                                         if (c != null) {
6141                                                 object o = c.LookupConstantValue (ec);
6142                                                 if (o == null)
6143                                                         return null;
6144                                                 
6145                                                 object real_value = ((Constant) c.Expr).GetValue ();
6146
6147                                                 return Constantify (real_value, fi.FieldType);
6148                                         }
6149                                 }
6150
6151                                 if (fi.IsLiteral) {
6152                                         Type t = fi.FieldType;
6153                                         
6154                                         object o;
6155
6156                                         if (fi is FieldBuilder)
6157                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
6158                                         else
6159                                                 o = fi.GetValue (fi);
6160                                         
6161                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
6162                                                 if (left_is_explicit && !left_is_type &&
6163                                                     !IdenticalNameAndTypeName (ec, left_original, loc)) {
6164                                                         error176 (loc, fe.FieldInfo.Name);
6165                                                         return null;
6166                                                 }                                       
6167                                                 
6168                                                 Expression enum_member = MemberLookup (
6169                                                         ec, decl_type, "value__", MemberTypes.Field,
6170                                                         AllBindingFlags, loc); 
6171
6172                                                 Enum en = TypeManager.LookupEnum (decl_type);
6173
6174                                                 Constant c;
6175                                                 if (en != null)
6176                                                         c = Constantify (o, en.UnderlyingType);
6177                                                 else 
6178                                                         c = Constantify (o, enum_member.Type);
6179                                                 
6180                                                 return new EnumConstant (c, decl_type);
6181                                         }
6182                                         
6183                                         Expression exp = Constantify (o, t);
6184
6185                                         if (left_is_explicit && !left_is_type) {
6186                                                 error176 (loc, fe.FieldInfo.Name);
6187                                                 return null;
6188                                         }
6189                                         
6190                                         return exp;
6191                                 }
6192
6193                                 if (fi.FieldType.IsPointer && !ec.InUnsafe){
6194                                         UnsafeError (loc);
6195                                         return null;
6196                                 }
6197                         }
6198
6199                         if (member_lookup is EventExpr) {
6200
6201                                 EventExpr ee = (EventExpr) member_lookup;
6202                                 
6203                                 //
6204                                 // If the event is local to this class, we transform ourselves into
6205                                 // a FieldExpr
6206                                 //
6207
6208                                 if (ee.EventInfo.DeclaringType == ec.ContainerType) {
6209                                         MemberInfo mi = GetFieldFromEvent (ee);
6210
6211                                         if (mi == null) {
6212                                                 //
6213                                                 // If this happens, then we have an event with its own
6214                                                 // accessors and private field etc so there's no need
6215                                                 // to transform ourselves : we should instead flag an error
6216                                                 //
6217                                                 Assign.error70 (ee.EventInfo, loc);
6218                                                 return null;
6219                                         }
6220
6221                                         Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
6222                                         
6223                                         if (ml == null) {
6224                                                 Report.Error (-200, loc, "Internal error!!");
6225                                                 return null;
6226                                         }
6227                                         
6228                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);
6229                                 }
6230                         }
6231                         
6232                         if (member_lookup is IMemberExpr) {
6233                                 IMemberExpr me = (IMemberExpr) member_lookup;
6234
6235                                 if (left_is_type){
6236                                         MethodGroupExpr mg = me as MethodGroupExpr;
6237                                         if ((mg != null) && left_is_explicit && left.Type.IsInterface)
6238                                                 mg.IsExplicitImpl = left_is_explicit;
6239
6240                                         if (!me.IsStatic){
6241                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
6242                                                         return member_lookup;
6243
6244                                                 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
6245                                                 return null;
6246                                         }
6247
6248                                 } else {
6249                                         if (!me.IsInstance){
6250                                                 if (IdenticalNameAndTypeName (ec, left_original, loc))
6251                                                         return member_lookup;
6252
6253                                                 if (left_is_explicit) {
6254                                                         error176 (loc, me.Name);
6255                                                         return null;
6256                                                 }
6257                                         }
6258
6259                                         //
6260                                         // Since we can not check for instance objects in SimpleName,
6261                                         // becaue of the rule that allows types and variables to share
6262                                         // the name (as long as they can be de-ambiguated later, see 
6263                                         // IdenticalNameAndTypeName), we have to check whether left 
6264                                         // is an instance variable in a static context
6265                                         //
6266                                         // However, if the left-hand value is explicitly given, then
6267                                         // it is already our instance expression, so we aren't in
6268                                         // static context.
6269                                         //
6270
6271                                         if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
6272                                                 IMemberExpr mexp = (IMemberExpr) left;
6273
6274                                                 if (!mexp.IsStatic){
6275                                                         SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
6276                                                         return null;
6277                                                 }
6278                                         }
6279
6280                                         me.InstanceExpression = left;
6281                                 }
6282
6283                                 return member_lookup;
6284                         }
6285
6286                         Console.WriteLine ("Left is: " + left);
6287                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
6288                         Environment.Exit (0);
6289                         return null;
6290                 }
6291                 
6292                 public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
6293                 {
6294                         if (type != null)
6295                                 throw new Exception ();
6296
6297                         //
6298                         // Resolve the expression with flow analysis turned off, we'll do the definite
6299                         // assignment checks later.  This is because we don't know yet what the expression
6300                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6301                         // definite assignment check on the actual field and not on the whole struct.
6302                         //
6303
6304                         Expression original = expr;
6305                         expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
6306                         if (expr == null)
6307                                 return null;
6308
6309                         if (expr is SimpleName){
6310                                 SimpleName child_expr = (SimpleName) expr;
6311                                 
6312                                 Expression new_expr = new SimpleName (child_expr.Name, Identifier, loc);
6313
6314                                 return new_expr.Resolve (ec, flags);
6315                         }
6316                                         
6317                         //
6318                         // TODO: I mailed Ravi about this, and apparently we can get rid
6319                         // of this and put it in the right place.
6320                         // 
6321                         // Handle enums here when they are in transit.
6322                         // Note that we cannot afford to hit MemberLookup in this case because
6323                         // it will fail to find any members at all
6324                         //
6325
6326                         int errors = Report.Errors;
6327                         
6328                         Type expr_type = expr.Type;
6329                         if (expr is TypeExpr){
6330                                 if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
6331                                         Error (122, "`" + expr_type + "' " +
6332                                                "is inaccessible because of its protection level");
6333                                         return null;
6334                                 }
6335                                     
6336                                 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
6337                                         Enum en = TypeManager.LookupEnum (expr_type);
6338                                         
6339                                         if (en != null) {
6340                                                 object value = en.LookupEnumValue (ec, Identifier, loc);
6341                                                 
6342                                                 if (value != null){
6343                                                         Constant c = Constantify (value, en.UnderlyingType);
6344                                                         return new EnumConstant (c, expr_type);
6345                                                 }
6346                                         }
6347                                 }
6348                         }
6349                         
6350                         if (expr_type.IsPointer){
6351                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
6352                                        TypeManager.CSharpName (expr_type) + ")");
6353                                 return null;
6354                         }
6355
6356                         Expression member_lookup;
6357                         member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
6358                         if (member_lookup == null)
6359                                 return null;
6360
6361                         if (member_lookup is TypeExpr)
6362                                 return member_lookup;
6363                         
6364                         member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
6365                         if (member_lookup == null)
6366                                 return null;
6367
6368                         // The following DoResolve/DoResolveLValue will do the definite assignment
6369                         // check.
6370
6371                         if (right_side != null)
6372                                 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
6373                         else
6374                                 member_lookup = member_lookup.DoResolve (ec);
6375
6376                         return member_lookup;
6377                 }
6378
6379                 public override Expression DoResolve (EmitContext ec)
6380                 {
6381                         return DoResolve (ec, null, ResolveFlags.VariableOrValue |
6382                                           ResolveFlags.SimpleName | ResolveFlags.Type);
6383                 }
6384
6385                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6386                 {
6387                         return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
6388                                           ResolveFlags.SimpleName | ResolveFlags.Type);
6389                 }
6390
6391                 public override Expression ResolveAsTypeStep (EmitContext ec)
6392                 {
6393                         Expression new_expr = expr.ResolveAsTypeStep (ec);
6394
6395                         if (new_expr == null)
6396                                 return null;
6397
6398                         if (new_expr is SimpleName){
6399                                 SimpleName child_expr = (SimpleName) new_expr;
6400                                 
6401                                 new_expr = new SimpleName (child_expr.Name, Identifier, loc);
6402
6403                                 return new_expr.ResolveAsTypeStep (ec);
6404                         }
6405
6406                         Type expr_type = new_expr.Type;
6407                       
6408                         if (expr_type.IsPointer){
6409                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
6410                                        TypeManager.CSharpName (expr_type) + ")");
6411                                 return null;
6412                         }
6413                         
6414                         Expression member_lookup;
6415                         member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
6416                         if (member_lookup == null)
6417                                 return null;
6418
6419                         if (member_lookup is TypeExpr){
6420                                 member_lookup.Resolve (ec, ResolveFlags.Type);
6421                                 return member_lookup;
6422                         } 
6423
6424                         return null;                    
6425                 }
6426
6427                 public override void Emit (EmitContext ec)
6428                 {
6429                         throw new Exception ("Should not happen");
6430                 }
6431
6432                 public override string ToString ()
6433                 {
6434                         return expr + "." + Identifier;
6435                 }
6436         }
6437
6438         /// <summary>
6439         ///   Implements checked expressions
6440         /// </summary>
6441         public class CheckedExpr : Expression {
6442
6443                 public Expression Expr;
6444
6445                 public CheckedExpr (Expression e, Location l)
6446                 {
6447                         Expr = e;
6448                         loc = l;
6449                 }
6450
6451                 public override Expression DoResolve (EmitContext ec)
6452                 {
6453                         bool last_check = ec.CheckState;
6454                         bool last_const_check = ec.ConstantCheckState;
6455
6456                         ec.CheckState = true;
6457                         ec.ConstantCheckState = true;
6458                         Expr = Expr.Resolve (ec);
6459                         ec.CheckState = last_check;
6460                         ec.ConstantCheckState = last_const_check;
6461                         
6462                         if (Expr == null)
6463                                 return null;
6464
6465                         if (Expr is Constant)
6466                                 return Expr;
6467                         
6468                         eclass = Expr.eclass;
6469                         type = Expr.Type;
6470                         return this;
6471                 }
6472
6473                 public override void Emit (EmitContext ec)
6474                 {
6475                         bool last_check = ec.CheckState;
6476                         bool last_const_check = ec.ConstantCheckState;
6477                         
6478                         ec.CheckState = true;
6479                         ec.ConstantCheckState = true;
6480                         Expr.Emit (ec);
6481                         ec.CheckState = last_check;
6482                         ec.ConstantCheckState = last_const_check;
6483                 }
6484                 
6485         }
6486
6487         /// <summary>
6488         ///   Implements the unchecked expression
6489         /// </summary>
6490         public class UnCheckedExpr : Expression {
6491
6492                 public Expression Expr;
6493
6494                 public UnCheckedExpr (Expression e, Location l)
6495                 {
6496                         Expr = e;
6497                         loc = l;
6498                 }
6499
6500                 public override Expression DoResolve (EmitContext ec)
6501                 {
6502                         bool last_check = ec.CheckState;
6503                         bool last_const_check = ec.ConstantCheckState;
6504
6505                         ec.CheckState = false;
6506                         ec.ConstantCheckState = false;
6507                         Expr = Expr.Resolve (ec);
6508                         ec.CheckState = last_check;
6509                         ec.ConstantCheckState = last_const_check;
6510
6511                         if (Expr == null)
6512                                 return null;
6513
6514                         if (Expr is Constant)
6515                                 return Expr;
6516                         
6517                         eclass = Expr.eclass;
6518                         type = Expr.Type;
6519                         return this;
6520                 }
6521
6522                 public override void Emit (EmitContext ec)
6523                 {
6524                         bool last_check = ec.CheckState;
6525                         bool last_const_check = ec.ConstantCheckState;
6526                         
6527                         ec.CheckState = false;
6528                         ec.ConstantCheckState = false;
6529                         Expr.Emit (ec);
6530                         ec.CheckState = last_check;
6531                         ec.ConstantCheckState = last_const_check;
6532                 }
6533                 
6534         }
6535
6536         /// <summary>
6537         ///   An Element Access expression.
6538         ///
6539         ///   During semantic analysis these are transformed into 
6540         ///   IndexerAccess or ArrayAccess 
6541         /// </summary>
6542         public class ElementAccess : Expression {
6543                 public ArrayList  Arguments;
6544                 public Expression Expr;
6545                 
6546                 public ElementAccess (Expression e, ArrayList e_list, Location l)
6547                 {
6548                         Expr = e;
6549
6550                         loc  = l;
6551                         
6552                         if (e_list == null)
6553                                 return;
6554                         
6555                         Arguments = new ArrayList ();
6556                         foreach (Expression tmp in e_list)
6557                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
6558                         
6559                 }
6560
6561                 bool CommonResolve (EmitContext ec)
6562                 {
6563                         Expr = Expr.Resolve (ec);
6564
6565                         if (Expr == null) 
6566                                 return false;
6567
6568                         if (Arguments == null)
6569                                 return false;
6570
6571                         foreach (Argument a in Arguments){
6572                                 if (!a.Resolve (ec, loc))
6573                                         return false;
6574                         }
6575
6576                         return true;
6577                 }
6578
6579                 Expression MakePointerAccess ()
6580                 {
6581                         Type t = Expr.Type;
6582
6583                         if (t == TypeManager.void_ptr_type){
6584                                 Error (242, "The array index operation is not valid for void pointers");
6585                                 return null;
6586                         }
6587                         if (Arguments.Count != 1){
6588                                 Error (196, "A pointer must be indexed by a single value");
6589                                 return null;
6590                         }
6591                         Expression p;
6592
6593                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc);
6594                         return new Indirection (p, loc);
6595                 }
6596                 
6597                 public override Expression DoResolve (EmitContext ec)
6598                 {
6599                         if (!CommonResolve (ec))
6600                                 return null;
6601
6602                         //
6603                         // We perform some simple tests, and then to "split" the emit and store
6604                         // code we create an instance of a different class, and return that.
6605                         //
6606                         // I am experimenting with this pattern.
6607                         //
6608                         Type t = Expr.Type;
6609
6610                         if (t.IsArray)
6611                                 return (new ArrayAccess (this, loc)).Resolve (ec);
6612                         else if (t.IsPointer)
6613                                 return MakePointerAccess ();
6614                         else
6615                                 return (new IndexerAccess (this, loc)).Resolve (ec);
6616                 }
6617
6618                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6619                 {
6620                         if (!CommonResolve (ec))
6621                                 return null;
6622
6623                         Type t = Expr.Type;
6624                         if (t.IsArray)
6625                                 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
6626                         else if (t.IsPointer)
6627                                 return MakePointerAccess ();
6628                         else
6629                                 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
6630                 }
6631                 
6632                 public override void Emit (EmitContext ec)
6633                 {
6634                         throw new Exception ("Should never be reached");
6635                 }
6636         }
6637
6638         /// <summary>
6639         ///   Implements array access 
6640         /// </summary>
6641         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
6642                 //
6643                 // Points to our "data" repository
6644                 //
6645                 ElementAccess ea;
6646
6647                 LocalTemporary [] cached_locations;
6648                 
6649                 public ArrayAccess (ElementAccess ea_data, Location l)
6650                 {
6651                         ea = ea_data;
6652                         eclass = ExprClass.Variable;
6653                         loc = l;
6654                 }
6655
6656                 public override Expression DoResolve (EmitContext ec)
6657                 {
6658                         ExprClass eclass = ea.Expr.eclass;
6659
6660 #if false
6661                         // As long as the type is valid
6662                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
6663                               eclass == ExprClass.Value)) {
6664                                 ea.Expr.Error_UnexpectedKind ("variable or value");
6665                                 return null;
6666                         }
6667 #endif
6668
6669                         Type t = ea.Expr.Type;
6670                         if (t.GetArrayRank () != ea.Arguments.Count){
6671                                 ea.Error (22,
6672                                           "Incorrect number of indexes for array " +
6673                                           " expected: " + t.GetArrayRank () + " got: " +
6674                                           ea.Arguments.Count);
6675                                 return null;
6676                         }
6677                         type = TypeManager.TypeToCoreType (t.GetElementType ());
6678                         if (type.IsPointer && !ec.InUnsafe){
6679                                 UnsafeError (ea.Location);
6680                                 return null;
6681                         }
6682
6683                         foreach (Argument a in ea.Arguments){
6684                                 Type argtype = a.Type;
6685
6686                                 if (argtype == TypeManager.int32_type ||
6687                                     argtype == TypeManager.uint32_type ||
6688                                     argtype == TypeManager.int64_type ||
6689                                     argtype == TypeManager.uint64_type)
6690                                         continue;
6691
6692                                 //
6693                                 // Mhm.  This is strage, because the Argument.Type is not the same as
6694                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
6695                                 //
6696                                 // Wonder if I will run into trouble for this.
6697                                 //
6698                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
6699                                 if (a.Expr == null)
6700                                         return null;
6701                         }
6702                         
6703                         eclass = ExprClass.Variable;
6704
6705                         return this;
6706                 }
6707
6708                 /// <summary>
6709                 ///    Emits the right opcode to load an object of Type `t'
6710                 ///    from an array of T
6711                 /// </summary>
6712                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
6713                 {
6714                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
6715                                 ig.Emit (OpCodes.Ldelem_U1);
6716                         else if (type == TypeManager.sbyte_type)
6717                                 ig.Emit (OpCodes.Ldelem_I1);
6718                         else if (type == TypeManager.short_type)
6719                                 ig.Emit (OpCodes.Ldelem_I2);
6720                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
6721                                 ig.Emit (OpCodes.Ldelem_U2);
6722                         else if (type == TypeManager.int32_type)
6723                                 ig.Emit (OpCodes.Ldelem_I4);
6724                         else if (type == TypeManager.uint32_type)
6725                                 ig.Emit (OpCodes.Ldelem_U4);
6726                         else if (type == TypeManager.uint64_type)
6727                                 ig.Emit (OpCodes.Ldelem_I8);
6728                         else if (type == TypeManager.int64_type)
6729                                 ig.Emit (OpCodes.Ldelem_I8);
6730                         else if (type == TypeManager.float_type)
6731                                 ig.Emit (OpCodes.Ldelem_R4);
6732                         else if (type == TypeManager.double_type)
6733                                 ig.Emit (OpCodes.Ldelem_R8);
6734                         else if (type == TypeManager.intptr_type)
6735                                 ig.Emit (OpCodes.Ldelem_I);
6736                         else if (type.IsValueType){
6737                                 ig.Emit (OpCodes.Ldelema, type);
6738                                 ig.Emit (OpCodes.Ldobj, type);
6739                         } else 
6740                                 ig.Emit (OpCodes.Ldelem_Ref);
6741                 }
6742
6743                 /// <summary>
6744                 ///    Emits the right opcode to store an object of Type `t'
6745                 ///    from an array of T.  
6746                 /// </summary>
6747                 static public void EmitStoreOpcode (ILGenerator ig, Type t)
6748                 {
6749                         bool is_stobj;
6750                         OpCode op = GetStoreOpcode (t, out is_stobj);
6751                         if (is_stobj)
6752                                 ig.Emit (OpCodes.Stobj, t);
6753                         else
6754                                 ig.Emit (op);
6755                 }
6756
6757                 /// <summary>
6758                 ///    Returns the right opcode to store an object of Type `t'
6759                 ///    from an array of T.  
6760                 /// </summary>
6761                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj)
6762                 {
6763                         is_stobj = false;
6764                         t = TypeManager.TypeToCoreType (t);
6765                         if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
6766                                 t = TypeManager.EnumToUnderlying (t);
6767                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
6768                             t == TypeManager.bool_type)
6769                                 return OpCodes.Stelem_I1;
6770                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
6771                                  t == TypeManager.char_type)
6772                                 return OpCodes.Stelem_I2;
6773                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
6774                                 return OpCodes.Stelem_I4;
6775                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
6776                                 return OpCodes.Stelem_I8;
6777                         else if (t == TypeManager.float_type)
6778                                 return OpCodes.Stelem_R4;
6779                         else if (t == TypeManager.double_type)
6780                                 return OpCodes.Stelem_R8;
6781                         else if (t == TypeManager.intptr_type)
6782                                 return OpCodes.Stelem_I;
6783                         else if (t.IsValueType) {
6784                                 is_stobj = true;
6785                                 return OpCodes.Stobj;
6786                         } else
6787                                 return OpCodes.Stelem_Ref;
6788                 }
6789
6790                 MethodInfo FetchGetMethod ()
6791                 {
6792                         ModuleBuilder mb = CodeGen.ModuleBuilder;
6793                         int arg_count = ea.Arguments.Count;
6794                         Type [] args = new Type [arg_count];
6795                         MethodInfo get;
6796                         
6797                         for (int i = 0; i < arg_count; i++){
6798                                 //args [i++] = a.Type;
6799                                 args [i] = TypeManager.int32_type;
6800                         }
6801                         
6802                         get = mb.GetArrayMethod (
6803                                 ea.Expr.Type, "Get",
6804                                 CallingConventions.HasThis |
6805                                 CallingConventions.Standard,
6806                                 type, args);
6807                         return get;
6808                 }
6809                                 
6810
6811                 MethodInfo FetchAddressMethod ()
6812                 {
6813                         ModuleBuilder mb = CodeGen.ModuleBuilder;
6814                         int arg_count = ea.Arguments.Count;
6815                         Type [] args = new Type [arg_count];
6816                         MethodInfo address;
6817                         Type ret_type;
6818                         
6819                         ret_type = TypeManager.GetReferenceType (type);
6820                         
6821                         for (int i = 0; i < arg_count; i++){
6822                                 //args [i++] = a.Type;
6823                                 args [i] = TypeManager.int32_type;
6824                         }
6825                         
6826                         address = mb.GetArrayMethod (
6827                                 ea.Expr.Type, "Address",
6828                                 CallingConventions.HasThis |
6829                                 CallingConventions.Standard,
6830                                 ret_type, args);
6831
6832                         return address;
6833                 }
6834
6835                 //
6836                 // Load the array arguments into the stack.
6837                 //
6838                 // If we have been requested to cache the values (cached_locations array
6839                 // initialized), then load the arguments the first time and store them
6840                 // in locals.  otherwise load from local variables.
6841                 //
6842                 void LoadArrayAndArguments (EmitContext ec)
6843                 {
6844                         ILGenerator ig = ec.ig;
6845                         
6846                         if (cached_locations == null){
6847                                 ea.Expr.Emit (ec);
6848                                 foreach (Argument a in ea.Arguments){
6849                                         Type argtype = a.Expr.Type;
6850                                         
6851                                         a.Expr.Emit (ec);
6852                                         
6853                                         if (argtype == TypeManager.int64_type)
6854                                                 ig.Emit (OpCodes.Conv_Ovf_I);
6855                                         else if (argtype == TypeManager.uint64_type)
6856                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);
6857                                 }
6858                                 return;
6859                         }
6860
6861                         if (cached_locations [0] == null){
6862                                 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
6863                                 ea.Expr.Emit (ec);
6864                                 ig.Emit (OpCodes.Dup);
6865                                 cached_locations [0].Store (ec);
6866                                 
6867                                 int j = 1;
6868                                 
6869                                 foreach (Argument a in ea.Arguments){
6870                                         Type argtype = a.Expr.Type;
6871                                         
6872                                         cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
6873                                         a.Expr.Emit (ec);
6874                                         if (argtype == TypeManager.int64_type)
6875                                                 ig.Emit (OpCodes.Conv_Ovf_I);
6876                                         else if (argtype == TypeManager.uint64_type)
6877                                                 ig.Emit (OpCodes.Conv_Ovf_I_Un);
6878
6879                                         ig.Emit (OpCodes.Dup);
6880                                         cached_locations [j].Store (ec);
6881                                         j++;
6882                                 }
6883                                 return;
6884                         }
6885
6886                         foreach (LocalTemporary lt in cached_locations)
6887                                 lt.Emit (ec);
6888                 }
6889
6890                 public new void CacheTemporaries (EmitContext ec)
6891                 {
6892                         cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
6893                 }
6894                 
6895                 public override void Emit (EmitContext ec)
6896                 {
6897                         int rank = ea.Expr.Type.GetArrayRank ();
6898                         ILGenerator ig = ec.ig;
6899
6900                         LoadArrayAndArguments (ec);
6901                         
6902                         if (rank == 1)
6903                                 EmitLoadOpcode (ig, type);
6904                         else {
6905                                 MethodInfo method;
6906                                 
6907                                 method = FetchGetMethod ();
6908                                 ig.Emit (OpCodes.Call, method);
6909                         }
6910                 }
6911
6912                 public void EmitAssign (EmitContext ec, Expression source)
6913                 {
6914                         int rank = ea.Expr.Type.GetArrayRank ();
6915                         ILGenerator ig = ec.ig;
6916                         Type t = source.Type;
6917
6918                         LoadArrayAndArguments (ec);
6919
6920                         //
6921                         // The stobj opcode used by value types will need
6922                         // an address on the stack, not really an array/array
6923                         // pair
6924                         //
6925                         if (rank == 1){
6926                                 if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
6927                                     (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
6928                                         ig.Emit (OpCodes.Ldelema, t);
6929                         }
6930                         
6931                         source.Emit (ec);
6932
6933                         if (rank == 1)
6934                                 EmitStoreOpcode (ig, t);
6935                         else {
6936                                 ModuleBuilder mb = CodeGen.ModuleBuilder;
6937                                 int arg_count = ea.Arguments.Count;
6938                                 Type [] args = new Type [arg_count + 1];
6939                                 MethodInfo set;
6940                                 
6941                                 for (int i = 0; i < arg_count; i++){
6942                                         //args [i++] = a.Type;
6943                                         args [i] = TypeManager.int32_type;
6944                                 }
6945
6946                                 args [arg_count] = type;
6947                                 
6948                                 set = mb.GetArrayMethod (
6949                                         ea.Expr.Type, "Set",
6950                                         CallingConventions.HasThis |
6951                                         CallingConventions.Standard,
6952                                         TypeManager.void_type, args);
6953                                 
6954                                 ig.Emit (OpCodes.Call, set);
6955                         }
6956                 }
6957
6958                 public void AddressOf (EmitContext ec, AddressOp mode)
6959                 {
6960                         int rank = ea.Expr.Type.GetArrayRank ();
6961                         ILGenerator ig = ec.ig;
6962
6963                         LoadArrayAndArguments (ec);
6964
6965                         if (rank == 1){
6966                                 ig.Emit (OpCodes.Ldelema, type);
6967                         } else {
6968                                 MethodInfo address = FetchAddressMethod ();
6969                                 ig.Emit (OpCodes.Call, address);
6970                         }
6971                 }
6972         }
6973
6974         
6975         class Indexers {
6976                 public ArrayList properties;
6977                 static Hashtable map;
6978
6979                 static Indexers ()
6980                 {
6981                         map = new Hashtable ();
6982                 }
6983
6984                 Indexers ()
6985                 {
6986                         properties = new ArrayList ();
6987                 }
6988                                 
6989                 void Append (MemberInfo [] mi)
6990                 {
6991                         foreach (PropertyInfo property in mi){
6992                                 MethodInfo get, set;
6993                                 
6994                                 get = property.GetGetMethod (true);
6995                                 set = property.GetSetMethod (true);
6996                                 properties.Add (new Pair (get, set));
6997                         }
6998                 }
6999
7000                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7001                 {
7002                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
7003
7004                         MemberInfo [] mi = TypeManager.MemberLookup (
7005                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
7006                                 BindingFlags.Public | BindingFlags.Instance |
7007                                 BindingFlags.DeclaredOnly, p_name);
7008
7009                         if (mi == null || mi.Length == 0)
7010                                 return null;
7011
7012                         return mi;
7013                 }
7014                 
7015                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) 
7016                 {
7017                         Indexers ix = (Indexers) map [lookup_type];
7018                         
7019                         if (ix != null)
7020                                 return ix;
7021
7022                         Type copy = lookup_type;
7023                         while (copy != TypeManager.object_type && copy != null){
7024                                 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy);
7025
7026                                 if (mi != null){
7027                                         if (ix == null)
7028                                                 ix = new Indexers ();
7029
7030                                         ix.Append (mi);
7031                                 }
7032                                         
7033                                 copy = copy.BaseType;
7034                         }
7035
7036                         Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7037                         if (ifaces != null) {
7038                                 foreach (Type itype in ifaces) {
7039                                         MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype);
7040                                         if (mi != null){
7041                                                 if (ix == null)
7042                                                         ix = new Indexers ();
7043                                         
7044                                                 ix.Append (mi);
7045                                         }
7046                                 }
7047                         }
7048
7049                         return ix;
7050                 }
7051         }
7052
7053         /// <summary>
7054         ///   Expressions that represent an indexer call.
7055         /// </summary>
7056         public class IndexerAccess : Expression, IAssignMethod {
7057                 //
7058                 // Points to our "data" repository
7059                 //
7060                 MethodInfo get, set;
7061                 ArrayList set_arguments;
7062                 bool is_base_indexer;
7063
7064                 protected Type indexer_type;
7065                 protected Type current_type;
7066                 protected Expression instance_expr;
7067                 protected ArrayList arguments;
7068                 
7069                 public IndexerAccess (ElementAccess ea, Location loc)
7070                         : this (ea.Expr, false, loc)
7071                 {
7072                         this.arguments = ea.Arguments;
7073                 }
7074
7075                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7076                                          Location loc)
7077                 {
7078                         this.instance_expr = instance_expr;
7079                         this.is_base_indexer = is_base_indexer;
7080                         this.eclass = ExprClass.Value;
7081                         this.loc = loc;
7082                 }
7083
7084                 protected virtual bool CommonResolve (EmitContext ec)
7085                 {
7086                         indexer_type = instance_expr.Type;
7087                         current_type = ec.ContainerType;
7088
7089                         return true;
7090                 }
7091
7092                 public override Expression DoResolve (EmitContext ec)
7093                 {
7094                         ArrayList AllGetters = new ArrayList();
7095                         if (!CommonResolve (ec))
7096                                 return null;
7097
7098                         //
7099                         // Step 1: Query for all `Item' *properties*.  Notice
7100                         // that the actual methods are pointed from here.
7101                         //
7102                         // This is a group of properties, piles of them.  
7103
7104                         bool found_any = false, found_any_getters = false;
7105                         Type lookup_type = indexer_type;
7106
7107                         Indexers ilist;
7108                         ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
7109                         if (ilist != null) {
7110                                 found_any = true;
7111                                 if (ilist.properties != null) {
7112                                         foreach (Pair o in ilist.properties) {
7113                                                 if (o.First != null)
7114                                                         AllGetters.Add(o.First);
7115                                         }
7116                                 }
7117                         }
7118
7119                         if (AllGetters.Count > 0) {
7120                                 found_any_getters = true;
7121                                 get = (MethodInfo) Invocation.OverloadResolve (
7122                                         ec, new MethodGroupExpr (AllGetters, loc), arguments, loc);
7123                         }
7124
7125                         if (!found_any) {
7126                                 Report.Error (21, loc,
7127                                               "Type `" + TypeManager.CSharpName (indexer_type) +
7128                                               "' does not have any indexers defined");
7129                                 return null;
7130                         }
7131
7132                         if (!found_any_getters) {
7133                                 Error (154, "indexer can not be used in this context, because " +
7134                                        "it lacks a `get' accessor");
7135                                 return null;
7136                         }
7137
7138                         if (get == null) {
7139                                 Error (1501, "No Overload for method `this' takes `" +
7140                                        arguments.Count + "' arguments");
7141                                 return null;
7142                         }
7143
7144                         //
7145                         // Only base will allow this invocation to happen.
7146                         //
7147                         if (get.IsAbstract && this is BaseIndexerAccess){
7148                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get));
7149                                 return null;
7150                         }
7151
7152                         type = get.ReturnType;
7153                         if (type.IsPointer && !ec.InUnsafe){
7154                                 UnsafeError (loc);
7155                                 return null;
7156                         }
7157                         
7158                         eclass = ExprClass.IndexerAccess;
7159                         return this;
7160                 }
7161
7162                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7163                 {
7164                         ArrayList AllSetters = new ArrayList();
7165                         if (!CommonResolve (ec))
7166                                 return null;
7167
7168                         Type right_type = right_side.Type;
7169
7170                         bool found_any = false, found_any_setters = false;
7171
7172                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
7173                         if (ilist != null) {
7174                                 found_any = true;
7175                                 if (ilist.properties != null) {
7176                                         foreach (Pair o in ilist.properties) {
7177                                                 if (o.Second != null)
7178                                                         AllSetters.Add(o.Second);
7179                                         }
7180                                 }
7181                         }
7182                         if (AllSetters.Count > 0) {
7183                                 found_any_setters = true;
7184                                 set_arguments = (ArrayList) arguments.Clone ();
7185                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7186                                 set = (MethodInfo) Invocation.OverloadResolve (
7187                                         ec, new MethodGroupExpr (AllSetters, loc),
7188                                         set_arguments, loc);
7189                         }
7190
7191                         if (!found_any) {
7192                                 Report.Error (21, loc,
7193                                               "Type `" + TypeManager.CSharpName (indexer_type) +
7194                                               "' does not have any indexers defined");
7195                                 return null;
7196                         }
7197
7198                         if (!found_any_setters) {
7199                                 Error (154, "indexer can not be used in this context, because " +
7200                                        "it lacks a `set' accessor");
7201                                 return null;
7202                         }
7203
7204                         if (set == null) {
7205                                 Error (1501, "No Overload for method `this' takes `" +
7206                                        arguments.Count + "' arguments");
7207                                 return null;
7208                         }
7209
7210                         //
7211                         // Only base will allow this invocation to happen.
7212                         //
7213                         if (set.IsAbstract && this is BaseIndexerAccess){
7214                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set));
7215                                 return null;
7216                         }
7217
7218                         //
7219                         // Now look for the actual match in the list of indexers to set our "return" type
7220                         //
7221                         type = TypeManager.void_type;   // default value
7222                         foreach (Pair t in ilist.properties){
7223                                 if (t.Second == set){
7224                                         if (t.First != null)
7225                                                 type = ((MethodInfo) t.First).ReturnType;
7226                                         break;
7227                                 }
7228                         }
7229                         
7230                         eclass = ExprClass.IndexerAccess;
7231                         return this;
7232                 }
7233                 
7234                 public override void Emit (EmitContext ec)
7235                 {
7236                         Invocation.EmitCall (ec, false, false, instance_expr, get, arguments, loc);
7237                 }
7238
7239                 //
7240                 // source is ignored, because we already have a copy of it from the
7241                 // LValue resolution and we have already constructed a pre-cached
7242                 // version of the arguments (ea.set_arguments);
7243                 //
7244                 public void EmitAssign (EmitContext ec, Expression source)
7245                 {
7246                         Invocation.EmitCall (ec, false, false, instance_expr, set, set_arguments, loc);
7247                 }
7248         }
7249
7250         /// <summary>
7251         ///   The base operator for method names
7252         /// </summary>
7253         public class BaseAccess : Expression {
7254                 string member;
7255                 
7256                 public BaseAccess (string member, Location l)
7257                 {
7258                         this.member = member;
7259                         loc = l;
7260                 }
7261
7262                 public override Expression DoResolve (EmitContext ec)
7263                 {
7264                         Expression c = CommonResolve (ec);
7265
7266                         if (c == null)
7267                                 return null;
7268
7269                         //
7270                         // MethodGroups use this opportunity to flag an error on lacking ()
7271                         //
7272                         if (!(c is MethodGroupExpr))
7273                                 return c.Resolve (ec);
7274                         return c;
7275                 }
7276
7277                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7278                 {
7279                         Expression c = CommonResolve (ec);
7280
7281                         if (c == null)
7282                                 return null;
7283
7284                         //
7285                         // MethodGroups use this opportunity to flag an error on lacking ()
7286                         //
7287                         if (! (c is MethodGroupExpr))
7288                                 return c.DoResolveLValue (ec, right_side);
7289
7290                         return c;
7291                 }
7292
7293                 Expression CommonResolve (EmitContext ec)
7294                 {
7295                         Expression member_lookup;
7296                         Type current_type = ec.ContainerType;
7297                         Type base_type = current_type.BaseType;
7298                         Expression e;
7299
7300                         if (ec.IsStatic){
7301                                 Error (1511, "Keyword base is not allowed in static method");
7302                                 return null;
7303                         }
7304                         
7305                         member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type, member,
7306                                                       AllMemberTypes, AllBindingFlags, loc);
7307                         if (member_lookup == null) {
7308                                 MemberLookupFailed (ec, base_type, base_type, member, null, loc);
7309                                 return null;
7310                         }
7311
7312                         Expression left;
7313                         
7314                         if (ec.IsStatic)
7315                                 left = new TypeExpr (base_type, loc);
7316                         else
7317                                 left = ec.This;
7318                         
7319                         e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
7320
7321                         if (e is PropertyExpr){
7322                                 PropertyExpr pe = (PropertyExpr) e;
7323
7324                                 pe.IsBase = true;
7325                         }
7326
7327                         return e;
7328                 }
7329
7330                 public override void Emit (EmitContext ec)
7331                 {
7332                         throw new Exception ("Should never be called"); 
7333                 }
7334         }
7335
7336         /// <summary>
7337         ///   The base indexer operator
7338         /// </summary>
7339         public class BaseIndexerAccess : IndexerAccess {
7340                 public BaseIndexerAccess (ArrayList args, Location loc)
7341                         : base (null, true, loc)
7342                 {
7343                         arguments = new ArrayList ();
7344                         foreach (Expression tmp in args)
7345                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
7346                 }
7347
7348                 protected override bool CommonResolve (EmitContext ec)
7349                 {
7350                         instance_expr = ec.This;
7351
7352                         current_type = ec.ContainerType.BaseType;
7353                         indexer_type = current_type;
7354
7355                         foreach (Argument a in arguments){
7356                                 if (!a.Resolve (ec, loc))
7357                                         return false;
7358                         }
7359
7360                         return true;
7361                 }
7362         }
7363         
7364         /// <summary>
7365         ///   This class exists solely to pass the Type around and to be a dummy
7366         ///   that can be passed to the conversion functions (this is used by
7367         ///   foreach implementation to typecast the object return value from
7368         ///   get_Current into the proper type.  All code has been generated and
7369         ///   we only care about the side effect conversions to be performed
7370         ///
7371         ///   This is also now used as a placeholder where a no-action expression
7372         ///   is needed (the `New' class).
7373         /// </summary>
7374         public class EmptyExpression : Expression {
7375                 public EmptyExpression ()
7376                 {
7377                         type = TypeManager.object_type;
7378                         eclass = ExprClass.Value;
7379                         loc = Location.Null;
7380                 }
7381
7382                 public EmptyExpression (Type t)
7383                 {
7384                         type = t;
7385                         eclass = ExprClass.Value;
7386                         loc = Location.Null;
7387                 }
7388                 
7389                 public override Expression DoResolve (EmitContext ec)
7390                 {
7391                         return this;
7392                 }
7393
7394                 public override void Emit (EmitContext ec)
7395                 {
7396                         // nothing, as we only exist to not do anything.
7397                 }
7398
7399                 //
7400                 // This is just because we might want to reuse this bad boy
7401                 // instead of creating gazillions of EmptyExpressions.
7402                 // (CanConvertImplicit uses it)
7403                 //
7404                 public void SetType (Type t)
7405                 {
7406                         type = t;
7407                 }
7408         }
7409
7410         public class UserCast : Expression {
7411                 MethodBase method;
7412                 Expression source;
7413                 
7414                 public UserCast (MethodInfo method, Expression source, Location l)
7415                 {
7416                         this.method = method;
7417                         this.source = source;
7418                         type = method.ReturnType;
7419                         eclass = ExprClass.Value;
7420                         loc = l;
7421                 }
7422
7423                 public override Expression DoResolve (EmitContext ec)
7424                 {
7425                         //
7426                         // We are born fully resolved
7427                         //
7428                         return this;
7429                 }
7430
7431                 public override void Emit (EmitContext ec)
7432                 {
7433                         ILGenerator ig = ec.ig;
7434
7435                         source.Emit (ec);
7436                         
7437                         if (method is MethodInfo)
7438                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
7439                         else
7440                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
7441
7442                 }
7443         }
7444
7445         // <summary>
7446         //   This class is used to "construct" the type during a typecast
7447         //   operation.  Since the Type.GetType class in .NET can parse
7448         //   the type specification, we just use this to construct the type
7449         //   one bit at a time.
7450         // </summary>
7451         public class ComposedCast : Expression {
7452                 Expression left;
7453                 string dim;
7454                 
7455                 public ComposedCast (Expression left, string dim, Location l)
7456                 {
7457                         this.left = left;
7458                         this.dim = dim;
7459                         loc = l;
7460                 }
7461
7462                 public override Expression ResolveAsTypeStep (EmitContext ec)
7463                 {
7464                         Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
7465                         if (ltype == null)
7466                                 return null;
7467
7468                         //
7469                         // ltype.Fullname is already fully qualified, so we can skip
7470                         // a lot of probes, and go directly to TypeManager.LookupType
7471                         //
7472                         string cname = ltype.FullName + dim;
7473                         type = TypeManager.LookupTypeDirect (cname);
7474                         if (type == null){
7475                                 //
7476                                 // For arrays of enumerations we are having a problem
7477                                 // with the direct lookup.  Need to investigate.
7478                                 //
7479                                 // For now, fall back to the full lookup in that case.
7480                                 //
7481                                 type = RootContext.LookupType (
7482                                         ec.DeclSpace, cname, false, loc);
7483
7484                                 if (type == null)
7485                                         return null;
7486                         }
7487
7488                         if (!ec.ResolvingTypeTree){
7489                                 //
7490                                 // If the above flag is set, this is being invoked from the ResolveType function.
7491                                 // Upper layers take care of the type validity in this context.
7492                                 //
7493                         if (!ec.InUnsafe && type.IsPointer){
7494                                 UnsafeError (loc);
7495                                 return null;
7496                         }
7497                         }
7498                         
7499                         eclass = ExprClass.Type;
7500                         return this;
7501                 }
7502
7503                 public override Expression DoResolve (EmitContext ec)
7504                 {
7505                         return ResolveAsTypeStep (ec);
7506                 }
7507
7508                 public override void Emit (EmitContext ec)
7509                 {
7510                         throw new Exception ("This should never be called");
7511                 }
7512
7513                 public override string ToString ()
7514                 {
7515                         return left + dim;
7516                 }
7517         }
7518
7519         //
7520         // This class is used to represent the address of an array, used
7521         // only by the Fixed statement, this is like the C "&a [0]" construct.
7522         //
7523         public class ArrayPtr : Expression {
7524                 Expression array;
7525                 
7526                 public ArrayPtr (Expression array, Location l)
7527                 {
7528                         Type array_type = array.Type.GetElementType ();
7529
7530                         this.array = array;
7531
7532                         type = TypeManager.GetPointerType (array_type);
7533                         eclass = ExprClass.Value;
7534                         loc = l;
7535                 }
7536
7537                 public override void Emit (EmitContext ec)
7538                 {
7539                         ILGenerator ig = ec.ig;
7540                         
7541                         array.Emit (ec);
7542                         IntLiteral.EmitInt (ig, 0);
7543                         ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());
7544                 }
7545
7546                 public override Expression DoResolve (EmitContext ec)
7547                 {
7548                         //
7549                         // We are born fully resolved
7550                         //
7551                         return this;
7552                 }
7553         }
7554
7555         //
7556         // Used by the fixed statement
7557         //
7558         public class StringPtr : Expression {
7559                 LocalBuilder b;
7560                 
7561                 public StringPtr (LocalBuilder b, Location l)
7562                 {
7563                         this.b = b;
7564                         eclass = ExprClass.Value;
7565                         type = TypeManager.char_ptr_type;
7566                         loc = l;
7567                 }
7568
7569                 public override Expression DoResolve (EmitContext ec)
7570                 {
7571                         // This should never be invoked, we are born in fully
7572                         // initialized state.
7573
7574                         return this;
7575                 }
7576
7577                 public override void Emit (EmitContext ec)
7578                 {
7579                         ILGenerator ig = ec.ig;
7580
7581                         ig.Emit (OpCodes.Ldloc, b);
7582                         ig.Emit (OpCodes.Conv_I);
7583                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
7584                         ig.Emit (OpCodes.Add);
7585                 }
7586         }
7587         
7588         //
7589         // Implements the `stackalloc' keyword
7590         //
7591         public class StackAlloc : Expression {
7592                 Type otype;
7593                 Expression t;
7594                 Expression count;
7595                 
7596                 public StackAlloc (Expression type, Expression count, Location l)
7597                 {
7598                         t = type;
7599                         this.count = count;
7600                         loc = l;
7601                 }
7602
7603                 public override Expression DoResolve (EmitContext ec)
7604                 {
7605                         count = count.Resolve (ec);
7606                         if (count == null)
7607                                 return null;
7608                         
7609                         if (count.Type != TypeManager.int32_type){
7610                                 count = ConvertImplicitRequired (ec, count, TypeManager.int32_type, loc);
7611                                 if (count == null)
7612                                         return null;
7613                         }
7614
7615                         if (ec.InCatch || ec.InFinally){
7616                                 Error (255,
7617                                               "stackalloc can not be used in a catch or finally block");
7618                                 return null;
7619                         }
7620
7621                         otype = ec.DeclSpace.ResolveType (t, false, loc);
7622
7623                         if (otype == null)
7624                                 return null;
7625
7626                         if (!TypeManager.VerifyUnManaged (otype, loc))
7627                                 return null;
7628
7629                         type = TypeManager.GetPointerType (otype);
7630                         eclass = ExprClass.Value;
7631
7632                         return this;
7633                 }
7634
7635                 public override void Emit (EmitContext ec)
7636                 {
7637                         int size = GetTypeSize (otype);
7638                         ILGenerator ig = ec.ig;
7639                                 
7640                         if (size == 0)
7641                                 ig.Emit (OpCodes.Sizeof, otype);
7642                         else
7643                                 IntConstant.EmitInt (ig, size);
7644                         count.Emit (ec);
7645                         ig.Emit (OpCodes.Mul);
7646                         ig.Emit (OpCodes.Localloc);
7647                 }
7648         }
7649 }