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