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