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