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