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