Test case for CheckedListBox and CheckBox
[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 ("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                 Expression ResolveOperator (EmitContext ec)
2264                 {
2265                         Type l = left.Type;
2266                         Type r = right.Type;
2267
2268                         if (oper == Operator.Equality || oper == Operator.Inequality){
2269                                 //
2270                                 // Optimize out call to op_Equality in a few cases.
2271                                 //
2272                                 if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
2273                                     (r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
2274                                   
2275                                         Type = TypeManager.bool_type;
2276                                         
2277                                         return this;
2278                                 }
2279
2280                                 // IntPtr equality
2281                                 if (l == TypeManager.intptr_type && r == TypeManager.intptr_type) {
2282                                         Type = TypeManager.bool_type;
2283                                         
2284                                         return this;
2285                                 }
2286                         }
2287
2288                         //
2289                         // Do not perform operator overload resolution when both sides are
2290                         // built-in types
2291                         //
2292                         if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))){
2293                                 //
2294                                 // Step 1: Perform Operator Overload location
2295                                 //
2296                                 Expression left_expr, right_expr;
2297                                 
2298                                 string op = oper_names [(int) oper];
2299                                 
2300                                 MethodGroupExpr union;
2301                                 left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
2302                                 if (r != l){
2303                                         right_expr = MemberLookup (
2304                                                 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
2305                                         union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
2306                                 } else
2307                                         union = (MethodGroupExpr) left_expr;
2308                                 
2309                                 if (union != null) {
2310                                         ArrayList args = new ArrayList (2);
2311                                         args.Add (new Argument (left, Argument.AType.Expression));
2312                                         args.Add (new Argument (right, Argument.AType.Expression));
2313                                         
2314                                         MethodBase method = Invocation.OverloadResolve (
2315                                                 ec, union, args, true, Location.Null);
2316
2317                                         if (method != null) {
2318                                                 MethodInfo mi = (MethodInfo) method;
2319                                                 
2320                                                 return new BinaryMethod (mi.ReturnType, method, args);
2321                                         }
2322                                 }
2323                         }
2324                         
2325                         //
2326                         // Step 0: String concatenation (because overloading will get this wrong)
2327                         //
2328                         if (oper == Operator.Addition){
2329                                 //
2330                                 // If any of the arguments is a string, cast to string
2331                                 //
2332                                 
2333                                 // Simple constant folding
2334                                 if (left is StringConstant && right is StringConstant)
2335                                         return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value);
2336                                 
2337                                 if (l == TypeManager.string_type || r == TypeManager.string_type) {
2338
2339                                         if (r == TypeManager.void_type || l == TypeManager.void_type) {
2340                                                 Error_OperatorCannotBeApplied ();
2341                                                 return null;
2342                                         }
2343                                         
2344                                         // try to fold it in on the left
2345                                         if (left is StringConcat) {
2346
2347                                                 //
2348                                                 // We have to test here for not-null, since we can be doubly-resolved
2349                                                 // take care of not appending twice
2350                                                 //
2351                                                 if (type == null){
2352                                                         type = TypeManager.string_type;
2353                                                         ((StringConcat) left).Append (ec, right);
2354                                                         return left.Resolve (ec);
2355                                                 } else {
2356                                                         return left;
2357                                                 }
2358                                         }
2359                                         
2360                                         // Otherwise, start a new concat expression
2361                                         return new StringConcat (ec, loc, left, right).Resolve (ec);
2362                                 }
2363
2364                                 //
2365                                 // Transform a + ( - b) into a - b
2366                                 //
2367                                 if (right is Unary){
2368                                         Unary right_unary = (Unary) right;
2369
2370                                         if (right_unary.Oper == Unary.Operator.UnaryNegation){
2371                                                 oper = Operator.Subtraction;
2372                                                 right = right_unary.Expr;
2373                                                 r = right.Type;
2374                                         }
2375                                 }
2376                         }
2377
2378                         if (oper == Operator.Equality || oper == Operator.Inequality){
2379                                 if (l == TypeManager.bool_type || r == TypeManager.bool_type){
2380                                         if (r != TypeManager.bool_type || l != TypeManager.bool_type){
2381                                                 Error_OperatorCannotBeApplied ();
2382                                                 return null;
2383                                         }
2384                                         
2385                                         type = TypeManager.bool_type;
2386                                         return this;
2387                                 }
2388
2389                                 if (l.IsPointer || r.IsPointer) {
2390                                         if (l.IsPointer && r.IsPointer) {
2391                                                 type = TypeManager.bool_type;
2392                                                 return this;
2393                                         }
2394
2395                                         if (l.IsPointer && r == TypeManager.null_type) {
2396                                                 right = new EmptyCast (NullPointer.Null, l);
2397                                                 type = TypeManager.bool_type;
2398                                                 return this;
2399                                         }
2400
2401                                         if (r.IsPointer && l == TypeManager.null_type) {
2402                                                 left = new EmptyCast (NullPointer.Null, r);
2403                                                 type = TypeManager.bool_type;
2404                                                 return this;
2405                                         }
2406                                 }
2407
2408                                 //
2409                                 // operator != (object a, object b)
2410                                 // operator == (object a, object b)
2411                                 //
2412                                 // For this to be used, both arguments have to be reference-types.
2413                                 // Read the rationale on the spec (14.9.6)
2414                                 //
2415                                 // Also, if at compile time we know that the classes do not inherit
2416                                 // one from the other, then we catch the error there.
2417                                 //
2418                                 if (!(l.IsValueType || r.IsValueType)){
2419                                         type = TypeManager.bool_type;
2420
2421                                         if (l == r)
2422                                                 return this;
2423                                         
2424                                         if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
2425                                                 return this;
2426
2427                                         //
2428                                         // Also, a standard conversion must exist from either one
2429                                         //
2430                                         if (!(Convert.ImplicitStandardConversionExists (ec, left, r) ||
2431                                               Convert.ImplicitStandardConversionExists (ec, right, l))){
2432                                                 Error_OperatorCannotBeApplied ();
2433                                                 return null;
2434                                         }
2435                                         //
2436                                         // We are going to have to convert to an object to compare
2437                                         //
2438                                         if (l != TypeManager.object_type)
2439                                                 left = new EmptyCast (left, TypeManager.object_type);
2440                                         if (r != TypeManager.object_type)
2441                                                 right = new EmptyCast (right, TypeManager.object_type);
2442
2443                                         //
2444                                         // FIXME: CSC here catches errors cs254 and cs252
2445                                         //
2446                                         return this;
2447                                 }
2448
2449                                 //
2450                                 // One of them is a valuetype, but the other one is not.
2451                                 //
2452                                 if (!l.IsValueType || !r.IsValueType) {
2453                                         Error_OperatorCannotBeApplied ();
2454                                         return null;
2455                                 }
2456                         }
2457
2458                         // Only perform numeric promotions on:
2459                         // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
2460                         //
2461                         if (oper == Operator.Addition || oper == Operator.Subtraction) {
2462                                 if (l.IsSubclassOf (TypeManager.delegate_type)){
2463                                         if (((right.eclass == ExprClass.MethodGroup) ||
2464                                              (r == TypeManager.anonymous_method_type))){
2465                                                 if ((RootContext.Version != LanguageVersion.ISO_1)){
2466                                                         Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
2467                                                         if (tmp == null)
2468                                                                 return null;
2469                                                         right = tmp;
2470                                                         r = right.Type;
2471                                                 }
2472                                         }
2473                                         
2474                                         if (r.IsSubclassOf (TypeManager.delegate_type)){
2475                                                 MethodInfo method;
2476                                                 ArrayList args = new ArrayList (2);
2477                                                 
2478                                                 args = new ArrayList (2);
2479                                                 args.Add (new Argument (left, Argument.AType.Expression));
2480                                                 args.Add (new Argument (right, Argument.AType.Expression));
2481                                                 
2482                                                 if (oper == Operator.Addition)
2483                                                         method = TypeManager.delegate_combine_delegate_delegate;
2484                                                 else
2485                                                         method = TypeManager.delegate_remove_delegate_delegate;
2486                                                 
2487                                                 if (l != r) {
2488                                                         Error_OperatorCannotBeApplied ();
2489                                                         return null;
2490                                                 }
2491                                                 
2492                                                 return new BinaryDelegate (l, method, args);
2493                                         }
2494                                 }
2495                                 
2496                                 //
2497                                 // Pointer arithmetic:
2498                                 //
2499                                 // T* operator + (T* x, int y);
2500                                 // T* operator + (T* x, uint y);
2501                                 // T* operator + (T* x, long y);
2502                                 // T* operator + (T* x, ulong y);
2503                                 //
2504                                 // T* operator + (int y,   T* x);
2505                                 // T* operator + (uint y,  T *x);
2506                                 // T* operator + (long y,  T *x);
2507                                 // T* operator + (ulong y, T *x);
2508                                 //
2509                                 // T* operator - (T* x, int y);
2510                                 // T* operator - (T* x, uint y);
2511                                 // T* operator - (T* x, long y);
2512                                 // T* operator - (T* x, ulong y);
2513                                 //
2514                                 // long operator - (T* x, T *y)
2515                                 //
2516                                 if (l.IsPointer){
2517                                         if (r.IsPointer && oper == Operator.Subtraction){
2518                                                 if (r == l)
2519                                                         return new PointerArithmetic (
2520                                                                 false, left, right, TypeManager.int64_type,
2521                                                                 loc).Resolve (ec);
2522                                         } else {
2523                                                 Expression t = Make32or64 (ec, right);
2524                                                 if (t != null)
2525                                                         return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
2526                                         }
2527                                 } else if (r.IsPointer && oper == Operator.Addition){
2528                                         Expression t = Make32or64 (ec, left);
2529                                         if (t != null)
2530                                                 return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
2531                                 }
2532                         }
2533                         
2534                         //
2535                         // Enumeration operators
2536                         //
2537                         bool lie = TypeManager.IsEnumType (l);
2538                         bool rie = TypeManager.IsEnumType (r);
2539                         if (lie || rie){
2540                                 Expression temp;
2541
2542                                 // U operator - (E e, E f)
2543                                 if (lie && rie){
2544                                         if (oper == Operator.Subtraction){
2545                                                 if (l == r){
2546                                                         type = TypeManager.EnumToUnderlying (l);
2547                                                         return this;
2548                                                 }
2549                                                 Error_OperatorCannotBeApplied ();
2550                                                 return null;
2551                                         }
2552                                 }
2553                                         
2554                                 //
2555                                 // operator + (E e, U x)
2556                                 // operator - (E e, U x)
2557                                 //
2558                                 if (oper == Operator.Addition || oper == Operator.Subtraction){
2559                                         Type enum_type = lie ? l : r;
2560                                         Type other_type = lie ? r : l;
2561                                         Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
2562                                         
2563                                         if (underlying_type != other_type){
2564                                                 temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
2565                                                 if (temp != null){
2566                                                         if (lie)
2567                                                                 right = temp;
2568                                                         else
2569                                                                 left = temp;
2570                                                         type = enum_type;
2571                                                         return this;
2572                                                 }
2573                                                         
2574                                                 Error_OperatorCannotBeApplied ();
2575                                                 return null;
2576                                         }
2577
2578                                         type = enum_type;
2579                                         return this;
2580                                 }
2581                                 
2582                                 if (!rie){
2583                                         temp = Convert.ImplicitConversion (ec, right, l, loc);
2584                                         if (temp != null)
2585                                                 right = temp;
2586                                         else {
2587                                                 Error_OperatorCannotBeApplied ();
2588                                                 return null;
2589                                         }
2590                                 } if (!lie){
2591                                         temp = Convert.ImplicitConversion (ec, left, r, loc);
2592                                         if (temp != null){
2593                                                 left = temp;
2594                                                 l = r;
2595                                         } else {
2596                                                 Error_OperatorCannotBeApplied ();
2597                                                 return null;
2598                                         }
2599                                 }
2600
2601                                 if (oper == Operator.Equality || oper == Operator.Inequality ||
2602                                     oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
2603                                     oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
2604                                         if (left.Type != right.Type){
2605                                                 Error_OperatorCannotBeApplied ();
2606                                                 return null;
2607                                         }
2608                                         type = TypeManager.bool_type;
2609                                         return this;
2610                                 }
2611
2612                                 if (oper == Operator.BitwiseAnd ||
2613                                     oper == Operator.BitwiseOr ||
2614                                     oper == Operator.ExclusiveOr){
2615                                         if (left.Type != right.Type){
2616                                                 Error_OperatorCannotBeApplied ();
2617                                                 return null;
2618                                         }
2619                                         type = l;
2620                                         return this;
2621                                 }
2622                                 Error_OperatorCannotBeApplied ();
2623                                 return null;
2624                         }
2625                         
2626                         if (oper == Operator.LeftShift || oper == Operator.RightShift)
2627                                 return CheckShiftArguments (ec);
2628
2629                         if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
2630                                 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2631                                         type = TypeManager.bool_type;
2632                                         return this;
2633                                 }
2634
2635                                 if (l != r) {
2636                                         Error_OperatorCannotBeApplied ();
2637                                         return null;
2638                                 }
2639
2640                                 Expression e = new ConditionalLogicalOperator (
2641                                         oper == Operator.LogicalAnd, left, right, l, loc);
2642                                 return e.Resolve (ec);
2643                         } 
2644
2645                         //
2646                         // operator & (bool x, bool y)
2647                         // operator | (bool x, bool y)
2648                         // operator ^ (bool x, bool y)
2649                         //
2650                         if (l == TypeManager.bool_type && r == TypeManager.bool_type){
2651                                 if (oper == Operator.BitwiseAnd ||
2652                                     oper == Operator.BitwiseOr ||
2653                                     oper == Operator.ExclusiveOr){
2654                                         type = l;
2655                                         return this;
2656                                 }
2657                         }
2658                         
2659                         //
2660                         // Pointer comparison
2661                         //
2662                         if (l.IsPointer && r.IsPointer){
2663                                 if (oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2664                                     oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2665                                         type = TypeManager.bool_type;
2666                                         return this;
2667                                 }
2668                         }
2669                         
2670                         //
2671                         // This will leave left or right set to null if there is an error
2672                         //
2673                         bool check_user_conv = is_user_defined (l) && is_user_defined (r);
2674                         DoNumericPromotions (ec, l, r, check_user_conv);
2675                         if (left == null || right == null){
2676                                 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2677                                 return null;
2678                         }
2679
2680                         //
2681                         // reload our cached types if required
2682                         //
2683                         l = left.Type;
2684                         r = right.Type;
2685                         
2686                         if (oper == Operator.BitwiseAnd ||
2687                             oper == Operator.BitwiseOr ||
2688                             oper == Operator.ExclusiveOr){
2689                                 if (l == r){
2690                                         if (((l == TypeManager.int32_type) ||
2691                                              (l == TypeManager.uint32_type) ||
2692                                              (l == TypeManager.short_type) ||
2693                                              (l == TypeManager.ushort_type) ||
2694                                              (l == TypeManager.int64_type) ||
2695                                              (l == TypeManager.uint64_type))){
2696                                                 type = l;
2697                                         } else {
2698                                                 Error_OperatorCannotBeApplied ();
2699                                                 return null;
2700                                         }
2701                                 } else {
2702                                         Error_OperatorCannotBeApplied ();
2703                                         return null;
2704                                 }
2705                         }
2706
2707                         if (oper == Operator.Equality ||
2708                             oper == Operator.Inequality ||
2709                             oper == Operator.LessThanOrEqual ||
2710                             oper == Operator.LessThan ||
2711                             oper == Operator.GreaterThanOrEqual ||
2712                             oper == Operator.GreaterThan){
2713                                 type = TypeManager.bool_type;
2714                         }
2715
2716                         return this;
2717                 }
2718
2719                 public override Expression DoResolve (EmitContext ec)
2720                 {
2721                         if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
2722                                 left = ((ParenthesizedExpression) left).Expr;
2723                                 left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
2724                                 if (left == null)
2725                                         return null;
2726
2727                                 if (left.eclass == ExprClass.Type) {
2728                                         Error (75, "To cast a negative value, you must enclose the value in parentheses");
2729                                         return null;
2730                                 }
2731                         } else
2732                                 left = left.Resolve (ec);
2733
2734                         if (left == null)
2735                                 return null;
2736
2737                         Constant lc = left as Constant;
2738                         if (lc != null && lc.Type == TypeManager.bool_type && 
2739                                 ((oper == Operator.LogicalAnd && (bool)lc.GetValue () == false) ||
2740                                  (oper == Operator.LogicalOr && (bool)lc.GetValue () == true))) {
2741
2742                                 // TODO: make a sense to resolve unreachable expression as we do for statement
2743                                 Report.Warning (429, 4, loc, "Unreachable expression code detected");
2744                                 return left;
2745                         }
2746
2747                         right = right.Resolve (ec);
2748                         if (right == null)
2749                                 return null;
2750
2751                         eclass = ExprClass.Value;
2752
2753                         Constant rc = right as Constant;
2754
2755                         if (oper == Operator.BitwiseAnd) {
2756                                 if (rc != null && rc.IsZeroInteger) {
2757                                         return lc is EnumConstant ?
2758                                                 new EnumConstant (rc, lc.Type):
2759                                                 rc;
2760                                 }
2761
2762                                 if (lc != null && lc.IsZeroInteger) {
2763                                         return rc is EnumConstant ?
2764                                                 new EnumConstant (lc, rc.Type):
2765                                                 lc;
2766                                 }
2767                         }
2768
2769                         if (rc != null && lc != null){
2770                                 Expression e = ConstantFold.BinaryFold (
2771                                         ec, oper, lc, rc, loc);
2772                                 if (e != null)
2773                                         return e;
2774                         }
2775
2776                         return ResolveOperator (ec);
2777                 }
2778
2779                 /// <remarks>
2780                 ///   EmitBranchable is called from Statement.EmitBoolExpression in the
2781                 ///   context of a conditional bool expression.  This function will return
2782                 ///   false if it is was possible to use EmitBranchable, or true if it was.
2783                 ///
2784                 ///   The expression's code is generated, and we will generate a branch to `target'
2785                 ///   if the resulting expression value is equal to isTrue
2786                 /// </remarks>
2787                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2788                 {
2789                         ILGenerator ig = ec.ig;
2790
2791                         //
2792                         // This is more complicated than it looks, but its just to avoid
2793                         // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2794                         // but on top of that we want for == and != to use a special path
2795                         // if we are comparing against null
2796                         //
2797                         if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2798                                 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2799                                 
2800                                 //
2801                                 // put the constant on the rhs, for simplicity
2802                                 //
2803                                 if (left is Constant) {
2804                                         Expression swap = right;
2805                                         right = left;
2806                                         left = swap;
2807                                 }
2808                                 
2809                                 if (((Constant) right).IsZeroInteger) {
2810                                         left.Emit (ec);
2811                                         if (my_on_true)
2812                                                 ig.Emit (OpCodes.Brtrue, target);
2813                                         else
2814                                                 ig.Emit (OpCodes.Brfalse, target);
2815                                         
2816                                         return;
2817                                 } else if (right is BoolConstant) {
2818                                         left.Emit (ec);
2819                                         if (my_on_true != ((BoolConstant) right).Value)
2820                                                 ig.Emit (OpCodes.Brtrue, target);
2821                                         else
2822                                                 ig.Emit (OpCodes.Brfalse, target);
2823                                         
2824                                         return;
2825                                 }
2826
2827                         } else if (oper == Operator.LogicalAnd) {
2828
2829                                 if (onTrue) {
2830                                         Label tests_end = ig.DefineLabel ();
2831                                         
2832                                         left.EmitBranchable (ec, tests_end, false);
2833                                         right.EmitBranchable (ec, target, true);
2834                                         ig.MarkLabel (tests_end);                                       
2835                                 } else {
2836                                         left.EmitBranchable (ec, target, false);
2837                                         right.EmitBranchable (ec, target, false);
2838                                 }
2839                                 
2840                                 return;
2841                                 
2842                         } else if (oper == Operator.LogicalOr){
2843                                 if (onTrue) {
2844                                         left.EmitBranchable (ec, target, true);
2845                                         right.EmitBranchable (ec, target, true);
2846                                         
2847                                 } else {
2848                                         Label tests_end = ig.DefineLabel ();
2849                                         left.EmitBranchable (ec, tests_end, true);
2850                                         right.EmitBranchable (ec, target, false);
2851                                         ig.MarkLabel (tests_end);
2852                                 }
2853                                 
2854                                 return;
2855                                 
2856                         } else if (!(oper == Operator.LessThan        || oper == Operator.GreaterThan ||
2857                                      oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2858                                      oper == Operator.Equality        || oper == Operator.Inequality)) {
2859                                 base.EmitBranchable (ec, target, onTrue);
2860                                 return;
2861                         }
2862                         
2863                         left.Emit (ec);
2864                         right.Emit (ec);
2865
2866                         Type t = left.Type;
2867                         bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2868                         
2869                         switch (oper){
2870                         case Operator.Equality:
2871                                 if (onTrue)
2872                                         ig.Emit (OpCodes.Beq, target);
2873                                 else
2874                                         ig.Emit (OpCodes.Bne_Un, target);
2875                                 break;
2876
2877                         case Operator.Inequality:
2878                                 if (onTrue)
2879                                         ig.Emit (OpCodes.Bne_Un, target);
2880                                 else
2881                                         ig.Emit (OpCodes.Beq, target);
2882                                 break;
2883
2884                         case Operator.LessThan:
2885                                 if (onTrue)
2886                                         if (isUnsigned)
2887                                                 ig.Emit (OpCodes.Blt_Un, target);
2888                                         else
2889                                                 ig.Emit (OpCodes.Blt, target);
2890                                 else
2891                                         if (isUnsigned)
2892                                                 ig.Emit (OpCodes.Bge_Un, target);
2893                                         else
2894                                                 ig.Emit (OpCodes.Bge, target);
2895                                 break;
2896
2897                         case Operator.GreaterThan:
2898                                 if (onTrue)
2899                                         if (isUnsigned)
2900                                                 ig.Emit (OpCodes.Bgt_Un, target);
2901                                         else
2902                                                 ig.Emit (OpCodes.Bgt, target);
2903                                 else
2904                                         if (isUnsigned)
2905                                                 ig.Emit (OpCodes.Ble_Un, target);
2906                                         else
2907                                                 ig.Emit (OpCodes.Ble, target);
2908                                 break;
2909
2910                         case Operator.LessThanOrEqual:
2911                                 if (onTrue)
2912                                         if (isUnsigned)
2913                                                 ig.Emit (OpCodes.Ble_Un, target);
2914                                         else
2915                                                 ig.Emit (OpCodes.Ble, target);
2916                                 else
2917                                         if (isUnsigned)
2918                                                 ig.Emit (OpCodes.Bgt_Un, target);
2919                                         else
2920                                                 ig.Emit (OpCodes.Bgt, target);
2921                                 break;
2922
2923
2924                         case Operator.GreaterThanOrEqual:
2925                                 if (onTrue)
2926                                         if (isUnsigned)
2927                                                 ig.Emit (OpCodes.Bge_Un, target);
2928                                         else
2929                                                 ig.Emit (OpCodes.Bge, target);
2930                                 else
2931                                         if (isUnsigned)
2932                                                 ig.Emit (OpCodes.Blt_Un, target);
2933                                         else
2934                                                 ig.Emit (OpCodes.Blt, target);
2935                                 break;
2936                         default:
2937                                 Console.WriteLine (oper);
2938                                 throw new Exception ("what is THAT");
2939                         }
2940                 }
2941                 
2942                 public override void Emit (EmitContext ec)
2943                 {
2944                         ILGenerator ig = ec.ig;
2945                         Type l = left.Type;
2946                         OpCode opcode;
2947
2948                         //
2949                         // Handle short-circuit operators differently
2950                         // than the rest
2951                         //
2952                         if (oper == Operator.LogicalAnd) {
2953                                 Label load_zero = ig.DefineLabel ();
2954                                 Label end = ig.DefineLabel ();
2955                                                                 
2956                                 left.EmitBranchable (ec, load_zero, false);
2957                                 right.Emit (ec);
2958                                 ig.Emit (OpCodes.Br, end);
2959                                 
2960                                 ig.MarkLabel (load_zero);
2961                                 ig.Emit (OpCodes.Ldc_I4_0);
2962                                 ig.MarkLabel (end);
2963                                 return;
2964                         } else if (oper == Operator.LogicalOr) {
2965                                 Label load_one = ig.DefineLabel ();
2966                                 Label end = ig.DefineLabel ();
2967
2968                                 left.EmitBranchable (ec, load_one, true);
2969                                 right.Emit (ec);
2970                                 ig.Emit (OpCodes.Br, end);
2971                                 
2972                                 ig.MarkLabel (load_one);
2973                                 ig.Emit (OpCodes.Ldc_I4_1);
2974                                 ig.MarkLabel (end);
2975                                 return;
2976                         }
2977
2978                         left.Emit (ec);
2979                         right.Emit (ec);
2980
2981                         bool isUnsigned = is_unsigned (left.Type);
2982                         
2983                         switch (oper){
2984                         case Operator.Multiply:
2985                                 if (ec.CheckState){
2986                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2987                                                 opcode = OpCodes.Mul_Ovf;
2988                                         else if (isUnsigned)
2989                                                 opcode = OpCodes.Mul_Ovf_Un;
2990                                         else
2991                                                 opcode = OpCodes.Mul;
2992                                 } else
2993                                         opcode = OpCodes.Mul;
2994
2995                                 break;
2996
2997                         case Operator.Division:
2998                                 if (isUnsigned)
2999                                         opcode = OpCodes.Div_Un;
3000                                 else
3001                                         opcode = OpCodes.Div;
3002                                 break;
3003
3004                         case Operator.Modulus:
3005                                 if (isUnsigned)
3006                                         opcode = OpCodes.Rem_Un;
3007                                 else
3008                                         opcode = OpCodes.Rem;
3009                                 break;
3010
3011                         case Operator.Addition:
3012                                 if (ec.CheckState){
3013                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3014                                                 opcode = OpCodes.Add_Ovf;
3015                                         else if (isUnsigned)
3016                                                 opcode = OpCodes.Add_Ovf_Un;
3017                                         else
3018                                                 opcode = OpCodes.Add;
3019                                 } else
3020                                         opcode = OpCodes.Add;
3021                                 break;
3022
3023                         case Operator.Subtraction:
3024                                 if (ec.CheckState){
3025                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
3026                                                 opcode = OpCodes.Sub_Ovf;
3027                                         else if (isUnsigned)
3028                                                 opcode = OpCodes.Sub_Ovf_Un;
3029                                         else
3030                                                 opcode = OpCodes.Sub;
3031                                 } else
3032                                         opcode = OpCodes.Sub;
3033                                 break;
3034
3035                         case Operator.RightShift:
3036                                 if (isUnsigned)
3037                                         opcode = OpCodes.Shr_Un;
3038                                 else
3039                                         opcode = OpCodes.Shr;
3040                                 break;
3041                                 
3042                         case Operator.LeftShift:
3043                                 opcode = OpCodes.Shl;
3044                                 break;
3045
3046                         case Operator.Equality:
3047                                 opcode = OpCodes.Ceq;
3048                                 break;
3049
3050                         case Operator.Inequality:
3051                                 ig.Emit (OpCodes.Ceq);
3052                                 ig.Emit (OpCodes.Ldc_I4_0);
3053                                 
3054                                 opcode = OpCodes.Ceq;
3055                                 break;
3056
3057                         case Operator.LessThan:
3058                                 if (isUnsigned)
3059                                         opcode = OpCodes.Clt_Un;
3060                                 else
3061                                         opcode = OpCodes.Clt;
3062                                 break;
3063
3064                         case Operator.GreaterThan:
3065                                 if (isUnsigned)
3066                                         opcode = OpCodes.Cgt_Un;
3067                                 else
3068                                         opcode = OpCodes.Cgt;
3069                                 break;
3070
3071                         case Operator.LessThanOrEqual:
3072                                 Type lt = left.Type;
3073                                 
3074                                 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
3075                                         ig.Emit (OpCodes.Cgt_Un);
3076                                 else
3077                                         ig.Emit (OpCodes.Cgt);
3078                                 ig.Emit (OpCodes.Ldc_I4_0);
3079                                 
3080                                 opcode = OpCodes.Ceq;
3081                                 break;
3082
3083                         case Operator.GreaterThanOrEqual:
3084                                 Type le = left.Type;
3085                                 
3086                                 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
3087                                         ig.Emit (OpCodes.Clt_Un);
3088                                 else
3089                                         ig.Emit (OpCodes.Clt);
3090                                 
3091                                 ig.Emit (OpCodes.Ldc_I4_0);
3092                                 
3093                                 opcode = OpCodes.Ceq;
3094                                 break;
3095
3096                         case Operator.BitwiseOr:
3097                                 opcode = OpCodes.Or;
3098                                 break;
3099
3100                         case Operator.BitwiseAnd:
3101                                 opcode = OpCodes.And;
3102                                 break;
3103
3104                         case Operator.ExclusiveOr:
3105                                 opcode = OpCodes.Xor;
3106                                 break;
3107
3108                         default:
3109                                 throw new Exception ("This should not happen: Operator = "
3110                                                      + oper.ToString ());
3111                         }
3112
3113                         ig.Emit (opcode);
3114                 }
3115         }
3116
3117         //
3118         // Object created by Binary when the binary operator uses an method instead of being
3119         // a binary operation that maps to a CIL binary operation.
3120         //
3121         public class BinaryMethod : Expression {
3122                 public MethodBase method;
3123                 public ArrayList  Arguments;
3124                 
3125                 public BinaryMethod (Type t, MethodBase m, ArrayList args)
3126                 {
3127                         method = m;
3128                         Arguments = args;
3129                         type = t;
3130                         eclass = ExprClass.Value;
3131                 }
3132
3133                 public override Expression DoResolve (EmitContext ec)
3134                 {
3135                         return this;
3136                 }
3137
3138                 public override void Emit (EmitContext ec)
3139                 {
3140                         ILGenerator ig = ec.ig;
3141                         
3142                         if (Arguments != null) 
3143                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
3144                         
3145                         if (method is MethodInfo)
3146                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
3147                         else
3148                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
3149                 }
3150         }
3151         
3152         //
3153         // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
3154         // b, c, d... may be strings or objects.
3155         //
3156         public class StringConcat : Expression {
3157                 ArrayList operands;
3158                 bool invalid = false;
3159                 bool emit_conv_done = false;
3160                 //
3161                 // Are we also concating objects?
3162                 //
3163                 bool is_strings_only = true;
3164                 
3165                 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
3166                 {
3167                         this.loc = loc;
3168                         type = TypeManager.string_type;
3169                         eclass = ExprClass.Value;
3170                 
3171                         operands = new ArrayList (2);
3172                         Append (ec, left);
3173                         Append (ec, right);
3174                 }
3175                 
3176                 public override Expression DoResolve (EmitContext ec)
3177                 {
3178                         if (invalid)
3179                                 return null;
3180                         
3181                         return this;
3182                 }
3183                 
3184                 public void Append (EmitContext ec, Expression operand)
3185                 {
3186                         //
3187                         // Constant folding
3188                         //
3189                         if (operand is StringConstant && operands.Count != 0) {
3190                                 StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
3191                                 if (last_operand != null) {
3192                                         operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value);
3193                                         return;
3194                                 }
3195                         }
3196                         
3197                         //
3198                         // Conversion to object
3199                         //
3200                         if (operand.Type != TypeManager.string_type) {
3201                                 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
3202                                 
3203                                 if (no == null) {
3204                                         Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
3205                                         invalid = true;
3206                                 }
3207                                 operand = no;
3208                         }
3209                         
3210                         operands.Add (operand);
3211                 }
3212
3213                 public override void Emit (EmitContext ec)
3214                 {
3215                         MethodInfo concat_method = null;
3216                         
3217                         //
3218                         // Do conversion to arguments; check for strings only
3219                         //
3220                         
3221                         // This can get called multiple times, so we have to deal with that.
3222                         if (!emit_conv_done) {
3223                                 emit_conv_done = true;
3224                                 for (int i = 0; i < operands.Count; i ++) {
3225                                         Expression e = (Expression) operands [i];
3226                                         is_strings_only &= e.Type == TypeManager.string_type;
3227                                 }
3228                                 
3229                                 for (int i = 0; i < operands.Count; i ++) {
3230                                         Expression e = (Expression) operands [i];
3231                                         
3232                                         if (! is_strings_only && e.Type == TypeManager.string_type) {
3233                                                 // need to make sure this is an object, because the EmitParams
3234                                                 // method might look at the type of this expression, see it is a
3235                                                 // string and emit a string [] when we want an object [];
3236                                                 
3237                                                 e = new EmptyCast (e, TypeManager.object_type);
3238                                         }
3239                                         operands [i] = new Argument (e, Argument.AType.Expression);
3240                                 }
3241                         }
3242                         
3243                         //
3244                         // Find the right method
3245                         //
3246                         switch (operands.Count) {
3247                         case 1:
3248                                 //
3249                                 // This should not be possible, because simple constant folding
3250                                 // is taken care of in the Binary code.
3251                                 //
3252                                 throw new Exception ("how did you get here?");
3253                         
3254                         case 2:
3255                                 concat_method = is_strings_only ? 
3256                                         TypeManager.string_concat_string_string :
3257                                         TypeManager.string_concat_object_object ;
3258                                 break;
3259                         case 3:
3260                                 concat_method = is_strings_only ? 
3261                                         TypeManager.string_concat_string_string_string :
3262                                         TypeManager.string_concat_object_object_object ;
3263                                 break;
3264                         case 4:
3265                                 //
3266                                 // There is not a 4 param overlaod for object (the one that there is
3267                                 // is actually a varargs methods, and is only in corlib because it was
3268                                 // introduced there before.).
3269                                 //
3270                                 if (!is_strings_only)
3271                                         goto default;
3272                                 
3273                                 concat_method = TypeManager.string_concat_string_string_string_string;
3274                                 break;
3275                         default:
3276                                 concat_method = is_strings_only ? 
3277                                         TypeManager.string_concat_string_dot_dot_dot :
3278                                         TypeManager.string_concat_object_dot_dot_dot ;
3279                                 break;
3280                         }
3281                         
3282                         Invocation.EmitArguments (ec, concat_method, operands, false, null);
3283                         ec.ig.Emit (OpCodes.Call, concat_method);
3284                 }
3285         }
3286
3287         //
3288         // Object created with +/= on delegates
3289         //
3290         public class BinaryDelegate : Expression {
3291                 MethodInfo method;
3292                 ArrayList  args;
3293
3294                 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3295                 {
3296                         method = mi;
3297                         this.args = args;
3298                         type = t;
3299                         eclass = ExprClass.Value;
3300                 }
3301
3302                 public override Expression DoResolve (EmitContext ec)
3303                 {
3304                         return this;
3305                 }
3306
3307                 public override void Emit (EmitContext ec)
3308                 {
3309                         ILGenerator ig = ec.ig;
3310                         
3311                         Invocation.EmitArguments (ec, method, args, false, null);
3312                         
3313                         ig.Emit (OpCodes.Call, (MethodInfo) method);
3314                         ig.Emit (OpCodes.Castclass, type);
3315                 }
3316
3317                 public Expression Right {
3318                         get {
3319                                 Argument arg = (Argument) args [1];
3320                                 return arg.Expr;
3321                         }
3322                 }
3323
3324                 public bool IsAddition {
3325                         get {
3326                                 return method == TypeManager.delegate_combine_delegate_delegate;
3327                         }
3328                 }
3329         }
3330         
3331         //
3332         // User-defined conditional logical operator
3333         public class ConditionalLogicalOperator : Expression {
3334                 Expression left, right;
3335                 bool is_and;
3336
3337                 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3338                 {
3339                         type = t;
3340                         eclass = ExprClass.Value;
3341                         this.loc = loc;
3342                         this.left = left;
3343                         this.right = right;
3344                         this.is_and = is_and;
3345                 }
3346
3347                 protected void Error19 ()
3348                 {
3349                         Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", type, type);
3350                 }
3351
3352                 protected void Error218 ()
3353                 {
3354                         Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3355                                "declarations of operator true and operator false");
3356                 }
3357
3358                 Expression op_true, op_false, op;
3359                 LocalTemporary left_temp;
3360
3361                 public override Expression DoResolve (EmitContext ec)
3362                 {
3363                         MethodInfo method;
3364                         Expression operator_group;
3365
3366                         operator_group = MethodLookup (ec, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
3367                         if (operator_group == null) {
3368                                 Error19 ();
3369                                 return null;
3370                         }
3371
3372                         left_temp = new LocalTemporary (ec, type);
3373
3374                         ArrayList arguments = new ArrayList ();
3375                         arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3376                         arguments.Add (new Argument (right, Argument.AType.Expression));
3377                         method = Invocation.OverloadResolve (
3378                                 ec, (MethodGroupExpr) operator_group, arguments, false, loc)
3379                                 as MethodInfo;
3380                         if (method == null) {
3381                                 Error19 ();
3382                                 return null;
3383                         }
3384
3385                         if (method.ReturnType != type) {
3386                                 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3387                                                 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3388                                 return null;
3389                         }
3390
3391                         op = new StaticCallExpr (method, arguments, loc);
3392
3393                         op_true = GetOperatorTrue (ec, left_temp, loc);
3394                         op_false = GetOperatorFalse (ec, left_temp, loc);
3395                         if ((op_true == null) || (op_false == null)) {
3396                                 Error218 ();
3397                                 return null;
3398                         }
3399
3400                         return this;
3401                 }
3402
3403                 public override void Emit (EmitContext ec)
3404                 {
3405                         ILGenerator ig = ec.ig;
3406                         Label false_target = ig.DefineLabel ();
3407                         Label end_target = ig.DefineLabel ();
3408
3409                         left.Emit (ec);
3410                         left_temp.Store (ec);
3411
3412                         (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3413                         left_temp.Emit (ec);
3414                         ig.Emit (OpCodes.Br, end_target);
3415                         ig.MarkLabel (false_target);
3416                         op.Emit (ec);
3417                         ig.MarkLabel (end_target);
3418                 }
3419         }
3420
3421         public class PointerArithmetic : Expression {
3422                 Expression left, right;
3423                 bool is_add;
3424
3425                 //
3426                 // We assume that `l' is always a pointer
3427                 //
3428                 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3429                 {
3430                         type = t;
3431                         this.loc = loc;
3432                         left = l;
3433                         right = r;
3434                         is_add = is_addition;
3435                 }
3436
3437                 public override Expression DoResolve (EmitContext ec)
3438                 {
3439                         eclass = ExprClass.Variable;
3440                         
3441                         if (left.Type == TypeManager.void_ptr_type) {
3442                                 Error (242, "The operation in question is undefined on void pointers");
3443                                 return null;
3444                         }
3445                         
3446                         return this;
3447                 }
3448
3449                 public override void Emit (EmitContext ec)
3450                 {
3451                         Type op_type = left.Type;
3452                         ILGenerator ig = ec.ig;
3453                         
3454                         // It must be either array or fixed buffer
3455                         Type element = TypeManager.HasElementType (op_type) ?
3456                                 element = TypeManager.GetElementType (op_type) :
3457                                 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3458
3459                         int size = GetTypeSize (element);
3460                         Type rtype = right.Type;
3461                         
3462                         if (rtype.IsPointer){
3463                                 //
3464                                 // handle (pointer - pointer)
3465                                 //
3466                                 left.Emit (ec);
3467                                 right.Emit (ec);
3468                                 ig.Emit (OpCodes.Sub);
3469
3470                                 if (size != 1){
3471                                         if (size == 0)
3472                                                 ig.Emit (OpCodes.Sizeof, element);
3473                                         else 
3474                                                 IntLiteral.EmitInt (ig, size);
3475                                         ig.Emit (OpCodes.Div);
3476                                 }
3477                                 ig.Emit (OpCodes.Conv_I8);
3478                         } else {
3479                                 //
3480                                 // handle + and - on (pointer op int)
3481                                 //
3482                                 left.Emit (ec);
3483                                 ig.Emit (OpCodes.Conv_I);
3484
3485                                 Constant right_const = right as Constant;
3486                                 if (right_const != null && size != 0) {
3487                                         Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size), right_const, loc);
3488                                         if (ex == null)
3489                                                 return;
3490                                         ex.Emit (ec);
3491                                 } else {
3492                                         right.Emit (ec);
3493                                         if (size != 1){
3494                                                 if (size == 0)
3495                                                         ig.Emit (OpCodes.Sizeof, element);
3496                                                 else 
3497                                                         IntLiteral.EmitInt (ig, size);
3498                                                 if (rtype == TypeManager.int64_type)
3499                                                         ig.Emit (OpCodes.Conv_I8);
3500                                                 else if (rtype == TypeManager.uint64_type)
3501                                                         ig.Emit (OpCodes.Conv_U8);
3502                                                 ig.Emit (OpCodes.Mul);
3503                                         }
3504                                 }
3505                                 
3506                                 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3507                                         ig.Emit (OpCodes.Conv_I);
3508                                 
3509                                 if (is_add)
3510                                         ig.Emit (OpCodes.Add);
3511                                 else
3512                                         ig.Emit (OpCodes.Sub);
3513                         }
3514                 }
3515         }
3516         
3517         /// <summary>
3518         ///   Implements the ternary conditional operator (?:)
3519         /// </summary>
3520         public class Conditional : Expression {
3521                 Expression expr, trueExpr, falseExpr;
3522                 
3523                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3524                 {
3525                         this.expr = expr;
3526                         this.trueExpr = trueExpr;
3527                         this.falseExpr = falseExpr;
3528                         this.loc = l;
3529                 }
3530
3531                 public Expression Expr {
3532                         get {
3533                                 return expr;
3534                         }
3535                 }
3536
3537                 public Expression TrueExpr {
3538                         get {
3539                                 return trueExpr;
3540                         }
3541                 }
3542
3543                 public Expression FalseExpr {
3544                         get {
3545                                 return falseExpr;
3546                         }
3547                 }
3548
3549                 public override Expression DoResolve (EmitContext ec)
3550                 {
3551                         expr = expr.Resolve (ec);
3552
3553                         if (expr == null)
3554                                 return null;
3555                         
3556                         if (expr.Type != TypeManager.bool_type){
3557                                 expr = Expression.ResolveBoolean (
3558                                         ec, expr, loc);
3559                                 
3560                                 if (expr == null)
3561                                         return null;
3562                         }
3563                         
3564                         trueExpr = trueExpr.Resolve (ec);
3565                         falseExpr = falseExpr.Resolve (ec);
3566
3567                         if (trueExpr == null || falseExpr == null)
3568                                 return null;
3569
3570                         eclass = ExprClass.Value;
3571                         if (trueExpr.Type == falseExpr.Type)
3572                                 type = trueExpr.Type;
3573                         else {
3574                                 Expression conv;
3575                                 Type true_type = trueExpr.Type;
3576                                 Type false_type = falseExpr.Type;
3577
3578                                 //
3579                                 // First, if an implicit conversion exists from trueExpr
3580                                 // to falseExpr, then the result type is of type falseExpr.Type
3581                                 //
3582                                 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3583                                 if (conv != null){
3584                                         //
3585                                         // Check if both can convert implicitl to each other's type
3586                                         //
3587                                         if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3588                                                 Error (172,
3589                                                        "Can not compute type of conditional expression " +
3590                                                        "as `" + TypeManager.CSharpName (trueExpr.Type) +
3591                                                        "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3592                                                        "' convert implicitly to each other");
3593                                                 return null;
3594                                         }
3595                                         type = false_type;
3596                                         trueExpr = conv;
3597                                 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3598                                         type = true_type;
3599                                         falseExpr = conv;
3600                                 } else {
3601                                         Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3602                                                 trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
3603                                         return null;
3604                                 }
3605                         }
3606
3607                         // Dead code optimalization
3608                         if (expr is BoolConstant){
3609                                 BoolConstant bc = (BoolConstant) expr;
3610
3611                                 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3612                                 return bc.Value ? trueExpr : falseExpr;
3613                         }
3614
3615                         return this;
3616                 }
3617
3618                 public override void Emit (EmitContext ec)
3619                 {
3620                         ILGenerator ig = ec.ig;
3621                         Label false_target = ig.DefineLabel ();
3622                         Label end_target = ig.DefineLabel ();
3623
3624                         expr.EmitBranchable (ec, false_target, false);
3625                         trueExpr.Emit (ec);
3626                         ig.Emit (OpCodes.Br, end_target);
3627                         ig.MarkLabel (false_target);
3628                         falseExpr.Emit (ec);
3629                         ig.MarkLabel (end_target);
3630                 }
3631
3632         }
3633
3634         /// <summary>
3635         ///   Local variables
3636         /// </summary>
3637         public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3638                 public readonly string Name;
3639                 public readonly Block Block;
3640                 public LocalInfo local_info;
3641                 bool is_readonly;
3642                 bool prepared;
3643                 LocalTemporary temp;
3644                 
3645                 public LocalVariableReference (Block block, string name, Location l)
3646                 {
3647                         Block = block;
3648                         Name = name;
3649                         loc = l;
3650                         eclass = ExprClass.Variable;
3651                 }
3652
3653                 //
3654                 // Setting `is_readonly' to false will allow you to create a writable
3655                 // reference to a read-only variable.  This is used by foreach and using.
3656                 //
3657                 public LocalVariableReference (Block block, string name, Location l,
3658                                                LocalInfo local_info, bool is_readonly)
3659                         : this (block, name, l)
3660                 {
3661                         this.local_info = local_info;
3662                         this.is_readonly = is_readonly;
3663                 }
3664
3665                 public VariableInfo VariableInfo {
3666                         get {
3667                                 return local_info.VariableInfo;
3668                         }
3669                 }
3670
3671                 public bool IsReadOnly {
3672                         get {
3673                                 return is_readonly;
3674                         }
3675                 }
3676
3677                 protected Expression DoResolveBase (EmitContext ec, Expression lvalue_right_side)
3678                 {
3679                         if (local_info == null) {
3680                                 local_info = Block.GetLocalInfo (Name);
3681
3682                                 // is out param
3683                                 if (lvalue_right_side == EmptyExpression.Null)
3684                                         local_info.Used = true;
3685
3686                                 is_readonly = local_info.ReadOnly;
3687                         }
3688
3689                         type = local_info.VariableType;
3690
3691                         VariableInfo variable_info = local_info.VariableInfo;
3692                         if (lvalue_right_side != null){
3693                                 if (is_readonly){
3694                                         if (lvalue_right_side is LocalVariableReference || lvalue_right_side == EmptyExpression.Null)
3695                                                 Report.Error (1657, loc, "Cannot pass `{0}' as a ref or out argument because it is a `{1}'",
3696                                                         Name, local_info.GetReadOnlyContext ());
3697                                         else
3698                                                 Report.Error (1656, loc, "Cannot assign to `{0}' because it is a `{1}'",
3699                                                         Name, local_info.GetReadOnlyContext ());
3700                                         return null;
3701                                 }
3702                                 
3703                                 if (variable_info != null)
3704                                         variable_info.SetAssigned (ec);
3705                         }
3706                         
3707                         Expression e = Block.GetConstantExpression (Name);
3708                         if (e != null) {
3709                                 local_info.Used = true;
3710                                 eclass = ExprClass.Value;
3711                                 return e.Resolve (ec);
3712                         }
3713
3714                         if ((variable_info != null) && !variable_info.IsAssigned (ec, loc))
3715                                 return null;
3716
3717                         if (lvalue_right_side == null)
3718                                 local_info.Used = true;
3719
3720                         if (ec.CurrentAnonymousMethod != null){
3721                                 //
3722                                 // If we are referencing a variable from the external block
3723                                 // flag it for capturing
3724                                 //
3725                                 if ((local_info.Block.Toplevel != ec.CurrentBlock.Toplevel) ||
3726                                     ec.CurrentAnonymousMethod.IsIterator)
3727                                 {
3728                                         if (local_info.AddressTaken){
3729                                                 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3730                                                 return null;
3731                                         }
3732                                         ec.CaptureVariable (local_info);
3733                                 }
3734                         }
3735
3736                         return this;
3737                 }
3738                 
3739                 public override Expression DoResolve (EmitContext ec)
3740                 {
3741                         return DoResolveBase (ec, null);
3742                 }
3743
3744                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3745                 {
3746                         Expression ret = DoResolveBase (ec, right_side);
3747                         if (ret != null)
3748                                 CheckObsoleteAttribute (ret.Type);
3749                         
3750                         return ret;
3751                 }
3752
3753                 public bool VerifyFixed ()
3754                 {
3755                         // A local Variable is always fixed.
3756                         return true;
3757                 }
3758
3759                 public override int GetHashCode()
3760                 {
3761                         return Name.GetHashCode ();
3762                 }
3763
3764                 public override bool Equals (object obj)
3765                 {
3766                         LocalVariableReference lvr = obj as LocalVariableReference;
3767                         if (lvr == null)
3768                                 return false;
3769
3770                         return Name == lvr.Name && Block == lvr.Block;
3771                 }
3772
3773                 public override void Emit (EmitContext ec)
3774                 {
3775                         ILGenerator ig = ec.ig;
3776
3777                         if (local_info.FieldBuilder == null){
3778                                 //
3779                                 // A local variable on the local CLR stack
3780                                 //
3781                                 ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
3782                         } else {
3783                                 //
3784                                 // A local variable captured by anonymous methods.
3785                                 //
3786                                 if (!prepared)
3787                                         ec.EmitCapturedVariableInstance (local_info);
3788                                 
3789                                 ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder);
3790                         }
3791                 }
3792                 
3793                 public void Emit (EmitContext ec, bool leave_copy)
3794                 {
3795                         Emit (ec);
3796                         if (leave_copy){
3797                                 ec.ig.Emit (OpCodes.Dup);
3798                                 if (local_info.FieldBuilder != null){
3799                                         temp = new LocalTemporary (ec, Type);
3800                                         temp.Store (ec);
3801                                 }
3802                         }
3803                 }
3804                 
3805                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3806                 {
3807                         ILGenerator ig = ec.ig;
3808                         prepared = prepare_for_load;
3809
3810                         if (local_info.FieldBuilder == null){
3811                                 //
3812                                 // A local variable on the local CLR stack
3813                                 //
3814                                 if (local_info.LocalBuilder == null)
3815                                         throw new Exception ("This should not happen: both Field and Local are null");
3816
3817                                 source.Emit (ec);
3818                                 if (leave_copy)
3819                                         ec.ig.Emit (OpCodes.Dup);
3820                                 ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
3821                         } else {
3822                                 //
3823                                 // A local variable captured by anonymous methods or itereators.
3824                                 //
3825                                 ec.EmitCapturedVariableInstance (local_info);
3826
3827                                 if (prepare_for_load)
3828                                         ig.Emit (OpCodes.Dup);
3829                                 source.Emit (ec);
3830                                 if (leave_copy){
3831                                         ig.Emit (OpCodes.Dup);
3832                                         temp = new LocalTemporary (ec, Type);
3833                                         temp.Store (ec);
3834                                 }
3835                                 ig.Emit (OpCodes.Stfld, local_info.FieldBuilder);
3836                                 if (temp != null)
3837                                         temp.Emit (ec);
3838                         }
3839                 }
3840                 
3841                 public void AddressOf (EmitContext ec, AddressOp mode)
3842                 {
3843                         ILGenerator ig = ec.ig;
3844
3845                         if (local_info.FieldBuilder == null){
3846                                 //
3847                                 // A local variable on the local CLR stack
3848                                 //
3849                                 ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
3850                         } else {
3851                                 //
3852                                 // A local variable captured by anonymous methods or iterators
3853                                 //
3854                                 ec.EmitCapturedVariableInstance (local_info);
3855                                 ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder);
3856                         }
3857                 }
3858
3859                 public override string ToString ()
3860                 {
3861                         return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3862                 }
3863         }
3864
3865         /// <summary>
3866         ///   This represents a reference to a parameter in the intermediate
3867         ///   representation.
3868         /// </summary>
3869         public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3870                 Parameters pars;
3871                 String name;
3872                 int idx;
3873                 Block block;
3874                 VariableInfo vi;
3875                 public Parameter.Modifier mod;
3876                 public bool is_ref, is_out, prepared;
3877
3878                 public bool IsOut {
3879                         get {
3880                                 return is_out;
3881                         }
3882                 }
3883
3884                 public bool IsRef {
3885                         get {
3886                                 return is_ref;
3887                         }
3888                 }
3889
3890                 LocalTemporary temp;
3891                 
3892                 public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc)
3893                 {
3894                         this.pars = pars;
3895                         this.block = block;
3896                         this.idx  = idx;
3897                         this.name = name;
3898                         this.loc = loc;
3899                         eclass = ExprClass.Variable;
3900                 }
3901
3902                 public ParameterReference (InternalParameters pars, Block block, int idx, Location loc)
3903                         : this (pars.Parameters, block, idx, pars.ParameterName (idx), loc)
3904                 { }
3905
3906                 public VariableInfo VariableInfo {
3907                         get { return vi; }
3908                 }
3909
3910                 public bool VerifyFixed ()
3911                 {
3912                         // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3913                         return mod == Parameter.Modifier.NONE;
3914                 }
3915
3916                 public bool IsAssigned (EmitContext ec, Location loc)
3917                 {
3918                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (vi))
3919                                 return true;
3920
3921                         Report.Error (269, loc,
3922                                       "Use of unassigned out parameter `{0}'", name);
3923                         return false;
3924                 }
3925
3926                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3927                 {
3928                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (vi, field_name))
3929                                 return true;
3930
3931                         Report.Error (170, loc,
3932                                       "Use of possibly unassigned field `" + field_name + "'");
3933                         return false;
3934                 }
3935
3936                 public void SetAssigned (EmitContext ec)
3937                 {
3938                         if (is_out && ec.DoFlowAnalysis)
3939                                 ec.CurrentBranching.SetAssigned (vi);
3940                 }
3941
3942                 public void SetFieldAssigned (EmitContext ec, string field_name)        
3943                 {
3944                         if (is_out && ec.DoFlowAnalysis)
3945                                 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
3946                 }
3947
3948                 protected void DoResolveBase (EmitContext ec)
3949                 {
3950                         type = pars.GetParameterInfo (ec, idx, out mod);
3951                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3952                         is_out = (mod & Parameter.Modifier.OUT) != 0;
3953                         eclass = ExprClass.Variable;
3954
3955                         if (is_out)
3956                                 vi = block.ParameterMap [idx];
3957
3958                         if (ec.CurrentAnonymousMethod != null){
3959                                 if (is_ref){
3960                                         Report.Error (1628, Location, "Cannot use ref or out parameter `{0}' inside an anonymous method block",
3961                                                 name);
3962                                         return;
3963                                 }
3964
3965                                 //
3966                                 // If we are referencing the parameter from the external block
3967                                 // flag it for capturing
3968                                 //
3969                                 //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name));
3970                                 if (!block.Toplevel.IsLocalParameter (name)){
3971                                         ec.CaptureParameter (name, type, idx);
3972                                 }
3973                         }
3974                 }
3975
3976                 public override int GetHashCode()
3977                 {
3978                         return name.GetHashCode ();
3979                 }
3980
3981                 public override bool Equals (object obj)
3982                 {
3983                         ParameterReference pr = obj as ParameterReference;
3984                         if (pr == null)
3985                                 return false;
3986
3987                         return name == pr.name && block == pr.block;
3988                 }
3989
3990                 //
3991                 // Notice that for ref/out parameters, the type exposed is not the
3992                 // same type exposed externally.
3993                 //
3994                 // for "ref int a":
3995                 //   externally we expose "int&"
3996                 //   here we expose       "int".
3997                 //
3998                 // We record this in "is_ref".  This means that the type system can treat
3999                 // the type as it is expected, but when we generate the code, we generate
4000                 // the alternate kind of code.
4001                 //
4002                 public override Expression DoResolve (EmitContext ec)
4003                 {
4004                         DoResolveBase (ec);
4005
4006                         if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
4007                                 return null;
4008
4009                         return this;
4010                 }
4011
4012                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
4013                 {
4014                         DoResolveBase (ec);
4015
4016                         SetAssigned (ec);
4017
4018                         return this;
4019                 }
4020
4021                 static public void EmitLdArg (ILGenerator ig, int x)
4022                 {
4023                         if (x <= 255){
4024                                 switch (x){
4025                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
4026                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
4027                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
4028                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
4029                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
4030                                 }
4031                         } else
4032                                 ig.Emit (OpCodes.Ldarg, x);
4033                 }
4034                 
4035                 //
4036                 // This method is used by parameters that are references, that are
4037                 // being passed as references:  we only want to pass the pointer (that
4038                 // is already stored in the parameter, not the address of the pointer,
4039                 // and not the value of the variable).
4040                 //
4041                 public void EmitLoad (EmitContext ec)
4042                 {
4043                         ILGenerator ig = ec.ig;
4044                         int arg_idx = idx;
4045
4046                         if (!ec.MethodIsStatic)
4047                                 arg_idx++;
4048                         
4049                         EmitLdArg (ig, arg_idx);
4050
4051                         //
4052                         // FIXME: Review for anonymous methods
4053                         //
4054                 }
4055                 
4056                 public override void Emit (EmitContext ec)
4057                 {
4058                         Emit (ec, false);
4059                 }
4060                 
4061                 public void Emit (EmitContext ec, bool leave_copy)
4062                 {
4063                         ILGenerator ig = ec.ig;
4064                         int arg_idx = idx;
4065
4066                         if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4067                                 if (leave_copy)
4068                                         throw new InternalErrorException ();
4069
4070                                 ec.EmitParameter (name);
4071                                 return;
4072                         }
4073
4074                         if (!ec.MethodIsStatic)
4075                                 arg_idx++;
4076
4077                         EmitLdArg (ig, arg_idx);
4078
4079                         if (is_ref) {
4080                                 if (prepared)
4081                                         ec.ig.Emit (OpCodes.Dup);
4082         
4083                                 //
4084                                 // If we are a reference, we loaded on the stack a pointer
4085                                 // Now lets load the real value
4086                                 //
4087                                 LoadFromPtr (ig, type);
4088                         }
4089                         
4090                         if (leave_copy) {
4091                                 ec.ig.Emit (OpCodes.Dup);
4092                                 
4093                                 if (is_ref) {
4094                                         temp = new LocalTemporary (ec, type);
4095                                         temp.Store (ec);
4096                                 }
4097                         }
4098                 }
4099                 
4100                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
4101                 {
4102                         if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4103                                 ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load);
4104                                 return;
4105                         }
4106
4107                         ILGenerator ig = ec.ig;
4108                         int arg_idx = idx;
4109                         
4110                         prepared = prepare_for_load;
4111                         
4112                         if (!ec.MethodIsStatic)
4113                                 arg_idx++;
4114
4115                         if (is_ref && !prepared)
4116                                 EmitLdArg (ig, arg_idx);
4117                         
4118                         source.Emit (ec);
4119
4120                         if (leave_copy)
4121                                 ec.ig.Emit (OpCodes.Dup);
4122                         
4123                         if (is_ref) {
4124                                 if (leave_copy) {
4125                                         temp = new LocalTemporary (ec, type);
4126                                         temp.Store (ec);
4127                                 }
4128                                 
4129                                 StoreFromPtr (ig, type);
4130                                 
4131                                 if (temp != null)
4132                                         temp.Emit (ec);
4133                         } else {
4134                                 if (arg_idx <= 255)
4135                                         ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
4136                                 else
4137                                         ig.Emit (OpCodes.Starg, arg_idx);
4138                         }
4139                 }
4140
4141                 public void AddressOf (EmitContext ec, AddressOp mode)
4142                 {
4143                         if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4144                                 ec.EmitAddressOfParameter (name);
4145                                 return;
4146                         }
4147                         
4148                         int arg_idx = idx;
4149
4150                         if (!ec.MethodIsStatic)
4151                                 arg_idx++;
4152
4153                         if (is_ref){
4154                                 if (arg_idx <= 255)
4155                                         ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
4156                                 else
4157                                         ec.ig.Emit (OpCodes.Ldarg, arg_idx);
4158                         } else {
4159                                 if (arg_idx <= 255)
4160                                         ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
4161                                 else
4162                                         ec.ig.Emit (OpCodes.Ldarga, arg_idx);
4163                         }
4164                 }
4165
4166         }
4167         
4168         /// <summary>
4169         ///   Used for arguments to New(), Invocation()
4170         /// </summary>
4171         public class Argument {
4172                 public enum AType : byte {
4173                         Expression,
4174                         Ref,
4175                         Out,
4176                         ArgList
4177                 };
4178
4179                 public readonly AType ArgType;
4180                 public Expression Expr;
4181                 
4182                 public Argument (Expression expr, AType type)
4183                 {
4184                         this.Expr = expr;
4185                         this.ArgType = type;
4186                 }
4187
4188                 public Argument (Expression expr)
4189                 {
4190                         this.Expr = expr;
4191                         this.ArgType = AType.Expression;
4192                 }
4193
4194                 public Type Type {
4195                         get {
4196                                 if (ArgType == AType.Ref || ArgType == AType.Out)
4197                                         return TypeManager.GetReferenceType (Expr.Type);
4198                                 else
4199                                         return Expr.Type;
4200                         }
4201                 }
4202
4203                 public Parameter.Modifier Modifier
4204                 {
4205                         get {
4206                                 switch (ArgType) {
4207                                         case AType.Out:
4208                                                 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
4209
4210                                         case AType.Ref:
4211                                                 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
4212
4213                                         default:
4214                                                 return Parameter.Modifier.NONE;
4215                                 }
4216                         }
4217                 }
4218
4219                 public static string FullDesc (Argument a)
4220                 {
4221                         if (a.ArgType == AType.ArgList)
4222                                 return "__arglist";
4223
4224                         return (a.ArgType == AType.Ref ? "ref " :
4225                                 (a.ArgType == AType.Out ? "out " : "")) +
4226                                 TypeManager.CSharpName (a.Expr.Type);
4227                 }
4228
4229                 public bool ResolveMethodGroup (EmitContext ec, Location loc)
4230                 {
4231                         // FIXME: csc doesn't report any error if you try to use `ref' or
4232                         //        `out' in a delegate creation expression.
4233                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4234                         if (Expr == null)
4235                                 return false;
4236
4237                         return true;
4238                 }
4239                 
4240                 void Error_LValueRequired (Location loc)
4241                 {
4242                         Report.Error (1510, loc, "A ref or out argument must be an assignable variable");
4243                 }
4244
4245                 public bool Resolve (EmitContext ec, Location loc)
4246                 {
4247                         bool old_do_flow_analysis = ec.DoFlowAnalysis;
4248                         ec.DoFlowAnalysis = true;
4249
4250                         if (ArgType == AType.Ref) {
4251                                 ec.InRefOutArgumentResolving = true;
4252                                 Expr = Expr.Resolve (ec);
4253                                 ec.InRefOutArgumentResolving = false;
4254                                 if (Expr == null) {
4255                                         ec.DoFlowAnalysis = old_do_flow_analysis;
4256                                         return false;
4257                                 }
4258
4259                                 Expr = Expr.DoResolveLValue (ec, Expr);
4260                                 if (Expr == null)
4261                                         Error_LValueRequired (loc);
4262                         } else if (ArgType == AType.Out) {
4263                                 ec.InRefOutArgumentResolving = true;
4264                                 Expr = Expr.DoResolveLValue (ec, EmptyExpression.Null);
4265                                 ec.InRefOutArgumentResolving = false;
4266
4267                                 if (Expr == null)
4268                                         Error_LValueRequired (loc);
4269                         }
4270                         else
4271                                 Expr = Expr.Resolve (ec);
4272
4273                         ec.DoFlowAnalysis = old_do_flow_analysis;
4274
4275                         if (Expr == null)
4276                                 return false;
4277
4278                         if (ArgType == AType.Expression)
4279                                 return true;
4280                         else {
4281                                 //
4282                                 // Catch errors where fields of a MarshalByRefObject are passed as ref or out
4283                                 // This is only allowed for `this'
4284                                 //
4285                                 FieldExpr fe = Expr as FieldExpr;
4286                                 if (fe != null && !fe.IsStatic){
4287                                         Expression instance = fe.InstanceExpression;
4288
4289                                         if (instance.GetType () != typeof (This)){
4290                                                 if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){
4291                                                         Report.SymbolRelatedToPreviousError (fe.InstanceExpression.Type);
4292                                                         Report.Warning (197, 1, loc,
4293                                                                 "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",
4294                                                                 fe.GetSignatureForError ());
4295                                                         return false;
4296                                                 }
4297                                         }
4298                                 }
4299                         }
4300
4301                         if (Expr.eclass != ExprClass.Variable){
4302                                 //
4303                                 // We just probe to match the CSC output
4304                                 //
4305                                 if (Expr.eclass == ExprClass.PropertyAccess ||
4306                                     Expr.eclass == ExprClass.IndexerAccess){
4307                                         Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
4308                                                 Expr.GetSignatureForError ());
4309                                 } else {
4310                                         Error_LValueRequired (loc);
4311                                 }
4312                                 return false;
4313                         }
4314                                 
4315                         return true;
4316                 }
4317
4318                 public void Emit (EmitContext ec)
4319                 {
4320                         //
4321                         // Ref and Out parameters need to have their addresses taken.
4322                         //
4323                         // ParameterReferences might already be references, so we want
4324                         // to pass just the value
4325                         //
4326                         if (ArgType == AType.Ref || ArgType == AType.Out){
4327                                 AddressOp mode = AddressOp.Store;
4328
4329                                 if (ArgType == AType.Ref)
4330                                         mode |= AddressOp.Load;
4331                                 
4332                                 if (Expr is ParameterReference){
4333                                         ParameterReference pr = (ParameterReference) Expr;
4334
4335                                         if (pr.IsRef)
4336                                                 pr.EmitLoad (ec);
4337                                         else {
4338                                                 
4339                                                 pr.AddressOf (ec, mode);
4340                                         }
4341                                 } else {
4342                                         if (Expr is IMemoryLocation)
4343                                                ((IMemoryLocation) Expr).AddressOf (ec, mode);
4344                                         else {
4345                                                 Error_LValueRequired (Expr.Location);
4346                                                 return;
4347                                         }
4348                                 }
4349                         } else
4350                                 Expr.Emit (ec);
4351                 }
4352         }
4353
4354         /// <summary>
4355         ///   Invocation of methods or delegates.
4356         /// </summary>
4357         public class Invocation : ExpressionStatement {
4358                 public readonly ArrayList Arguments;
4359
4360                 Expression expr;
4361                 MethodBase method = null;
4362                 
4363                 //
4364                 // arguments is an ArrayList, but we do not want to typecast,
4365                 // as it might be null.
4366                 //
4367                 // FIXME: only allow expr to be a method invocation or a
4368                 // delegate invocation (7.5.5)
4369                 //
4370                 public Invocation (Expression expr, ArrayList arguments, Location l)
4371                 {
4372                         this.expr = expr;
4373                         Arguments = arguments;
4374                         loc = l;
4375                 }
4376
4377                 public Expression Expr {
4378                         get {
4379                                 return expr;
4380                         }
4381                 }
4382
4383                 /// <summary>
4384                 ///   Determines "better conversion" as specified in 7.4.2.3
4385                 ///
4386                 ///    Returns : p    if a->p is better,
4387                 ///              q    if a->q is better,
4388                 ///              null if neither is better
4389                 /// </summary>
4390                 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
4391                 {
4392                         Type argument_type = a.Type;
4393                         Expression argument_expr = a.Expr;
4394
4395                         if (argument_type == null)
4396                                 throw new Exception ("Expression of type " + a.Expr +
4397                                                      " does not resolve its type");
4398
4399                         if (p == null || q == null)
4400                                 throw new InternalErrorException ("BetterConversion Got a null conversion");
4401
4402                         if (p == q)
4403                                 return null;
4404
4405                         if (argument_expr is NullLiteral) {
4406                                 //
4407                                 // If the argument is null and one of the types to compare is 'object' and
4408                                 // the other is a reference type, we prefer the other.
4409                                 //
4410                                 // This follows from the usual rules:
4411                                 //   * There is an implicit conversion from 'null' to type 'object'
4412                                 //   * There is an implicit conversion from 'null' to any reference type
4413                                 //   * There is an implicit conversion from any reference type to type 'object'
4414                                 //   * There is no implicit conversion from type 'object' to other reference types
4415                                 //  => Conversion of 'null' to a reference type is better than conversion to 'object'
4416                                 //
4417                                 //  FIXME: This probably isn't necessary, since the type of a NullLiteral is the 
4418                                 //         null type. I think it used to be 'object' and thus needed a special 
4419                                 //         case to avoid the immediately following two checks.
4420                                 //
4421                                 if (!p.IsValueType && q == TypeManager.object_type)
4422                                         return p;
4423                                 if (!q.IsValueType && p == TypeManager.object_type)
4424                                         return q;
4425                         }
4426                                 
4427                         if (argument_type == p)
4428                                 return p;
4429
4430                         if (argument_type == q)
4431                                 return q;
4432
4433                         Expression p_tmp = new EmptyExpression (p);
4434                         Expression q_tmp = new EmptyExpression (q);
4435
4436                         bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4437                         bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4438
4439                         if (p_to_q && !q_to_p)
4440                                 return p;
4441
4442                         if (q_to_p && !p_to_q)
4443                                 return q;
4444
4445                         if (p == TypeManager.sbyte_type)
4446                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4447                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4448                                         return p;
4449                         if (q == TypeManager.sbyte_type)
4450                                 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
4451                                     p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4452                                         return q;
4453
4454                         if (p == TypeManager.short_type)
4455                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4456                                     q == TypeManager.uint64_type)
4457                                         return p;
4458                         if (q == TypeManager.short_type)
4459                                 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
4460                                     p == TypeManager.uint64_type)
4461                                         return q;
4462
4463                         if (p == TypeManager.int32_type)
4464                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4465                                         return p;
4466                         if (q == TypeManager.int32_type)
4467                                 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4468                                         return q;
4469
4470                         if (p == TypeManager.int64_type)
4471                                 if (q == TypeManager.uint64_type)
4472                                         return p;
4473                         if (q == TypeManager.int64_type)
4474                                 if (p == TypeManager.uint64_type)
4475                                         return q;
4476
4477                         return null;
4478                 }
4479                 
4480                 /// <summary>
4481                 ///   Determines "Better function" between candidate
4482                 ///   and the current best match
4483                 /// </summary>
4484                 /// <remarks>
4485                 ///    Returns an integer indicating :
4486                 ///     false if candidate ain't better
4487                 ///     true if candidate is better than the current best match
4488                 /// </remarks>
4489                 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
4490                                             MethodBase candidate, bool candidate_params,
4491                                             MethodBase best, bool best_params, Location loc)
4492                 {
4493                         ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
4494                         ParameterData best_pd = TypeManager.GetParameterData (best);
4495                 
4496                         bool better_at_least_one = false;
4497                         bool same = true;
4498                         for (int j = 0; j < argument_count; ++j) {
4499                                 Argument a = (Argument) args [j];
4500
4501                                 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (j));
4502                                 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (j));
4503
4504                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4505                                         if (candidate_params)
4506                                                 ct = TypeManager.GetElementType (ct);
4507
4508                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4509                                         if (best_params)
4510                                                 bt = TypeManager.GetElementType (bt);
4511
4512                                 if (ct == bt)
4513                                         continue;
4514
4515                                 same = false;
4516                                 Type better = BetterConversion (ec, a, ct, bt, loc);
4517
4518                                 // for each argument, the conversion to 'ct' should be no worse than 
4519                                 // the conversion to 'bt'.
4520                                 if (better == bt)
4521                                         return false;
4522
4523                                 // for at least one argument, the conversion to 'ct' should be better than 
4524                                 // the conversion to 'bt'.
4525                                 if (better == ct)
4526                                         better_at_least_one = true;
4527                         }
4528
4529                         if (better_at_least_one)
4530                                 return true;
4531
4532                         //
4533                         // This handles the case
4534                         //
4535                         //   Add (float f1, float f2, float f3);
4536                         //   Add (params decimal [] foo);
4537                         //
4538                         // The call Add (3, 4, 5) should be ambiguous.  Without this check, the
4539                         // first candidate would've chosen as better.
4540                         //
4541                         if (!same)
4542                                 return false;
4543
4544                         //
4545                         // This handles the following cases:
4546                         //
4547                         //   Trim () is better than Trim (params char[] chars)
4548                         //   Concat (string s1, string s2, string s3) is better than
4549                         //     Concat (string s1, params string [] srest)
4550                         //
4551                         return !candidate_params && best_params;
4552                 }
4553
4554                 static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4555                 {
4556                         if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4557                                 return false;
4558
4559                         ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
4560                         ParameterData base_pd = TypeManager.GetParameterData (base_method);
4561                 
4562                         if (cand_pd.Count != base_pd.Count)
4563                                 return false;
4564
4565                         for (int j = 0; j < cand_pd.Count; ++j) {
4566                                 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
4567                                 Parameter.Modifier bm = base_pd.ParameterModifier (j);
4568                                 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
4569                                 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
4570
4571                                 if (cm != bm || ct != bt)
4572                                         return false;
4573                         }
4574
4575                         return true;
4576                 }
4577
4578                 public static string FullMethodDesc (MethodBase mb)
4579                 {
4580                         if (mb == null)
4581                                 return "";
4582
4583                         StringBuilder sb;
4584                         if (mb is MethodInfo) {
4585                                 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4586                                 sb.Append (" ");
4587                         }
4588                         else
4589                                 sb = new StringBuilder ();
4590
4591                         sb.Append (TypeManager.CSharpSignature (mb));
4592                         return sb.ToString ();
4593                 }
4594
4595                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4596                 {
4597                         MemberInfo [] miset;
4598                         MethodGroupExpr union;
4599
4600                         if (mg1 == null) {
4601                                 if (mg2 == null)
4602                                         return null;
4603                                 return (MethodGroupExpr) mg2;
4604                         } else {
4605                                 if (mg2 == null)
4606                                         return (MethodGroupExpr) mg1;
4607                         }
4608                         
4609                         MethodGroupExpr left_set = null, right_set = null;
4610                         int length1 = 0, length2 = 0;
4611                         
4612                         left_set = (MethodGroupExpr) mg1;
4613                         length1 = left_set.Methods.Length;
4614                         
4615                         right_set = (MethodGroupExpr) mg2;
4616                         length2 = right_set.Methods.Length;
4617                         
4618                         ArrayList common = new ArrayList ();
4619
4620                         foreach (MethodBase r in right_set.Methods){
4621                                 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4622                                         common.Add (r);
4623                         }
4624
4625                         miset = new MemberInfo [length1 + length2 - common.Count];
4626                         left_set.Methods.CopyTo (miset, 0);
4627                         
4628                         int k = length1;
4629
4630                         foreach (MethodBase r in right_set.Methods) {
4631                                 if (!common.Contains (r))
4632                                         miset [k++] = r;
4633                         }
4634
4635                         union = new MethodGroupExpr (miset, loc);
4636                         
4637                         return union;
4638                 }
4639
4640                 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4641                                                              ArrayList arguments, int arg_count,
4642                                                              ref MethodBase candidate)
4643                 {
4644                         return IsParamsMethodApplicable (
4645                                 ec, me, arguments, arg_count, false, ref candidate) ||
4646                                 IsParamsMethodApplicable (
4647                                         ec, me, arguments, arg_count, true, ref candidate);
4648
4649
4650                 }
4651
4652                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4653                                                       ArrayList arguments, int arg_count,
4654                                                       bool do_varargs, ref MethodBase candidate)
4655                 {
4656                         return IsParamsMethodApplicable (
4657                                 ec, arguments, arg_count, candidate, do_varargs);
4658                 }
4659
4660                 /// <summary>
4661                 ///   Determines if the candidate method, if a params method, is applicable
4662                 ///   in its expanded form to the given set of arguments
4663                 /// </summary>
4664                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4665                                                       int arg_count, MethodBase candidate,
4666                                                       bool do_varargs)
4667                 {
4668                         ParameterData pd = TypeManager.GetParameterData (candidate);
4669
4670                         int pd_count = pd.Count;
4671                         if (pd_count == 0)
4672                                 return false;
4673
4674                         int count = pd_count - 1;
4675                         if (do_varargs) {
4676                                 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4677                                         return false;
4678                                 if (pd_count != arg_count)
4679                                         return false;
4680                         } else {
4681                                 if (pd.ParameterModifier (count) != Parameter.Modifier.PARAMS)
4682                                         return false;
4683                         }
4684                         
4685                         if (count > arg_count)
4686                                 return false;
4687                         
4688                         if (pd_count == 1 && arg_count == 0)
4689                                 return true;
4690
4691                         //
4692                         // If we have come this far, the case which
4693                         // remains is when the number of parameters is
4694                         // less than or equal to the argument count.
4695                         //
4696                         for (int i = 0; i < count; ++i) {
4697
4698                                 Argument a = (Argument) arguments [i];
4699
4700                                 Parameter.Modifier a_mod = a.Modifier & 
4701                                         (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4702                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4703                                         (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4704
4705                                 if (a_mod == p_mod) {
4706
4707                                         if (a_mod == Parameter.Modifier.NONE)
4708                                                 if (!Convert.ImplicitConversionExists (ec,
4709                                                                                        a.Expr,
4710                                                                                        pd.ParameterType (i)))
4711                                                         return false;
4712                                                                                 
4713                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4714                                                 Type pt = pd.ParameterType (i);
4715
4716                                                 if (!pt.IsByRef)
4717                                                         pt = TypeManager.GetReferenceType (pt);
4718                                                 
4719                                                 if (pt != a.Type)
4720                                                         return false;
4721                                         }
4722                                 } else
4723                                         return false;
4724                                 
4725                         }
4726
4727                         if (do_varargs) {
4728                                 Argument a = (Argument) arguments [count];
4729                                 if (!(a.Expr is Arglist))
4730                                         return false;
4731
4732                                 return true;
4733                         }
4734
4735                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
4736
4737                         for (int i = pd_count - 1; i < arg_count; i++) {
4738                                 Argument a = (Argument) arguments [i];
4739
4740                                 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4741                                         return false;
4742                         }
4743                         
4744                         return true;
4745                 }
4746
4747                 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4748                                                  ArrayList arguments, int arg_count,
4749                                                  ref MethodBase candidate)
4750                 {
4751                         return IsApplicable (ec, arguments, arg_count, candidate);
4752                 }
4753
4754                 /// <summary>
4755                 ///   Determines if the candidate method is applicable (section 14.4.2.1)
4756                 ///   to the given set of arguments
4757                 /// </summary>
4758                 static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4759                                           MethodBase candidate)
4760                 {
4761                         ParameterData pd = TypeManager.GetParameterData (candidate);
4762
4763                         if (arg_count != pd.Count)
4764                                 return false;
4765
4766                         for (int i = arg_count; i > 0; ) {
4767                                 i--;
4768
4769                                 Argument a = (Argument) arguments [i];
4770
4771                                 Parameter.Modifier a_mod = a.Modifier &
4772                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
4773                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4774                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
4775
4776                                 if (a_mod == p_mod ||
4777                                     (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
4778                                         if (a_mod == Parameter.Modifier.NONE) {
4779                                                 if (!Convert.ImplicitConversionExists (ec,
4780                                                                                        a.Expr,
4781                                                                                        pd.ParameterType (i)))
4782                                                         return false;
4783                                         }
4784                                         
4785                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4786                                                 Type pt = pd.ParameterType (i);
4787
4788                                                 if (!pt.IsByRef)
4789                                                         pt = TypeManager.GetReferenceType (pt);
4790                                                 
4791                                                 if (pt != a.Type)
4792                                                         return false;
4793                                         }
4794                                 } else
4795                                         return false;
4796                         }
4797
4798                         return true;
4799                 }
4800
4801                 static private bool IsAncestralType (Type first_type, Type second_type)
4802                 {
4803                         return first_type != second_type &&
4804                                 (second_type.IsSubclassOf (first_type) ||
4805                                  TypeManager.ImplementsInterface (second_type, first_type));
4806                 }
4807                 
4808                 /// <summary>
4809                 ///   Find the Applicable Function Members (7.4.2.1)
4810                 ///
4811                 ///   me: Method Group expression with the members to select.
4812                 ///       it might contain constructors or methods (or anything
4813                 ///       that maps to a method).
4814                 ///
4815                 ///   Arguments: ArrayList containing resolved Argument objects.
4816                 ///
4817                 ///   loc: The location if we want an error to be reported, or a Null
4818                 ///        location for "probing" purposes.
4819                 ///
4820                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4821                 ///            that is the best match of me on Arguments.
4822                 ///
4823                 /// </summary>
4824                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4825                                                           ArrayList Arguments, bool may_fail, 
4826                                                           Location loc)
4827                 {
4828                         MethodBase method = null;
4829                         bool method_params = false;
4830                         Type applicable_type = null;
4831                         int arg_count = 0;
4832                         ArrayList candidates = new ArrayList (2);
4833                         ArrayList candidate_overrides = null;
4834
4835                         //
4836                         // Used to keep a map between the candidate
4837                         // and whether it is being considered in its
4838                         // normal or expanded form
4839                         //
4840                         // false is normal form, true is expanded form
4841                         //
4842                         Hashtable candidate_to_form = null;
4843
4844                         if (Arguments != null)
4845                                 arg_count = Arguments.Count;
4846
4847                         if ((me.Name == "Invoke") &&
4848                                 TypeManager.IsDelegateType (me.DeclaringType)) {
4849                                 Error_InvokeOnDelegate (loc);
4850                                 return null;
4851                         }
4852
4853                         MethodBase[] methods = me.Methods;
4854
4855                         //
4856                         // First we construct the set of applicable methods
4857                         //
4858                         bool is_sorted = true;
4859                         for (int i = 0; i < methods.Length; i++){
4860                                 Type decl_type = methods [i].DeclaringType;
4861
4862                                 //
4863                                 // If we have already found an applicable method
4864                                 // we eliminate all base types (Section 14.5.5.1)
4865                                 //
4866                                 if ((applicable_type != null) &&
4867                                         IsAncestralType (decl_type, applicable_type))
4868                                         continue;
4869
4870                                 //
4871                                 // Methods marked 'override' don't take part in 'applicable_type'
4872                                 // computation, nor in the actual overload resolution.
4873                                 // However, they still need to be emitted instead of a base virtual method.
4874                                 // We avoid doing the 'applicable' test here, since it'll anyway be applied
4875                                 // to the base virtual function, and IsOverride is much faster than IsApplicable.
4876                                 //
4877                                 if (!me.IsBase && TypeManager.IsOverride (methods [i])) {
4878                                         if (candidate_overrides == null)
4879                                                 candidate_overrides = new ArrayList ();
4880                                         candidate_overrides.Add (methods [i]);
4881                                         continue;
4882                                 }
4883
4884                                 //
4885                                 // Check if candidate is applicable (section 14.4.2.1)
4886                                 //   Is candidate applicable in normal form?
4887                                 //
4888                                 bool is_applicable = IsApplicable (
4889                                         ec, me, Arguments, arg_count, ref methods [i]);
4890
4891                                 if (!is_applicable &&
4892                                         (IsParamsMethodApplicable (
4893                                         ec, me, Arguments, arg_count, ref methods [i]))) {
4894                                         MethodBase candidate = methods [i];
4895                                         if (candidate_to_form == null)
4896                                                 candidate_to_form = new PtrHashtable ();
4897                                         candidate_to_form [candidate] = candidate;
4898                                         // Candidate is applicable in expanded form
4899                                         is_applicable = true;
4900                                 }
4901
4902                                 if (!is_applicable)
4903                                         continue;
4904
4905                                 candidates.Add (methods [i]);
4906
4907                                 if (applicable_type == null)
4908                                         applicable_type = decl_type;
4909                                 else if (applicable_type != decl_type) {
4910                                         is_sorted = false;
4911                                         if (IsAncestralType (applicable_type, decl_type))
4912                                                 applicable_type = decl_type;
4913                                 }
4914                         }
4915
4916                         int candidate_top = candidates.Count;
4917
4918                         if (applicable_type == null) {
4919                                 //
4920                                 // Okay so we have failed to find anything so we
4921                                 // return by providing info about the closest match
4922                                 //
4923                                 for (int i = 0; i < methods.Length; ++i) {
4924                                         MethodBase c = (MethodBase) methods [i];
4925                                         ParameterData pd = TypeManager.GetParameterData (c);
4926
4927                                         if (pd.Count != arg_count)
4928                                                 continue;
4929
4930                                         VerifyArgumentsCompat (ec, Arguments, arg_count,
4931                                                 c, false, null, may_fail, loc);
4932                                         break;
4933                                 }
4934
4935                                 if (!may_fail) {
4936
4937                                         string report_name = me.Name;
4938                                         if (report_name == ".ctor")
4939                                                 report_name = me.DeclaringType.ToString ();
4940                                         
4941                                         Error_WrongNumArguments (
4942                                                 loc, report_name, arg_count);
4943                                         return null;
4944                                 }
4945                                 
4946                                 return null;
4947                         }
4948
4949                         if (!is_sorted) {
4950                                 //
4951                                 // At this point, applicable_type is _one_ of the most derived types
4952                                 // in the set of types containing the methods in this MethodGroup.
4953                                 // Filter the candidates so that they only contain methods from the
4954                                 // most derived types.
4955                                 //
4956
4957                                 int finalized = 0; // Number of finalized candidates
4958
4959                                 do {
4960                                         // Invariant: applicable_type is a most derived type
4961
4962                                         // We'll try to complete Section 14.5.5.1 for 'applicable_type' by 
4963                                         // eliminating all it's base types.  At the same time, we'll also move
4964                                         // every unrelated type to the end of the array, and pick the next
4965                                         // 'applicable_type'.
4966
4967                                         Type next_applicable_type = null;
4968                                         int j = finalized; // where to put the next finalized candidate
4969                                         int k = finalized; // where to put the next undiscarded candidate
4970                                         for (int i = finalized; i < candidate_top; ++i) {
4971                                                 MethodBase candidate = (MethodBase) candidates [i];
4972                                                 Type decl_type = candidate.DeclaringType;
4973
4974                                                 if (decl_type == applicable_type) {
4975                                                         candidates [k++] = candidates [j];
4976                                                         candidates [j++] = candidates [i];
4977                                                         continue;
4978                                                 }
4979
4980                                                 if (IsAncestralType (decl_type, applicable_type))
4981                                                         continue;
4982
4983                                                 if (next_applicable_type != null &&
4984                                                     IsAncestralType (decl_type, next_applicable_type))
4985                                                         continue;
4986
4987                                                 candidates [k++] = candidates [i];
4988
4989                                                 if (next_applicable_type == null ||
4990                                                     IsAncestralType (next_applicable_type, decl_type))
4991                                                         next_applicable_type = decl_type;
4992                                         }
4993
4994                                         applicable_type = next_applicable_type;
4995                                         finalized = j;
4996                                         candidate_top = k;
4997                                 } while (applicable_type != null);
4998                         }
4999
5000                         //
5001                         // Now we actually find the best method
5002                         //
5003
5004                         method = (MethodBase) candidates [0];
5005                         method_params = candidate_to_form != null && candidate_to_form.Contains (method);
5006                         for (int ix = 1; ix < candidate_top; ix++){
5007                                 MethodBase candidate = (MethodBase) candidates [ix];
5008
5009                                 if (candidate == method)
5010                                         continue;
5011
5012                                 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
5013                                 
5014                                 if (BetterFunction (ec, Arguments, arg_count, 
5015                                                     candidate, cand_params,
5016                                                     method, method_params, loc)) {
5017                                         method = candidate;
5018                                         method_params = cand_params;
5019                                 }
5020                         }
5021
5022                         //
5023                         // Now check that there are no ambiguities i.e the selected method
5024                         // should be better than all the others
5025                         //
5026                         MethodBase ambiguous = null;
5027                         for (int ix = 0; ix < candidate_top; ix++){
5028                                 MethodBase candidate = (MethodBase) candidates [ix];
5029
5030                                 if (candidate == method)
5031                                         continue;
5032
5033                                 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
5034                                 if (!BetterFunction (ec, Arguments, arg_count,
5035                                                      method, method_params,
5036                                                      candidate, cand_params,
5037                                                      loc)) {
5038                                         Report.SymbolRelatedToPreviousError (candidate);
5039                                         ambiguous = candidate;
5040                                 }
5041                         }
5042
5043                         if (ambiguous != null) {
5044                                 Report.SymbolRelatedToPreviousError (method);
5045                                 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
5046                                         TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method));
5047                                 return null;
5048                         }
5049
5050                         //
5051                         // If the method is a virtual function, pick an override closer to the LHS type.
5052                         //
5053                         if (!me.IsBase && method.IsVirtual) {
5054                                 if (TypeManager.IsOverride (method))
5055                                         throw new InternalErrorException (
5056                                                 "Should not happen.  An 'override' method took part in overload resolution: " + method);
5057
5058                                 if (candidate_overrides != null)
5059                                         foreach (MethodBase candidate in candidate_overrides) {
5060                                                 if (IsOverride (candidate, method))
5061                                                         method = candidate;
5062                                         }
5063                         }
5064
5065                         //
5066                         // And now check if the arguments are all
5067                         // compatible, perform conversions if
5068                         // necessary etc. and return if everything is
5069                         // all right
5070                         //
5071                         if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method,
5072                                                     method_params, null, may_fail, loc))
5073                                 return null;
5074
5075                         if (method != null) {
5076                                 IMethodData data = TypeManager.GetMethod (method);
5077                                 if (data != null)
5078                                         data.SetMemberIsUsed ();
5079                         }
5080                         return method;
5081                 }
5082
5083                 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
5084                 {
5085                         Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
5086                                 name, arg_count);
5087                 }
5088
5089                 static void Error_InvokeOnDelegate (Location loc)
5090                 {
5091                         Report.Error (1533, loc,
5092                                       "Invoke cannot be called directly on a delegate");
5093                 }
5094                         
5095                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
5096                                                     Type delegate_type, Argument a, ParameterData expected_par)
5097                 {
5098                         if (delegate_type == null) 
5099                                 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
5100                                               TypeManager.CSharpSignature (method));
5101                         else
5102                                 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
5103                                         TypeManager.CSharpName (delegate_type));
5104
5105                         string par_desc = expected_par.ParameterDesc (idx);
5106
5107                         if (a.Modifier != expected_par.ParameterModifier (idx)) {
5108                                 if ((expected_par.ParameterModifier (idx) & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
5109                                         Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
5110                                                 idx + 1, Parameter.GetModifierSignature (a.Modifier));
5111                                 else
5112                                         Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
5113                                                 idx + 1, Parameter.GetModifierSignature (expected_par.ParameterModifier (idx)));
5114                                 return;
5115                         }
5116
5117                         Report.Error (1503, loc,
5118                                       String.Format ("Argument {0}: Cannot convert from `{1}' to `{2}'",
5119                                                      idx + 1, Argument.FullDesc (a), par_desc));
5120                 }
5121                 
5122                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
5123                                                           int arg_count, MethodBase method, 
5124                                                           bool chose_params_expanded,
5125                                                           Type delegate_type, bool may_fail,
5126                                                           Location loc)
5127                 {
5128                         ParameterData pd = TypeManager.GetParameterData (method);
5129                         int pd_count = pd.Count;
5130
5131                         for (int j = 0; j < arg_count; j++) {
5132                                 Argument a = (Argument) Arguments [j];
5133                                 Expression a_expr = a.Expr;
5134                                 Type parameter_type = pd.ParameterType (j);
5135                                 Parameter.Modifier pm = pd.ParameterModifier (j);
5136                                 
5137                                 if (pm == Parameter.Modifier.PARAMS){
5138                                         if ((pm & ~Parameter.Modifier.PARAMS) != a.Modifier) {
5139                                                 if (!may_fail)
5140                                                         Error_InvalidArguments (
5141                                                                 loc, j, method, delegate_type,
5142                                                                 a, pd);
5143                                                 return false;
5144                                         }
5145
5146                                         if (chose_params_expanded)
5147                                                 parameter_type = TypeManager.GetElementType (parameter_type);
5148                                 } else if (pm == Parameter.Modifier.ARGLIST){
5149                                         continue;
5150                                 } else {
5151                                         //
5152                                         // Check modifiers
5153                                         //
5154                                         if (pd.ParameterModifier (j) != a.Modifier){
5155                                                 if (!may_fail)
5156                                                         Error_InvalidArguments (
5157                                                                 loc, j, method, delegate_type,
5158                                                                 a, pd);
5159                                                 return false;
5160                                         }
5161                                 }
5162
5163                                 //
5164                                 // Check Type
5165                                 //
5166                                 if (!a.Type.Equals (parameter_type)){
5167                                         Expression conv;
5168                                         
5169                                         conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
5170
5171                                         if (conv == null) {
5172                                                 if (!may_fail)
5173                                                         Error_InvalidArguments (loc, j, method, delegate_type, a, pd);
5174                                                 return false;
5175                                         }
5176                                         
5177                                         //
5178                                         // Update the argument with the implicit conversion
5179                                         //
5180                                         if (a_expr != conv)
5181                                                 a.Expr = conv;
5182                                 }
5183
5184                                 if (parameter_type.IsPointer){
5185                                         if (!ec.InUnsafe){
5186                                                 UnsafeError (loc);
5187                                                 return false;
5188                                         }
5189                                 }
5190                                 
5191                                 Parameter.Modifier a_mod = a.Modifier &
5192                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5193                                 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
5194                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5195                                 
5196                                 if (a_mod != p_mod &&
5197                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
5198                                         if (!may_fail) {
5199                                                 Invocation.Error_InvalidArguments (loc, j, method, null, a, pd);
5200                                         }
5201                                         
5202                                         return false;
5203                                 }
5204                         }
5205
5206                         return true;
5207                 }
5208
5209                 public override Expression DoResolve (EmitContext ec)
5210                 {
5211                         //
5212                         // First, resolve the expression that is used to
5213                         // trigger the invocation
5214                         //
5215                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5216                         if (expr == null)
5217                                 return null;
5218
5219                         if (!(expr is MethodGroupExpr)) {
5220                                 Type expr_type = expr.Type;
5221
5222                                 if (expr_type != null){
5223                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
5224                                         if (IsDelegate)
5225                                                 return (new DelegateInvocation (
5226                                                         this.expr, Arguments, loc)).Resolve (ec);
5227                                 }
5228                         }
5229
5230                         if (!(expr is MethodGroupExpr)){
5231                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
5232                                 return null;
5233                         }
5234
5235                         //
5236                         // Next, evaluate all the expressions in the argument list
5237                         //
5238                         if (Arguments != null){
5239                                 foreach (Argument a in Arguments){
5240                                         if (!a.Resolve (ec, loc))
5241                                                 return null;
5242                                 }
5243                         }
5244
5245                         MethodGroupExpr mg = (MethodGroupExpr) expr;
5246                         method = OverloadResolve (ec, mg, Arguments, false, loc);
5247
5248                         if (method == null)
5249                                 return null;
5250
5251                         MethodInfo mi = method as MethodInfo;
5252                         if (mi != null) {
5253                                 type = TypeManager.TypeToCoreType (mi.ReturnType);
5254                                 Expression iexpr = mg.InstanceExpression;
5255                                 if (mi.IsStatic) {
5256                                         if (iexpr == null || 
5257                                             iexpr is This || iexpr is EmptyExpression ||
5258                                             mg.IdenticalTypeName) {
5259                                                 mg.InstanceExpression = null;
5260                                         } else {
5261                                                 MemberExpr.error176 (loc, TypeManager.CSharpSignature (mi));
5262                                                 return null;
5263                                         }
5264                                 } else {
5265                                         if (iexpr == null || iexpr is EmptyExpression) {
5266                                                 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (mi));
5267                                                 return null;
5268                                         }
5269                                 }
5270                         }
5271
5272                         if (type.IsPointer){
5273                                 if (!ec.InUnsafe){
5274                                         UnsafeError (loc);
5275                                         return null;
5276                                 }
5277                         }
5278                         
5279                         //
5280                         // Only base will allow this invocation to happen.
5281                         //
5282                         if (mg.IsBase && method.IsAbstract){
5283                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
5284                                 return null;
5285                         }
5286
5287                         if (Arguments == null && method.Name == "Finalize") {
5288                                 if (mg.IsBase)
5289                                         Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5290                                 else
5291                                         Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5292                                 return null;
5293                         }
5294
5295                         if ((method.Attributes & MethodAttributes.SpecialName) != 0) {
5296                                 if (TypeManager.LookupDeclSpace (method.DeclaringType) != null || TypeManager.IsSpecialMethod (method)) {
5297                                         Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5298                                                 TypeManager.CSharpSignature (method, true));
5299                                         return null;
5300                                 }
5301                         }
5302
5303                         if (mg.InstanceExpression != null)
5304                                 mg.InstanceExpression.CheckMarshallByRefAccess (ec.ContainerType);
5305
5306                         eclass = ExprClass.Value;
5307                         return this;
5308                 }
5309
5310                 // <summary>
5311                 //   Emits the list of arguments as an array
5312                 // </summary>
5313                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
5314                 {
5315                         ILGenerator ig = ec.ig;
5316                         int count = arguments.Count - idx;
5317                         Argument a = (Argument) arguments [idx];
5318                         Type t = a.Expr.Type;
5319                         
5320                         IntConstant.EmitInt (ig, count);
5321                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5322
5323                         int top = arguments.Count;
5324                         for (int j = idx; j < top; j++){
5325                                 a = (Argument) arguments [j];
5326                                 
5327                                 ig.Emit (OpCodes.Dup);
5328                                 IntConstant.EmitInt (ig, j - idx);
5329
5330                                 bool is_stobj;
5331                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj);
5332                                 if (is_stobj)
5333                                         ig.Emit (OpCodes.Ldelema, t);
5334
5335                                 a.Emit (ec);
5336
5337                                 if (is_stobj)
5338                                         ig.Emit (OpCodes.Stobj, t);
5339                                 else
5340                                         ig.Emit (op);
5341                         }
5342                 }
5343                 
5344                 /// <summary>
5345                 ///   Emits a list of resolved Arguments that are in the arguments
5346                 ///   ArrayList.
5347                 /// 
5348                 ///   The MethodBase argument might be null if the
5349                 ///   emission of the arguments is known not to contain
5350                 ///   a `params' field (for example in constructors or other routines
5351                 ///   that keep their arguments in this structure)
5352                 ///   
5353                 ///   if `dup_args' is true, a copy of the arguments will be left
5354                 ///   on the stack. If `dup_args' is true, you can specify `this_arg'
5355                 ///   which will be duplicated before any other args. Only EmitCall
5356                 ///   should be using this interface.
5357                 /// </summary>
5358                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
5359                 {
5360                         ParameterData pd;
5361                         if (mb != null)
5362                                 pd = TypeManager.GetParameterData (mb);
5363                         else
5364                                 pd = null;
5365                         
5366                         LocalTemporary [] temps = null;
5367                         
5368                         if (dup_args)
5369                                 temps = new LocalTemporary [arguments.Count];
5370
5371                         //
5372                         // If we are calling a params method with no arguments, special case it
5373                         //
5374                         if (arguments == null){
5375                                 if (pd != null && pd.Count > 0 &&
5376                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
5377                                         ILGenerator ig = ec.ig;
5378
5379                                         IntConstant.EmitInt (ig, 0);
5380                                         ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0)));
5381                                 }
5382
5383                                 return;
5384                         }
5385
5386                         int top = arguments.Count;
5387
5388                         for (int i = 0; i < top; i++){
5389                                 Argument a = (Argument) arguments [i];
5390
5391                                 if (pd != null){
5392                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5393                                                 //
5394                                                 // Special case if we are passing the same data as the
5395                                                 // params argument, do not put it in an array.
5396                                                 //
5397                                                 if (pd.ParameterType (i) == a.Type)
5398                                                         a.Emit (ec);
5399                                                 else
5400                                                         EmitParams (ec, i, arguments);
5401                                                 return;
5402                                         }
5403                                 }
5404                                             
5405                                 a.Emit (ec);
5406                                 if (dup_args) {
5407                                         ec.ig.Emit (OpCodes.Dup);
5408                                         (temps [i] = new LocalTemporary (ec, a.Type)).Store (ec);
5409                                 }
5410                         }
5411                         
5412                         if (dup_args) {
5413                                 if (this_arg != null)
5414                                         this_arg.Emit (ec);
5415                                 
5416                                 for (int i = 0; i < top; i ++)
5417                                         temps [i].Emit (ec);
5418                         }
5419
5420                         if (pd != null && pd.Count > top &&
5421                             pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
5422                                 ILGenerator ig = ec.ig;
5423
5424                                 IntConstant.EmitInt (ig, 0);
5425                                 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
5426                         }
5427                 }
5428
5429                 static Type[] GetVarargsTypes (EmitContext ec, MethodBase mb,
5430                                                ArrayList arguments)
5431                 {
5432                         ParameterData pd = TypeManager.GetParameterData (mb);
5433
5434                         if (arguments == null)
5435                                 return new Type [0];
5436
5437                         Argument a = (Argument) arguments [pd.Count - 1];
5438                         Arglist list = (Arglist) a.Expr;
5439
5440                         return list.ArgumentTypes;
5441                 }
5442
5443                 /// <summary>
5444                 /// This checks the ConditionalAttribute on the method 
5445                 /// </summary>
5446                 static bool IsMethodExcluded (MethodBase method, EmitContext ec)
5447                 {
5448                         if (method.IsConstructor)
5449                                 return false;
5450
5451                         IMethodData md = TypeManager.GetMethod (method);
5452                         if (md != null)
5453                                 return md.IsExcluded (ec);
5454
5455                         // For some methods (generated by delegate class) GetMethod returns null
5456                         // because they are not included in builder_to_method table
5457                         if (method.DeclaringType is TypeBuilder)
5458                                 return false;
5459
5460                         return AttributeTester.IsConditionalMethodExcluded (method);
5461                 }
5462
5463                 /// <remarks>
5464                 ///   is_base tells whether we want to force the use of the `call'
5465                 ///   opcode instead of using callvirt.  Call is required to call
5466                 ///   a specific method, while callvirt will always use the most
5467                 ///   recent method in the vtable.
5468                 ///
5469                 ///   is_static tells whether this is an invocation on a static method
5470                 ///
5471                 ///   instance_expr is an expression that represents the instance
5472                 ///   it must be non-null if is_static is false.
5473                 ///
5474                 ///   method is the method to invoke.
5475                 ///
5476                 ///   Arguments is the list of arguments to pass to the method or constructor.
5477                 /// </remarks>
5478                 public static void EmitCall (EmitContext ec, bool is_base,
5479                                              bool is_static, Expression instance_expr,
5480                                              MethodBase method, ArrayList Arguments, Location loc)
5481                 {
5482                         EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
5483                 }
5484                 
5485                 // `dup_args' leaves an extra copy of the arguments on the stack
5486                 // `omit_args' does not leave any arguments at all.
5487                 // So, basically, you could make one call with `dup_args' set to true,
5488                 // and then another with `omit_args' set to true, and the two calls
5489                 // would have the same set of arguments. However, each argument would
5490                 // only have been evaluated once.
5491                 public static void EmitCall (EmitContext ec, bool is_base,
5492                                              bool is_static, Expression instance_expr,
5493                                              MethodBase method, ArrayList Arguments, Location loc,
5494                                              bool dup_args, bool omit_args)
5495                 {
5496                         ILGenerator ig = ec.ig;
5497                         bool struct_call = false;
5498                         bool this_call = false;
5499                         LocalTemporary this_arg = null;
5500
5501                         Type decl_type = method.DeclaringType;
5502
5503                         if (!RootContext.StdLib) {
5504                                 // Replace any calls to the system's System.Array type with calls to
5505                                 // the newly created one.
5506                                 if (method == TypeManager.system_int_array_get_length)
5507                                         method = TypeManager.int_array_get_length;
5508                                 else if (method == TypeManager.system_int_array_get_rank)
5509                                         method = TypeManager.int_array_get_rank;
5510                                 else if (method == TypeManager.system_object_array_clone)
5511                                         method = TypeManager.object_array_clone;
5512                                 else if (method == TypeManager.system_int_array_get_length_int)
5513                                         method = TypeManager.int_array_get_length_int;
5514                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5515                                         method = TypeManager.int_array_get_lower_bound_int;
5516                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5517                                         method = TypeManager.int_array_get_upper_bound_int;
5518                                 else if (method == TypeManager.system_void_array_copyto_array_int)
5519                                         method = TypeManager.void_array_copyto_array_int;
5520                         }
5521
5522                         if (ec.TestObsoleteMethodUsage) {
5523                                 //
5524                                 // This checks ObsoleteAttribute on the method and on the declaring type
5525                                 //
5526                                 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
5527                                 if (oa != null)
5528                                         AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
5529
5530
5531                                 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5532                                 if (oa != null) {
5533                                         AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5534                                 }
5535                         }
5536
5537                         if (IsMethodExcluded (method, ec))
5538                 return; 
5539                         
5540                         if (!is_static){
5541                                 if (instance_expr == EmptyExpression.Null) {
5542                                         SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
5543                                         return;
5544                                 }
5545
5546                                 this_call = instance_expr is This;
5547                                 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5548                                         struct_call = true;
5549                                 
5550                                 if (!omit_args) {
5551                                         Type t = null;
5552                                         //
5553                                         // Push the instance expression
5554                                         //
5555                                         if (instance_expr.Type.IsValueType) {
5556                                                 //
5557                                                 // Special case: calls to a function declared in a 
5558                                                 // reference-type with a value-type argument need
5559                                                 // to have their value boxed.
5560                                                 if (decl_type.IsValueType) {
5561                                                         //
5562                                                         // If the expression implements IMemoryLocation, then
5563                                                         // we can optimize and use AddressOf on the
5564                                                         // return.
5565                                                         //
5566                                                         // If not we have to use some temporary storage for
5567                                                         // it.
5568                                                         if (instance_expr is IMemoryLocation) {
5569                                                                 ((IMemoryLocation)instance_expr).
5570                                                                         AddressOf (ec, AddressOp.LoadStore);
5571                                                         } else {
5572                                                                 LocalTemporary temp = new LocalTemporary (ec, instance_expr.Type);
5573                                                                 instance_expr.Emit (ec);
5574                                                                 temp.Store (ec);
5575                                                                 temp.AddressOf (ec, AddressOp.Load);
5576                                                         }
5577                                                         
5578                                                         // avoid the overhead of doing this all the time.
5579                                                         if (dup_args)
5580                                                                 t = TypeManager.GetReferenceType (instance_expr.Type);
5581                                                 } else {
5582                                                         instance_expr.Emit (ec);
5583                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
5584                                                         t = TypeManager.object_type;
5585                                                 } 
5586                                         } else {
5587                                                 instance_expr.Emit (ec);
5588                                                 t = instance_expr.Type;
5589                                         }
5590
5591                                         if (dup_args) {
5592                                                 this_arg = new LocalTemporary (ec, t);
5593                                                 ig.Emit (OpCodes.Dup);
5594                                                 this_arg.Store (ec);
5595                                         }
5596                                 }
5597                         }
5598
5599                         if (!omit_args)
5600                                 EmitArguments (ec, method, Arguments, dup_args, this_arg);
5601
5602                         OpCode call_op;
5603                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5604                                 call_op = OpCodes.Call;
5605                         else
5606                                 call_op = OpCodes.Callvirt;
5607
5608                         if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5609                                 Type[] varargs_types = GetVarargsTypes (ec, method, Arguments);
5610                                 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5611                                 return;
5612                         }
5613
5614                         //
5615                         // If you have:
5616                         // this.DoFoo ();
5617                         // and DoFoo is not virtual, you can omit the callvirt,
5618                         // because you don't need the null checking behavior.
5619                         //
5620                         if (method is MethodInfo)
5621                                 ig.Emit (call_op, (MethodInfo) method);
5622                         else
5623                                 ig.Emit (call_op, (ConstructorInfo) method);
5624                 }
5625                 
5626                 public override void Emit (EmitContext ec)
5627                 {
5628                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5629
5630                         EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5631                 }
5632                 
5633                 public override void EmitStatement (EmitContext ec)
5634                 {
5635                         Emit (ec);
5636
5637                         // 
5638                         // Pop the return value if there is one
5639                         //
5640                         if (method is MethodInfo){
5641                                 Type ret = ((MethodInfo)method).ReturnType;
5642                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5643                                         ec.ig.Emit (OpCodes.Pop);
5644                         }
5645                 }
5646         }
5647
5648         public class InvocationOrCast : ExpressionStatement
5649         {
5650                 Expression expr;
5651                 Expression argument;
5652
5653                 public InvocationOrCast (Expression expr, Expression argument, Location loc)
5654                 {
5655                         this.expr = expr;
5656                         this.argument = argument;
5657                         this.loc = loc;
5658                 }
5659
5660                 public override Expression DoResolve (EmitContext ec)
5661                 {
5662                         //
5663                         // First try to resolve it as a cast.
5664                         //
5665                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5666                         if (te != null) {
5667                                 Cast cast = new Cast (te, argument, loc);
5668                                 return cast.Resolve (ec);
5669                         }
5670
5671                         //
5672                         // This can either be a type or a delegate invocation.
5673                         // Let's just resolve it and see what we'll get.
5674                         //
5675                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5676                         if (expr == null)
5677                                 return null;
5678
5679                         //
5680                         // Ok, so it's a Cast.
5681                         //
5682                         if (expr.eclass == ExprClass.Type) {
5683                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5684                                 return cast.Resolve (ec);
5685                         }
5686
5687                         //
5688                         // It's a delegate invocation.
5689                         //
5690                         if (!TypeManager.IsDelegateType (expr.Type)) {
5691                                 Error (149, "Method name expected");
5692                                 return null;
5693                         }
5694
5695                         ArrayList args = new ArrayList ();
5696                         args.Add (new Argument (argument, Argument.AType.Expression));
5697                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5698                         return invocation.Resolve (ec);
5699                 }
5700
5701                 void error201 ()
5702                 {
5703                         Error (201, "Only assignment, call, increment, decrement and new object " +
5704                                "expressions can be used as a statement");
5705                 }
5706
5707                 public override ExpressionStatement ResolveStatement (EmitContext ec)
5708                 {
5709                         //
5710                         // First try to resolve it as a cast.
5711                         //
5712                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5713                         if (te != null) {
5714                                 error201 ();
5715                                 return null;
5716                         }
5717
5718                         //
5719                         // This can either be a type or a delegate invocation.
5720                         // Let's just resolve it and see what we'll get.
5721                         //
5722                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5723                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5724                                 error201 ();
5725                                 return null;
5726                         }
5727
5728                         //
5729                         // It's a delegate invocation.
5730                         //
5731                         if (!TypeManager.IsDelegateType (expr.Type)) {
5732                                 Error (149, "Method name expected");
5733                                 return null;
5734                         }
5735
5736                         ArrayList args = new ArrayList ();
5737                         args.Add (new Argument (argument, Argument.AType.Expression));
5738                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5739                         return invocation.ResolveStatement (ec);
5740                 }
5741
5742                 public override void Emit (EmitContext ec)
5743                 {
5744                         throw new Exception ("Cannot happen");
5745                 }
5746
5747                 public override void EmitStatement (EmitContext ec)
5748                 {
5749                         throw new Exception ("Cannot happen");
5750                 }
5751         }
5752
5753         //
5754         // This class is used to "disable" the code generation for the
5755         // temporary variable when initializing value types.
5756         //
5757         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5758                 public void AddressOf (EmitContext ec, AddressOp Mode)
5759                 {
5760                         // nothing
5761                 }
5762         }
5763         
5764         /// <summary>
5765         ///    Implements the new expression 
5766         /// </summary>
5767         public class New : ExpressionStatement, IMemoryLocation {
5768                 public readonly ArrayList Arguments;
5769
5770                 //
5771                 // During bootstrap, it contains the RequestedType,
5772                 // but if `type' is not null, it *might* contain a NewDelegate
5773                 // (because of field multi-initialization)
5774                 //
5775                 public Expression RequestedType;
5776
5777                 MethodBase method = null;
5778
5779                 //
5780                 // If set, the new expression is for a value_target, and
5781                 // we will not leave anything on the stack.
5782                 //
5783                 Expression value_target;
5784                 bool value_target_set = false;
5785                 
5786                 public New (Expression requested_type, ArrayList arguments, Location l)
5787                 {
5788                         RequestedType = requested_type;
5789                         Arguments = arguments;
5790                         loc = l;
5791                 }
5792
5793                 public bool SetValueTypeVariable (Expression value)
5794                 {
5795                         value_target = value;
5796                         value_target_set = true;
5797                         if (!(value_target is IMemoryLocation)){
5798                                 Error_UnexpectedKind ("variable", loc);
5799                                 return false;
5800                         }
5801                         return true;
5802                 }
5803
5804                 //
5805                 // This function is used to disable the following code sequence for
5806                 // value type initialization:
5807                 //
5808                 // AddressOf (temporary)
5809                 // Construct/Init
5810                 // LoadTemporary
5811                 //
5812                 // Instead the provide will have provided us with the address on the
5813                 // stack to store the results.
5814                 //
5815                 static Expression MyEmptyExpression;
5816                 
5817                 public void DisableTemporaryValueType ()
5818                 {
5819                         if (MyEmptyExpression == null)
5820                                 MyEmptyExpression = new EmptyAddressOf ();
5821
5822                         //
5823                         // To enable this, look into:
5824                         // test-34 and test-89 and self bootstrapping.
5825                         //
5826                         // For instance, we can avoid a copy by using `newobj'
5827                         // instead of Call + Push-temp on value types.
5828 //                      value_target = MyEmptyExpression;
5829                 }
5830
5831
5832                 /// <summary>
5833                 /// Converts complex core type syntax like 'new int ()' to simple constant
5834                 /// </summary>
5835                 Expression Constantify (Type t)
5836                 {
5837                         if (t == TypeManager.int32_type)
5838                                 return new IntConstant (0);
5839                         if (t == TypeManager.uint32_type)
5840                                 return new UIntConstant (0);
5841                         if (t == TypeManager.int64_type)
5842                                 return new LongConstant (0);
5843                         if (t == TypeManager.uint64_type)
5844                                 return new ULongConstant (0);
5845                         if (t == TypeManager.float_type)
5846                                 return new FloatConstant (0);
5847                         if (t == TypeManager.double_type)
5848                                 return new DoubleConstant (0);
5849                         if (t == TypeManager.short_type)
5850                                 return new ShortConstant (0);
5851                         if (t == TypeManager.ushort_type)
5852                                 return new UShortConstant (0);
5853                         if (t == TypeManager.sbyte_type)
5854                                 return new SByteConstant (0);
5855                         if (t == TypeManager.byte_type)
5856                                 return new ByteConstant (0);
5857                         if (t == TypeManager.char_type)
5858                                 return new CharConstant ('\0');
5859                         if (t == TypeManager.bool_type)
5860                                 return new BoolConstant (false);
5861                         if (t == TypeManager.decimal_type)
5862                                 return new DecimalConstant (0);
5863
5864                         return null;
5865                 }
5866
5867                 public override Expression DoResolve (EmitContext ec)
5868                 {
5869                         //
5870                         // The New DoResolve might be called twice when initializing field
5871                         // expressions (see EmitFieldInitializers, the call to
5872                         // GetInitializerExpression will perform a resolve on the expression,
5873                         // and later the assign will trigger another resolution
5874                         //
5875                         // This leads to bugs (#37014)
5876                         //
5877                         if (type != null){
5878                                 if (RequestedType is NewDelegate)
5879                                         return RequestedType;
5880                                 return this;
5881                         }
5882                         
5883                         TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5884                         if (texpr == null)
5885                                 return null;
5886
5887                         type = texpr.ResolveType (ec);
5888
5889                         if (Arguments == null) {
5890                                 Expression c = Constantify (type);
5891                                 if (c != null)
5892                                         return c;
5893                         }
5894                         
5895                         CheckObsoleteAttribute (type);
5896
5897                         bool IsDelegate = TypeManager.IsDelegateType (type);
5898                         
5899                         if (IsDelegate){
5900                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5901                                 if (RequestedType != null)
5902                                         if (!(RequestedType is DelegateCreation))
5903                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5904                                 return RequestedType;
5905                         }
5906
5907                         if (type.IsAbstract && type.IsSealed) {
5908                                 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5909                                 return null;
5910                         }
5911
5912                         if (type.IsInterface || type.IsAbstract){
5913                                 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5914                                 return null;
5915                         }
5916                         
5917                         bool is_struct = type.IsValueType;
5918                         eclass = ExprClass.Value;
5919
5920                         //
5921                         // SRE returns a match for .ctor () on structs (the object constructor), 
5922                         // so we have to manually ignore it.
5923                         //
5924                         if (is_struct && Arguments == null)
5925                                 return this;
5926                         
5927                         Expression ml;
5928                         // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5929                         ml = MemberLookupFinal (ec, type, type, ".ctor",
5930                                                 MemberTypes.Constructor,
5931                                                 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5932
5933                         if (ml == null)
5934                                 return null;
5935                         
5936                         if (! (ml is MethodGroupExpr)){
5937                                 if (!is_struct){
5938                                         ml.Error_UnexpectedKind ("method group", loc);
5939                                         return null;
5940                                 }
5941                         }
5942
5943                         if (ml != null) {
5944                                 if (Arguments != null){
5945                                         foreach (Argument a in Arguments){
5946                                                 if (!a.Resolve (ec, loc))
5947                                                         return null;
5948                                         }
5949                                 }
5950
5951                                 method = Invocation.OverloadResolve (
5952                                         ec, (MethodGroupExpr) ml, Arguments, true, loc);
5953                                 
5954                         }
5955
5956                         if (method == null) {
5957                                 if (almostMatchedMembers.Count != 0) {
5958                                         MemberLookupFailed (ec, type, type, ".ctor", null, true, loc);
5959                                         return null;
5960                                 }
5961
5962                                 if (!is_struct || Arguments.Count > 0) {
5963                                         Invocation.Error_WrongNumArguments (loc, TypeManager.CSharpName (type),
5964                                                 Arguments == null ? 0 : Arguments.Count);
5965                                         return null;
5966                                 }
5967                         }
5968
5969                         return this;
5970                 }
5971
5972                 //
5973                 // This DoEmit can be invoked in two contexts:
5974                 //    * As a mechanism that will leave a value on the stack (new object)
5975                 //    * As one that wont (init struct)
5976                 //
5977                 // You can control whether a value is required on the stack by passing
5978                 // need_value_on_stack.  The code *might* leave a value on the stack
5979                 // so it must be popped manually
5980                 //
5981                 // If we are dealing with a ValueType, we have a few
5982                 // situations to deal with:
5983                 //
5984                 //    * The target is a ValueType, and we have been provided
5985                 //      the instance (this is easy, we are being assigned).
5986                 //
5987                 //    * The target of New is being passed as an argument,
5988                 //      to a boxing operation or a function that takes a
5989                 //      ValueType.
5990                 //
5991                 //      In this case, we need to create a temporary variable
5992                 //      that is the argument of New.
5993                 //
5994                 // Returns whether a value is left on the stack
5995                 //
5996                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5997                 {
5998                         bool is_value_type = type.IsValueType;
5999                         ILGenerator ig = ec.ig;
6000
6001                         if (is_value_type){
6002                                 IMemoryLocation ml;
6003
6004                                 // Allow DoEmit() to be called multiple times.
6005                                 // We need to create a new LocalTemporary each time since
6006                                 // you can't share LocalBuilders among ILGeneators.
6007                                 if (!value_target_set)
6008                                         value_target = new LocalTemporary (ec, type);
6009
6010                                 ml = (IMemoryLocation) value_target;
6011                                 ml.AddressOf (ec, AddressOp.Store);
6012                         }
6013
6014                         if (method != null)
6015                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
6016
6017                         if (is_value_type){
6018                                 if (method == null)
6019                                         ig.Emit (OpCodes.Initobj, type);
6020                                 else 
6021                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6022                                 if (need_value_on_stack){
6023                                         value_target.Emit (ec);
6024                                         return true;
6025                                 }
6026                                 return false;
6027                         } else {
6028                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
6029                                 return true;
6030                         }
6031                 }
6032
6033                 public override void Emit (EmitContext ec)
6034                 {
6035                         DoEmit (ec, true);
6036                 }
6037                 
6038                 public override void EmitStatement (EmitContext ec)
6039                 {
6040                         if (DoEmit (ec, false))
6041                                 ec.ig.Emit (OpCodes.Pop);
6042                 }
6043
6044                 public void AddressOf (EmitContext ec, AddressOp Mode)
6045                 {
6046                         if (!type.IsValueType){
6047                                 //
6048                                 // We throw an exception.  So far, I believe we only need to support
6049                                 // value types:
6050                                 // foreach (int j in new StructType ())
6051                                 // see bug 42390
6052                                 //
6053                                 throw new Exception ("AddressOf should not be used for classes");
6054                         }
6055
6056                         if (!value_target_set)
6057                                 value_target = new LocalTemporary (ec, type);
6058                                         
6059                         IMemoryLocation ml = (IMemoryLocation) value_target;
6060                         ml.AddressOf (ec, AddressOp.Store);
6061                         if (method != null)
6062                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
6063
6064                         if (method == null)
6065                                 ec.ig.Emit (OpCodes.Initobj, type);
6066                         else 
6067                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
6068                         
6069                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
6070                 }
6071         }
6072
6073         /// <summary>
6074         ///   14.5.10.2: Represents an array creation expression.
6075         /// </summary>
6076         ///
6077         /// <remarks>
6078         ///   There are two possible scenarios here: one is an array creation
6079         ///   expression that specifies the dimensions and optionally the
6080         ///   initialization data and the other which does not need dimensions
6081         ///   specified but where initialization data is mandatory.
6082         /// </remarks>
6083         public class ArrayCreation : Expression {
6084                 Expression requested_base_type;
6085                 ArrayList initializers;
6086
6087                 //
6088                 // The list of Argument types.
6089                 // This is used to construct the `newarray' or constructor signature
6090                 //
6091                 ArrayList arguments;
6092
6093                 //
6094                 // Method used to create the array object.
6095                 //
6096                 MethodBase new_method = null;
6097                 
6098                 Type array_element_type;
6099                 Type underlying_type;
6100                 bool is_one_dimensional = false;
6101                 bool is_builtin_type = false;
6102                 bool expect_initializers = false;
6103                 int num_arguments = 0;
6104                 int dimensions = 0;
6105                 string rank;
6106
6107                 ArrayList array_data;
6108
6109                 Hashtable bounds;
6110
6111                 //
6112                 // The number of array initializers that we can handle
6113                 // via the InitializeArray method - through EmitStaticInitializers
6114                 //
6115                 int num_automatic_initializers;
6116
6117                 const int max_automatic_initializers = 6;
6118                 
6119                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
6120                 {
6121                         this.requested_base_type = requested_base_type;
6122                         this.initializers = initializers;
6123                         this.rank = rank;
6124                         loc = l;
6125
6126                         arguments = new ArrayList ();
6127
6128                         foreach (Expression e in exprs) {
6129                                 arguments.Add (new Argument (e, Argument.AType.Expression));
6130                                 num_arguments++;
6131                         }
6132                 }
6133
6134                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
6135                 {
6136                         this.requested_base_type = requested_base_type;
6137                         this.initializers = initializers;
6138                         this.rank = rank;
6139                         loc = l;
6140
6141                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
6142                         //
6143                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
6144                         //
6145                         //dimensions = tmp.Length - 1;
6146                         expect_initializers = true;
6147                 }
6148
6149                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
6150                 {
6151                         StringBuilder sb = new StringBuilder (rank);
6152                         
6153                         sb.Append ("[");
6154                         for (int i = 1; i < idx_count; i++)
6155                                 sb.Append (",");
6156                         
6157                         sb.Append ("]");
6158
6159                         return new ComposedCast (base_type, sb.ToString (), loc);
6160                 }
6161
6162                 void Error_IncorrectArrayInitializer ()
6163                 {
6164                         Error (178, "Invalid rank specifier: expected `,' or `]'");
6165                 }
6166                 
6167                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
6168                 {
6169                         if (specified_dims) { 
6170                                 Argument a = (Argument) arguments [idx];
6171                                 
6172                                 if (!a.Resolve (ec, loc))
6173                                         return false;
6174                                 
6175                                 if (!(a.Expr is Constant)) {
6176                                         Error (150, "A constant value is expected");
6177                                         return false;
6178                                 }
6179                                 
6180                                 int value = (int) ((Constant) a.Expr).GetValue ();
6181                                 
6182                                 if (value != probe.Count) {
6183                                         Error_IncorrectArrayInitializer ();
6184                                         return false;
6185                                 }
6186                                 
6187                                 bounds [idx] = value;
6188                         }
6189
6190                         int child_bounds = -1;
6191                         for (int i = 0; i < probe.Count; ++i) {
6192                                 object o = probe [i];
6193                                 if (o is ArrayList) {
6194                                         ArrayList sub_probe = o as ArrayList;
6195                                         int current_bounds = sub_probe.Count;
6196                                         
6197                                         if (child_bounds == -1) 
6198                                                 child_bounds = current_bounds;
6199
6200                                         else if (child_bounds != current_bounds){
6201                                                 Error_IncorrectArrayInitializer ();
6202                                                 return false;
6203                                         }
6204                                         if (specified_dims && (idx + 1 >= arguments.Count)){
6205                                                 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6206                                                 return false;
6207                                         }
6208                                         
6209                                         bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
6210                                         if (!ret)
6211                                                 return false;
6212                                 } else {
6213                                         if (child_bounds != -1){
6214                                                 Error_IncorrectArrayInitializer ();
6215                                                 return false;
6216                                         }
6217                                         
6218                                         Expression tmp = (Expression) o;
6219                                         tmp = tmp.Resolve (ec);
6220                                         probe [i] = tmp;
6221                                         if (tmp == null)
6222                                                 return false;
6223
6224                                         // Console.WriteLine ("I got: " + tmp);
6225                                         // Handle initialization from vars, fields etc.
6226
6227                                         Expression conv = Convert.ImplicitConversionRequired (
6228                                                 ec, tmp, underlying_type, loc);
6229                                         
6230                                         if (conv == null) 
6231                                                 return false;
6232                                         
6233                                         if (conv is StringConstant || conv is DecimalConstant || conv is NullCast) {
6234                                                 // These are subclasses of Constant that can appear as elements of an
6235                                                 // array that cannot be statically initialized (with num_automatic_initializers
6236                                                 // > max_automatic_initializers), so num_automatic_initializers should be left as zero.
6237                                                 array_data.Add (conv);
6238                                         } else if (conv is Constant) {
6239                                                 // These are the types of Constant that can appear in arrays that can be
6240                                                 // statically allocated.
6241                                                 array_data.Add (conv);
6242                                                 num_automatic_initializers++;
6243                                         } else
6244                                                 array_data.Add (conv);
6245                                 }
6246                         }
6247
6248                         return true;
6249                 }
6250                 
6251                 public void UpdateIndices (EmitContext ec)
6252                 {
6253                         int i = 0;
6254                         for (ArrayList probe = initializers; probe != null;) {
6255                                 if (probe.Count > 0 && probe [0] is ArrayList) {
6256                                         Expression e = new IntConstant (probe.Count);
6257                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6258
6259                                         bounds [i++] =  probe.Count;
6260                                         
6261                                         probe = (ArrayList) probe [0];
6262                                         
6263                                 } else {
6264                                         Expression e = new IntConstant (probe.Count);
6265                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6266
6267                                         bounds [i++] = probe.Count;
6268                                         probe = null;
6269                                 }
6270                         }
6271
6272                 }
6273                 
6274                 public bool ValidateInitializers (EmitContext ec, Type array_type)
6275                 {
6276                         if (initializers == null) {
6277                                 if (expect_initializers)
6278                                         return false;
6279                                 else
6280                                         return true;
6281                         }
6282                         
6283                         if (underlying_type == null)
6284                                 return false;
6285                         
6286                         //
6287                         // We use this to store all the date values in the order in which we
6288                         // will need to store them in the byte blob later
6289                         //
6290                         array_data = new ArrayList ();
6291                         bounds = new Hashtable ();
6292                         
6293                         bool ret;
6294
6295                         if (arguments != null) {
6296                                 ret = CheckIndices (ec, initializers, 0, true);
6297                                 return ret;
6298                         } else {
6299                                 arguments = new ArrayList ();
6300
6301                                 ret = CheckIndices (ec, initializers, 0, false);
6302                                 
6303                                 if (!ret)
6304                                         return false;
6305                                 
6306                                 UpdateIndices (ec);
6307                                 
6308                                 if (arguments.Count != dimensions) {
6309                                         Error_IncorrectArrayInitializer ();
6310                                         return false;
6311                                 }
6312
6313                                 return ret;
6314                         }
6315                 }
6316
6317                 //
6318                 // Creates the type of the array
6319                 //
6320                 bool LookupType (EmitContext ec)
6321                 {
6322                         StringBuilder array_qualifier = new StringBuilder (rank);
6323
6324                         //
6325                         // `In the first form allocates an array instace of the type that results
6326                         // from deleting each of the individual expression from the expression list'
6327                         //
6328                         if (num_arguments > 0) {
6329                                 array_qualifier.Append ("[");
6330                                 for (int i = num_arguments-1; i > 0; i--)
6331                                         array_qualifier.Append (",");
6332                                 array_qualifier.Append ("]");                           
6333                         }
6334
6335                         //
6336                         // Lookup the type
6337                         //
6338                         TypeExpr array_type_expr;
6339                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6340                         array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6341                         if (array_type_expr == null)
6342                                 return false;
6343
6344                         type = array_type_expr.ResolveType (ec);
6345                         
6346                         if (!type.IsArray) {
6347                                 Error (622, "Can only use array initializer expressions to assign to array types. Try using a new expression instead.");
6348                                 return false;
6349                         }
6350                         underlying_type = TypeManager.GetElementType (type);
6351                         dimensions = type.GetArrayRank ();
6352
6353                         return true;
6354                 }
6355                 
6356                 public override Expression DoResolve (EmitContext ec)
6357                 {
6358                         int arg_count;
6359
6360                         if (!LookupType (ec))
6361                                 return null;
6362                         
6363                         //
6364                         // First step is to validate the initializers and fill
6365                         // in any missing bits
6366                         //
6367                         if (!ValidateInitializers (ec, type))
6368                                 return null;
6369
6370                         if (arguments == null)
6371                                 arg_count = 0;
6372                         else {
6373                                 arg_count = arguments.Count;
6374                                 foreach (Argument a in arguments){
6375                                         if (!a.Resolve (ec, loc))
6376                                                 return null;
6377
6378                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6379                                         if (real_arg == null)
6380                                                 return null;
6381
6382                                         a.Expr = real_arg;
6383                                 }
6384                         }
6385                         
6386                         array_element_type = TypeManager.GetElementType (type);
6387
6388                         if (array_element_type.IsAbstract && array_element_type.IsSealed) {
6389                                 Report.Error (719, loc, "`{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
6390                                 return null;
6391                         }
6392
6393                         if (arg_count == 1) {
6394                                 is_one_dimensional = true;
6395                                 eclass = ExprClass.Value;
6396                                 return this;
6397                         }
6398
6399                         is_builtin_type = TypeManager.IsBuiltinType (type);
6400
6401                         if (is_builtin_type) {
6402                                 Expression ml;
6403                                 
6404                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
6405                                                    AllBindingFlags, loc);
6406                                 
6407                                 if (!(ml is MethodGroupExpr)) {
6408                                         ml.Error_UnexpectedKind ("method group", loc);
6409                                         return null;
6410                                 }
6411                                 
6412                                 if (ml == null) {
6413                                         Error (-6, "New invocation: Can not find a constructor for " +
6414                                                       "this argument list");
6415                                         return null;
6416                                 }
6417                                 
6418                                 new_method = Invocation.OverloadResolve (
6419                                         ec, (MethodGroupExpr) ml, arguments, false, loc);
6420
6421                                 if (new_method == null) {
6422                                         Error (-6, "New invocation: Can not find a constructor for " +
6423                                                       "this argument list");
6424                                         return null;
6425                                 }
6426                                 
6427                                 eclass = ExprClass.Value;
6428                                 return this;
6429                         } else {
6430                                 ModuleBuilder mb = CodeGen.Module.Builder;
6431                                 ArrayList args = new ArrayList ();
6432                                 
6433                                 if (arguments != null) {
6434                                         for (int i = 0; i < arg_count; i++)
6435                                                 args.Add (TypeManager.int32_type);
6436                                 }
6437                                 
6438                                 Type [] arg_types = null;
6439
6440                                 if (args.Count > 0)
6441                                         arg_types = new Type [args.Count];
6442                                 
6443                                 args.CopyTo (arg_types, 0);
6444                                 
6445                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6446                                                             arg_types);
6447
6448                                 if (new_method == null) {
6449                                         Error (-6, "New invocation: Can not find a constructor for " +
6450                                                       "this argument list");
6451                                         return null;
6452                                 }
6453                                 
6454                                 eclass = ExprClass.Value;
6455                                 return this;
6456                         }
6457                 }
6458
6459                 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
6460                 {
6461                         int factor;
6462                         byte [] data;
6463                         byte [] element;
6464                         int count = array_data.Count;
6465
6466                         if (underlying_type.IsEnum)
6467                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6468                         
6469                         factor = GetTypeSize (underlying_type);
6470                         if (factor == 0)
6471                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6472
6473                         data = new byte [(count * factor + 4) & ~3];
6474                         int idx = 0;
6475                         
6476                         for (int i = 0; i < count; ++i) {
6477                                 object v = array_data [i];
6478
6479                                 if (v is EnumConstant)
6480                                         v = ((EnumConstant) v).Child;
6481                                 
6482                                 if (v is Constant && !(v is StringConstant))
6483                                         v = ((Constant) v).GetValue ();
6484                                 else {
6485                                         idx += factor;
6486                                         continue;
6487                                 }
6488                                 
6489                                 if (underlying_type == TypeManager.int64_type){
6490                                         if (!(v is Expression)){
6491                                                 long val = (long) v;
6492                                                 
6493                                                 for (int j = 0; j < factor; ++j) {
6494                                                         data [idx + j] = (byte) (val & 0xFF);
6495                                                         val = (val >> 8);
6496                                                 }
6497                                         }
6498                                 } else if (underlying_type == TypeManager.uint64_type){
6499                                         if (!(v is Expression)){
6500                                                 ulong val = (ulong) v;
6501
6502                                                 for (int j = 0; j < factor; ++j) {
6503                                                         data [idx + j] = (byte) (val & 0xFF);
6504                                                         val = (val >> 8);
6505                                                 }
6506                                         }
6507                                 } else if (underlying_type == TypeManager.float_type) {
6508                                         if (!(v is Expression)){
6509                                                 element = BitConverter.GetBytes ((float) v);
6510                                                         
6511                                                 for (int j = 0; j < factor; ++j)
6512                                                         data [idx + j] = element [j];
6513                                         }
6514                                 } else if (underlying_type == TypeManager.double_type) {
6515                                         if (!(v is Expression)){
6516                                                 element = BitConverter.GetBytes ((double) v);
6517
6518                                                 for (int j = 0; j < factor; ++j)
6519                                                         data [idx + j] = element [j];
6520                                         }
6521                                 } else if (underlying_type == TypeManager.char_type){
6522                                         if (!(v is Expression)){
6523                                                 int val = (int) ((char) v);
6524                                                 
6525                                                 data [idx] = (byte) (val & 0xff);
6526                                                 data [idx+1] = (byte) (val >> 8);
6527                                         }
6528                                 } else if (underlying_type == TypeManager.short_type){
6529                                         if (!(v is Expression)){
6530                                                 int val = (int) ((short) v);
6531                                         
6532                                                 data [idx] = (byte) (val & 0xff);
6533                                                 data [idx+1] = (byte) (val >> 8);
6534                                         }
6535                                 } else if (underlying_type == TypeManager.ushort_type){
6536                                         if (!(v is Expression)){
6537                                                 int val = (int) ((ushort) v);
6538                                         
6539                                                 data [idx] = (byte) (val & 0xff);
6540                                                 data [idx+1] = (byte) (val >> 8);
6541                                         }
6542                                 } else if (underlying_type == TypeManager.int32_type) {
6543                                         if (!(v is Expression)){
6544                                                 int val = (int) v;
6545                                         
6546                                                 data [idx]   = (byte) (val & 0xff);
6547                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6548                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6549                                                 data [idx+3] = (byte) (val >> 24);
6550                                         }
6551                                 } else if (underlying_type == TypeManager.uint32_type) {
6552                                         if (!(v is Expression)){
6553                                                 uint val = (uint) v;
6554                                         
6555                                                 data [idx]   = (byte) (val & 0xff);
6556                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6557                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6558                                                 data [idx+3] = (byte) (val >> 24);
6559                                         }
6560                                 } else if (underlying_type == TypeManager.sbyte_type) {
6561                                         if (!(v is Expression)){
6562                                                 sbyte val = (sbyte) v;
6563                                                 data [idx] = (byte) val;
6564                                         }
6565                                 } else if (underlying_type == TypeManager.byte_type) {
6566                                         if (!(v is Expression)){
6567                                                 byte val = (byte) v;
6568                                                 data [idx] = (byte) val;
6569                                         }
6570                                 } else if (underlying_type == TypeManager.bool_type) {
6571                                         if (!(v is Expression)){
6572                                                 bool val = (bool) v;
6573                                                 data [idx] = (byte) (val ? 1 : 0);
6574                                         }
6575                                 } else if (underlying_type == TypeManager.decimal_type){
6576                                         if (!(v is Expression)){
6577                                                 int [] bits = Decimal.GetBits ((decimal) v);
6578                                                 int p = idx;
6579
6580                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
6581                                                 int [] nbits = new int [4];
6582                                                 nbits [0] = bits [3];
6583                                                 nbits [1] = bits [2];
6584                                                 nbits [2] = bits [0];
6585                                                 nbits [3] = bits [1];
6586                                                 
6587                                                 for (int j = 0; j < 4; j++){
6588                                                         data [p++] = (byte) (nbits [j] & 0xff);
6589                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6590                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6591                                                         data [p++] = (byte) (nbits [j] >> 24);
6592                                                 }
6593                                         }
6594                                 } else
6595                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6596
6597                                 idx += factor;
6598                         }
6599
6600                         return data;
6601                 }
6602
6603                 //
6604                 // Emits the initializers for the array
6605                 //
6606                 void EmitStaticInitializers (EmitContext ec)
6607                 {
6608                         //
6609                         // First, the static data
6610                         //
6611                         FieldBuilder fb;
6612                         ILGenerator ig = ec.ig;
6613                         
6614                         byte [] data = MakeByteBlob (array_data, underlying_type, loc);
6615
6616                         fb = RootContext.MakeStaticData (data);
6617
6618                         ig.Emit (OpCodes.Dup);
6619                         ig.Emit (OpCodes.Ldtoken, fb);
6620                         ig.Emit (OpCodes.Call,
6621                                  TypeManager.void_initializearray_array_fieldhandle);
6622                 }
6623
6624                 //
6625                 // Emits pieces of the array that can not be computed at compile
6626                 // time (variables and string locations).
6627                 //
6628                 // This always expect the top value on the stack to be the array
6629                 //
6630                 void EmitDynamicInitializers (EmitContext ec)
6631                 {
6632                         ILGenerator ig = ec.ig;
6633                         int dims = bounds.Count;
6634                         int [] current_pos = new int [dims];
6635                         int top = array_data.Count;
6636
6637                         MethodInfo set = null;
6638
6639                         if (dims != 1){
6640                                 Type [] args;
6641                                 ModuleBuilder mb = null;
6642                                 mb = CodeGen.Module.Builder;
6643                                 args = new Type [dims + 1];
6644
6645                                 int j;
6646                                 for (j = 0; j < dims; j++)
6647                                         args [j] = TypeManager.int32_type;
6648
6649                                 args [j] = array_element_type;
6650                                 
6651                                 set = mb.GetArrayMethod (
6652                                         type, "Set",
6653                                         CallingConventions.HasThis | CallingConventions.Standard,
6654                                         TypeManager.void_type, args);
6655                         }
6656                         
6657                         for (int i = 0; i < top; i++){
6658
6659                                 Expression e = null;
6660
6661                                 if (array_data [i] is Expression)
6662                                         e = (Expression) array_data [i];
6663
6664                                 if (e != null) {
6665                                         //
6666                                         // Basically we do this for string literals and
6667                                         // other non-literal expressions
6668                                         //
6669                                         if (e is EnumConstant){
6670                                                 e = ((EnumConstant) e).Child;
6671                                         }
6672                                         
6673                                         if (e is StringConstant || e is DecimalConstant || !(e is Constant) ||
6674                                             num_automatic_initializers <= max_automatic_initializers) {
6675                                                 Type etype = e.Type;
6676                                                 
6677                                                 ig.Emit (OpCodes.Dup);
6678
6679                                                 for (int idx = 0; idx < dims; idx++) 
6680                                                         IntConstant.EmitInt (ig, current_pos [idx]);
6681
6682                                                 //
6683                                                 // If we are dealing with a struct, get the
6684                                                 // address of it, so we can store it.
6685                                                 //
6686                                                 if ((dims == 1) && 
6687                                                     etype.IsSubclassOf (TypeManager.value_type) &&
6688                                                     (!TypeManager.IsBuiltinOrEnum (etype) ||
6689                                                      etype == TypeManager.decimal_type)) {
6690                                                         if (e is New){
6691                                                                 New n = (New) e;
6692
6693                                                                 //
6694                                                                 // Let new know that we are providing
6695                                                                 // the address where to store the results
6696                                                                 //
6697                                                                 n.DisableTemporaryValueType ();
6698                                                         }
6699
6700                                                         ig.Emit (OpCodes.Ldelema, etype);
6701                                                 }
6702
6703                                                 e.Emit (ec);
6704
6705                                                 if (dims == 1) {
6706                                                         bool is_stobj;
6707                                                         OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj);
6708                                                         if (is_stobj)
6709                                                                 ig.Emit (OpCodes.Stobj, etype);
6710                                                         else
6711                                                                 ig.Emit (op);
6712                                                 } else 
6713                                                         ig.Emit (OpCodes.Call, set);
6714
6715                                         }
6716                                 }
6717                                 
6718                                 //
6719                                 // Advance counter
6720                                 //
6721                                 for (int j = dims - 1; j >= 0; j--){
6722                                         current_pos [j]++;
6723                                         if (current_pos [j] < (int) bounds [j])
6724                                                 break;
6725                                         current_pos [j] = 0;
6726                                 }
6727                         }
6728                 }
6729
6730                 void EmitArrayArguments (EmitContext ec)
6731                 {
6732                         ILGenerator ig = ec.ig;
6733                         
6734                         foreach (Argument a in arguments) {
6735                                 Type atype = a.Type;
6736                                 a.Emit (ec);
6737
6738                                 if (atype == TypeManager.uint64_type)
6739                                         ig.Emit (OpCodes.Conv_Ovf_U4);
6740                                 else if (atype == TypeManager.int64_type)
6741                                         ig.Emit (OpCodes.Conv_Ovf_I4);
6742                         }
6743                 }
6744                 
6745                 public override void Emit (EmitContext ec)
6746                 {
6747                         ILGenerator ig = ec.ig;
6748                         
6749                         EmitArrayArguments (ec);
6750                         if (is_one_dimensional)
6751                                 ig.Emit (OpCodes.Newarr, array_element_type);
6752                         else {
6753                                 if (is_builtin_type) 
6754                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6755                                 else 
6756                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6757                         }
6758                         
6759                         if (initializers != null){
6760                                 //
6761                                 // FIXME: Set this variable correctly.
6762                                 // 
6763                                 bool dynamic_initializers = true;
6764
6765                                 // This will never be true for array types that cannot be statically
6766                                 // initialized. num_automatic_initializers will always be zero.  See
6767                                 // CheckIndices.
6768                                 if (num_automatic_initializers > max_automatic_initializers)
6769                                         EmitStaticInitializers (ec);
6770                                 
6771                                 if (dynamic_initializers)
6772                                         EmitDynamicInitializers (ec);
6773                         }
6774                 }
6775
6776                 public object EncodeAsAttribute ()
6777                 {
6778                         if (!is_one_dimensional){
6779                                 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6780                                 return null;
6781                         }
6782
6783                         if (array_data == null){
6784                                 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6785                                 return null;
6786                         }
6787                         
6788                         object [] ret = new object [array_data.Count];
6789                         int i = 0;
6790                         foreach (Expression e in array_data){
6791                                 object v;
6792                                 
6793                                 if (e is NullLiteral)
6794                                         v = null;
6795                                 else {
6796                                         if (!Attribute.GetAttributeArgumentExpression (e, Location, array_element_type, out v))
6797                                                 return null;
6798                                 }
6799                                 ret [i++] = v;
6800                         }
6801                         return ret;
6802                 }
6803         }
6804         
6805         /// <summary>
6806         ///   Represents the `this' construct
6807         /// </summary>
6808         public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
6809
6810                 Block block;
6811                 VariableInfo variable_info;
6812                 
6813                 public This (Block block, Location loc)
6814                 {
6815                         this.loc = loc;
6816                         this.block = block;
6817                 }
6818
6819                 public This (Location loc)
6820                 {
6821                         this.loc = loc;
6822                 }
6823
6824                 public VariableInfo VariableInfo {
6825                         get { return variable_info; }
6826                 }
6827
6828                 public bool VerifyFixed ()
6829                 {
6830                         // Treat 'this' as a value parameter for the purpose of fixed variable determination.
6831                         return true;
6832                 }
6833
6834                 public bool ResolveBase (EmitContext ec)
6835                 {
6836                         eclass = ExprClass.Variable;
6837                         type = ec.ContainerType;
6838
6839                         if (ec.IsStatic) {
6840                                 Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
6841                                 return false;
6842                         }
6843
6844                         if (block != null && block.Toplevel.ThisVariable != null)
6845                                 variable_info = block.Toplevel.ThisVariable.VariableInfo;
6846
6847                         if (ec.CurrentAnonymousMethod != null)
6848                                 ec.CaptureThis ();
6849                         
6850                         return true;
6851                 }
6852
6853                 public override Expression DoResolve (EmitContext ec)
6854                 {
6855                         if (!ResolveBase (ec))
6856                                 return null;
6857
6858                         if ((variable_info != null) && !variable_info.IsAssigned (ec)) {
6859                                 Error (188, "The `this' object cannot be used before all of its fields are assigned to");
6860                                 variable_info.SetAssigned (ec);
6861                                 return this;
6862                         }
6863
6864                         if (ec.IsFieldInitializer) {
6865                                 Error (27, "Keyword `this' is not available in the current context");
6866                                 return null;
6867                         }
6868
6869                         return this;
6870                 }
6871
6872                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6873                 {
6874                         if (!ResolveBase (ec))
6875                                 return null;
6876
6877                         if (variable_info != null)
6878                                 variable_info.SetAssigned (ec);
6879                         
6880                         if (ec.TypeContainer is Class){
6881                                 Error (1604, "Cannot assign to 'this' because it is read-only");
6882                                 return null;
6883                         }
6884
6885                         return this;
6886                 }
6887
6888                 public void Emit (EmitContext ec, bool leave_copy)
6889                 {
6890                         Emit (ec);
6891                         if (leave_copy)
6892                                 ec.ig.Emit (OpCodes.Dup);
6893                 }
6894                 
6895                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
6896                 {
6897                         ILGenerator ig = ec.ig;
6898                         
6899                         if (ec.TypeContainer is Struct){
6900                                 ec.EmitThis ();
6901                                 source.Emit (ec);
6902                                 if (leave_copy)
6903                                         ec.ig.Emit (OpCodes.Dup);
6904                                 ig.Emit (OpCodes.Stobj, type);
6905                         } else {
6906                                 throw new Exception ("how did you get here");
6907                         }
6908                 }
6909                 
6910                 public override void Emit (EmitContext ec)
6911                 {
6912                         ILGenerator ig = ec.ig;
6913
6914                         ec.EmitThis ();
6915                         if (ec.TypeContainer is Struct)
6916                                 ig.Emit (OpCodes.Ldobj, type);
6917                 }
6918
6919                 public override int GetHashCode()
6920                 {
6921                         return block.GetHashCode ();
6922                 }
6923
6924                 public override bool Equals (object obj)
6925                 {
6926                         This t = obj as This;
6927                         if (t == null)
6928                                 return false;
6929
6930                         return block == t.block;
6931                 }
6932
6933                 public void AddressOf (EmitContext ec, AddressOp mode)
6934                 {
6935                         ec.EmitThis ();
6936
6937                         // FIMXE
6938                         // FIGURE OUT WHY LDARG_S does not work
6939                         //
6940                         // consider: struct X { int val; int P { set { val = value; }}}
6941                         //
6942                         // Yes, this looks very bad. Look at `NOTAS' for
6943                         // an explanation.
6944                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6945                 }
6946         }
6947
6948         /// <summary>
6949         ///   Represents the `__arglist' construct
6950         /// </summary>
6951         public class ArglistAccess : Expression
6952         {
6953                 public ArglistAccess (Location loc)
6954                 {
6955                         this.loc = loc;
6956                 }
6957
6958                 public bool ResolveBase (EmitContext ec)
6959                 {
6960                         eclass = ExprClass.Variable;
6961                         type = TypeManager.runtime_argument_handle_type;
6962                         return true;
6963                 }
6964
6965                 public override Expression DoResolve (EmitContext ec)
6966                 {
6967                         if (!ResolveBase (ec))
6968                                 return null;
6969
6970                         if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs) {
6971                                 Error (190, "The __arglist construct is valid only within " +
6972                                        "a variable argument method.");
6973                                 return null;
6974                         }
6975
6976                         return this;
6977                 }
6978
6979                 public override void Emit (EmitContext ec)
6980                 {
6981                         ec.ig.Emit (OpCodes.Arglist);
6982                 }
6983         }
6984
6985         /// <summary>
6986         ///   Represents the `__arglist (....)' construct
6987         /// </summary>
6988         public class Arglist : Expression
6989         {
6990                 public readonly Argument[] Arguments;
6991
6992                 public Arglist (Argument[] args, Location l)
6993                 {
6994                         Arguments = args;
6995                         loc = l;
6996                 }
6997
6998                 public Type[] ArgumentTypes {
6999                         get {
7000                                 Type[] retval = new Type [Arguments.Length];
7001                                 for (int i = 0; i < Arguments.Length; i++)
7002                                         retval [i] = Arguments [i].Type;
7003                                 return retval;
7004                         }
7005                 }
7006
7007                 public override Expression DoResolve (EmitContext ec)
7008                 {
7009                         eclass = ExprClass.Variable;
7010                         type = TypeManager.runtime_argument_handle_type;
7011
7012                         foreach (Argument arg in Arguments) {
7013                                 if (!arg.Resolve (ec, loc))
7014                                         return null;
7015                         }
7016
7017                         return this;
7018                 }
7019
7020                 public override void Emit (EmitContext ec)
7021                 {
7022                         foreach (Argument arg in Arguments)
7023                                 arg.Emit (ec);
7024                 }
7025         }
7026
7027         //
7028         // This produces the value that renders an instance, used by the iterators code
7029         //
7030         public class ProxyInstance : Expression, IMemoryLocation  {
7031                 public override Expression DoResolve (EmitContext ec)
7032                 {
7033                         eclass = ExprClass.Variable;
7034                         type = ec.ContainerType;
7035                         return this;
7036                 }
7037                 
7038                 public override void Emit (EmitContext ec)
7039                 {
7040                         ec.ig.Emit (OpCodes.Ldarg_0);
7041
7042                 }
7043                 
7044                 public void AddressOf (EmitContext ec, AddressOp mode)
7045                 {
7046                         ec.ig.Emit (OpCodes.Ldarg_0);
7047                 }
7048         }
7049
7050         /// <summary>
7051         ///   Implements the typeof operator
7052         /// </summary>
7053         public class TypeOf : Expression {
7054                 public Expression QueriedType;
7055                 protected Type typearg;
7056                 
7057                 public TypeOf (Expression queried_type, Location l)
7058                 {
7059                         QueriedType = queried_type;
7060                         loc = l;
7061                 }
7062
7063                 public override Expression DoResolve (EmitContext ec)
7064                 {
7065                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7066                         if (texpr == null)
7067                                 return null;
7068
7069                         typearg = texpr.ResolveType (ec);
7070
7071                         if (typearg == TypeManager.void_type) {
7072                                 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
7073                                 return null;
7074                         }
7075
7076                         if (typearg.IsPointer && !ec.InUnsafe){
7077                                 UnsafeError (loc);
7078                                 return null;
7079                         }
7080                         CheckObsoleteAttribute (typearg);
7081
7082                         type = TypeManager.type_type;
7083                         // Even though what is returned is a type object, it's treated as a value by the compiler.
7084                         // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
7085                         eclass = ExprClass.Value;
7086                         return this;
7087                 }
7088
7089                 public override void Emit (EmitContext ec)
7090                 {
7091                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
7092                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
7093                 }
7094
7095                 public Type TypeArg { 
7096                         get { return typearg; }
7097                 }
7098         }
7099
7100         /// <summary>
7101         ///   Implements the `typeof (void)' operator
7102         /// </summary>
7103         public class TypeOfVoid : TypeOf {
7104                 public TypeOfVoid (Location l) : base (null, l)
7105                 {
7106                         loc = l;
7107                 }
7108
7109                 public override Expression DoResolve (EmitContext ec)
7110                 {
7111                         type = TypeManager.type_type;
7112                         typearg = TypeManager.void_type;
7113                         // See description in TypeOf.
7114                         eclass = ExprClass.Value;
7115                         return this;
7116                 }
7117         }
7118
7119         /// <summary>
7120         ///   Implements the sizeof expression
7121         /// </summary>
7122         public class SizeOf : Expression {
7123                 public Expression QueriedType;
7124                 Type type_queried;
7125                 
7126                 public SizeOf (Expression queried_type, Location l)
7127                 {
7128                         this.QueriedType = queried_type;
7129                         loc = l;
7130                 }
7131
7132                 public override Expression DoResolve (EmitContext ec)
7133                 {
7134                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7135                         if (texpr == null)
7136                                 return null;
7137
7138                         type_queried = texpr.ResolveType (ec);
7139
7140                         int size_of = GetTypeSize (type_queried);
7141                         if (size_of > 0) {
7142                                 return new IntConstant (size_of);
7143                         }
7144
7145                         if (!ec.InUnsafe) {
7146                                 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)",
7147                                          TypeManager.CSharpName (type_queried));
7148                                 return null;
7149                         }
7150
7151                         CheckObsoleteAttribute (type_queried);
7152
7153                         if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7154                                 return null;
7155                         }
7156                         
7157                         type = TypeManager.int32_type;
7158                         eclass = ExprClass.Value;
7159                         return this;
7160                 }
7161
7162                 public override void Emit (EmitContext ec)
7163                 {
7164                         int size = GetTypeSize (type_queried);
7165
7166                         if (size == 0)
7167                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7168                         else
7169                                 IntConstant.EmitInt (ec.ig, size);
7170                 }
7171         }
7172
7173         /// <summary>
7174         ///   Implements the member access expression
7175         /// </summary>
7176         public class MemberAccess : Expression {
7177                 public readonly string Identifier;
7178                 Expression expr;
7179                 
7180                 public MemberAccess (Expression expr, string id, Location l)
7181                 {
7182                         this.expr = expr;
7183                         Identifier = id;
7184                         loc = l;
7185                 }
7186
7187                 public Expression Expr {
7188                         get { return expr; }
7189                 }
7190
7191                 Expression DoResolve (EmitContext ec, Expression right_side)
7192                 {
7193                         if (type != null)
7194                                 throw new Exception ();
7195
7196                         //
7197                         // Resolve the expression with flow analysis turned off, we'll do the definite
7198                         // assignment checks later.  This is because we don't know yet what the expression
7199                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7200                         // definite assignment check on the actual field and not on the whole struct.
7201                         //
7202
7203                         SimpleName original = expr as SimpleName;
7204                         Expression new_expr = expr.Resolve (ec,
7205                                 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7206                                 ResolveFlags.Intermediate | ResolveFlags.DisableFlowAnalysis);
7207
7208                         if (new_expr == null)
7209                                 return null;
7210
7211                         if (new_expr is Namespace) {
7212                                 Namespace ns = (Namespace) new_expr;
7213                                 FullNamedExpression retval = ns.Lookup (ec.DeclSpace, Identifier, loc);
7214                                 if (retval == null)
7215                                         Report.Error (234, loc, "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing an assembly reference?",
7216                                                 Identifier, ns.FullName);
7217                                 return retval;
7218                         }
7219
7220                         //
7221                         // TODO: I mailed Ravi about this, and apparently we can get rid
7222                         // of this and put it in the right place.
7223                         // 
7224                         // Handle enums here when they are in transit.
7225                         // Note that we cannot afford to hit MemberLookup in this case because
7226                         // it will fail to find any members at all
7227                         //
7228
7229                         Type expr_type = new_expr.Type;
7230                         if (new_expr is TypeExpr){
7231                                 if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
7232                                         ErrorIsInaccesible (loc, TypeManager.CSharpName (expr_type));
7233                                         return null;
7234                                 }
7235
7236                                 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
7237                                         Enum en = TypeManager.LookupEnum (expr_type);
7238
7239                                         if (en != null) {
7240                                                 object value = en.LookupEnumValue (Identifier, loc);
7241                                                 if (value != null){
7242                                                         MemberCore mc = en.GetDefinition (Identifier);
7243                                                         ObsoleteAttribute oa = mc.GetObsoleteAttribute (en);
7244                                                         if (oa != null) {
7245                                                                 AttributeTester.Report_ObsoleteMessage (oa, mc.GetSignatureForError (), Location);
7246                                                         }
7247                                                         oa = en.GetObsoleteAttribute (en);
7248                                                         if (oa != null) {
7249                                                                 AttributeTester.Report_ObsoleteMessage (oa, en.GetSignatureForError (), Location);
7250                                                         }
7251
7252                                                         Constant c = Constantify (value, en.UnderlyingType);
7253                                                         return new EnumConstant (c, expr_type);
7254                                                 }
7255                                         } else {
7256                                                 CheckObsoleteAttribute (expr_type);
7257
7258                                                 FieldInfo fi = expr_type.GetField (Identifier);
7259                                                 if (fi != null) {
7260                                                         ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
7261                                                         if (oa != null)
7262                                                                 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), Location);
7263                                                 }
7264                                         }
7265                                 }
7266                         }
7267
7268                         if (expr_type.IsPointer){
7269                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7270                                        TypeManager.CSharpName (expr_type) + ")");
7271                                 return null;
7272                         }
7273
7274                         Expression member_lookup;
7275                         member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
7276                         if (member_lookup == null)
7277                                 return null;
7278
7279                         if (member_lookup is TypeExpr) {
7280                                 if (!(new_expr is TypeExpr) && 
7281                                     (original == null || !original.IdenticalNameAndTypeName (ec, new_expr, loc))) {
7282                                         Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7283                                                 Identifier, member_lookup.GetSignatureForError ());
7284                                         return null;
7285                                 }
7286
7287                                 return member_lookup;
7288                         }
7289
7290                         MemberExpr me = (MemberExpr) member_lookup;
7291                         member_lookup = me.ResolveMemberAccess (ec, new_expr, loc, original);
7292                         if (member_lookup == null)
7293                                 return null;
7294
7295                         // The following DoResolve/DoResolveLValue will do the definite assignment
7296                         // check.
7297
7298                         if (right_side != null)
7299                                 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
7300                         else
7301                                 member_lookup = member_lookup.DoResolve (ec);
7302
7303                         return member_lookup;
7304                 }
7305
7306                 public override Expression DoResolve (EmitContext ec)
7307                 {
7308                         return DoResolve (ec, null);
7309                 }
7310
7311                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7312                 {
7313                         return DoResolve (ec, right_side);
7314                 }
7315
7316                 public override FullNamedExpression ResolveAsTypeStep (EmitContext ec)
7317                 {
7318                         return ResolveNamespaceOrType (ec, false);
7319                 }
7320
7321                 public FullNamedExpression ResolveNamespaceOrType (EmitContext ec, bool silent)
7322                 {
7323                         FullNamedExpression new_expr = expr.ResolveAsTypeStep (ec);
7324
7325                         if (new_expr == null)
7326                                 return null;
7327
7328                         if (new_expr is Namespace) {
7329                                 Namespace ns = (Namespace) new_expr;
7330                                 FullNamedExpression retval = ns.Lookup (ec.DeclSpace, Identifier, loc);
7331                                 if (!silent && retval == null)
7332                                         Report.Error (234, loc, "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing an assembly reference?",
7333                                                 Identifier, ns.FullName);
7334                                 return retval;
7335                         }
7336
7337                         Type expr_type = new_expr.Type;
7338                       
7339                         if (expr_type.IsPointer){
7340                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7341                                        TypeManager.CSharpName (expr_type) + ")");
7342                                 return null;
7343                         }
7344                         
7345                         Expression member_lookup = MemberLookup (ec, expr_type, expr_type, Identifier, loc);
7346                         if (member_lookup == null) {
7347                                 int errors = Report.Errors;
7348                                 MemberLookupFailed (ec, expr_type, expr_type, Identifier, null, false, loc);
7349
7350                                 if (!silent && errors == Report.Errors)
7351                                         Report.Error (234, loc, "The type or namespace name `{0}' does not exist in the namespace `{1}'. Are you missing an assembly reference?", 
7352                                                       Identifier, new_expr.FullName);
7353                                 return null;
7354                         }
7355
7356                         if (!(member_lookup is TypeExpr)) {
7357                                 Report.Error (118, loc, "`{0}.{1}' denotes a `{2}', where a type was expected",
7358                                               new_expr.FullName, Identifier, member_lookup.ExprClassName ());
7359                                 return null;
7360                         } 
7361
7362                         member_lookup = member_lookup.Resolve (ec, ResolveFlags.Type);
7363                         return (member_lookup as TypeExpr);
7364                 }
7365
7366                 public override void Emit (EmitContext ec)
7367                 {
7368                         throw new Exception ("Should not happen");
7369                 }
7370
7371                 public override string ToString ()
7372                 {
7373                         return expr + "." + Identifier;
7374                 }
7375
7376                 public override string GetSignatureForError ()
7377                 {
7378                         return expr.GetSignatureForError () + "." + Identifier;
7379                 }
7380         }
7381
7382         /// <summary>
7383         ///   Implements checked expressions
7384         /// </summary>
7385         public class CheckedExpr : Expression {
7386
7387                 public Expression Expr;
7388
7389                 public CheckedExpr (Expression e, Location l)
7390                 {
7391                         Expr = e;
7392                         loc = l;
7393                 }
7394
7395                 public override Expression DoResolve (EmitContext ec)
7396                 {
7397                         bool last_check = ec.CheckState;
7398                         bool last_const_check = ec.ConstantCheckState;
7399
7400                         ec.CheckState = true;
7401                         ec.ConstantCheckState = true;
7402                         Expr = Expr.Resolve (ec);
7403                         ec.CheckState = last_check;
7404                         ec.ConstantCheckState = last_const_check;
7405                         
7406                         if (Expr == null)
7407                                 return null;
7408
7409                         if (Expr is Constant)
7410                                 return Expr;
7411                         
7412                         eclass = Expr.eclass;
7413                         type = Expr.Type;
7414                         return this;
7415                 }
7416
7417                 public override void Emit (EmitContext ec)
7418                 {
7419                         bool last_check = ec.CheckState;
7420                         bool last_const_check = ec.ConstantCheckState;
7421                         
7422                         ec.CheckState = true;
7423                         ec.ConstantCheckState = true;
7424                         Expr.Emit (ec);
7425                         ec.CheckState = last_check;
7426                         ec.ConstantCheckState = last_const_check;
7427                 }
7428                 
7429         }
7430
7431         /// <summary>
7432         ///   Implements the unchecked expression
7433         /// </summary>
7434         public class UnCheckedExpr : Expression {
7435
7436                 public Expression Expr;
7437
7438                 public UnCheckedExpr (Expression e, Location l)
7439                 {
7440                         Expr = e;
7441                         loc = l;
7442                 }
7443
7444                 public override Expression DoResolve (EmitContext ec)
7445                 {
7446                         bool last_check = ec.CheckState;
7447                         bool last_const_check = ec.ConstantCheckState;
7448
7449                         ec.CheckState = false;
7450                         ec.ConstantCheckState = false;
7451                         Expr = Expr.Resolve (ec);
7452                         ec.CheckState = last_check;
7453                         ec.ConstantCheckState = last_const_check;
7454
7455                         if (Expr == null)
7456                                 return null;
7457
7458                         if (Expr is Constant)
7459                                 return Expr;
7460                         
7461                         eclass = Expr.eclass;
7462                         type = Expr.Type;
7463                         return this;
7464                 }
7465
7466                 public override void Emit (EmitContext ec)
7467                 {
7468                         bool last_check = ec.CheckState;
7469                         bool last_const_check = ec.ConstantCheckState;
7470                         
7471                         ec.CheckState = false;
7472                         ec.ConstantCheckState = false;
7473                         Expr.Emit (ec);
7474                         ec.CheckState = last_check;
7475                         ec.ConstantCheckState = last_const_check;
7476                 }
7477                 
7478         }
7479
7480         /// <summary>
7481         ///   An Element Access expression.
7482         ///
7483         ///   During semantic analysis these are transformed into 
7484         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7485         /// </summary>
7486         public class ElementAccess : Expression {
7487                 public ArrayList  Arguments;
7488                 public Expression Expr;
7489                 
7490                 public ElementAccess (Expression e, ArrayList e_list, Location l)
7491                 {
7492                         Expr = e;
7493
7494                         loc  = l;
7495                         
7496                         if (e_list == null)
7497                                 return;
7498                         
7499                         Arguments = new ArrayList ();
7500                         foreach (Expression tmp in e_list)
7501                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7502                         
7503                 }
7504
7505                 bool CommonResolve (EmitContext ec)
7506                 {
7507                         Expr = Expr.Resolve (ec);
7508
7509                         if (Expr == null) 
7510                                 return false;
7511
7512                         if (Arguments == null)
7513                                 return false;
7514
7515                         foreach (Argument a in Arguments){
7516                                 if (!a.Resolve (ec, loc))
7517                                         return false;
7518                         }
7519
7520                         return true;
7521                 }
7522
7523                 Expression MakePointerAccess (EmitContext ec, Type t)
7524                 {
7525                         if (t == TypeManager.void_ptr_type){
7526                                 Error (242, "The array index operation is not valid on void pointers");
7527                                 return null;
7528                         }
7529                         if (Arguments.Count != 1){
7530                                 Error (196, "A pointer must be indexed by only one value");
7531                                 return null;
7532                         }
7533                         Expression p;
7534
7535                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7536                         if (p == null)
7537                                 return null;
7538                         return new Indirection (p, loc).Resolve (ec);
7539                 }
7540                 
7541                 public override Expression DoResolve (EmitContext ec)
7542                 {
7543                         if (!CommonResolve (ec))
7544                                 return null;
7545
7546                         //
7547                         // We perform some simple tests, and then to "split" the emit and store
7548                         // code we create an instance of a different class, and return that.
7549                         //
7550                         // I am experimenting with this pattern.
7551                         //
7552                         Type t = Expr.Type;
7553
7554                         if (t == TypeManager.array_type){
7555                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7556                                 return null;
7557                         }
7558                         
7559                         if (t.IsArray)
7560                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7561                         if (t.IsPointer)
7562                                 return MakePointerAccess (ec, Expr.Type);
7563
7564                         FieldExpr fe = Expr as FieldExpr;
7565                         if (fe != null) {
7566                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7567                                 if (ff != null) {
7568                                         return MakePointerAccess (ec, ff.ElementType);
7569                                 }
7570                         }
7571                         return (new IndexerAccess (this, loc)).Resolve (ec);
7572                 }
7573
7574                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7575                 {
7576                         if (!CommonResolve (ec))
7577                                 return null;
7578
7579                         Type t = Expr.Type;
7580                         if (t.IsArray)
7581                                 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7582
7583                         if (t.IsPointer)
7584                                 return MakePointerAccess (ec, Expr.Type);
7585
7586                         FieldExpr fe = Expr as FieldExpr;
7587                         if (fe != null) {
7588                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7589                                 if (ff != null) {
7590                                         if (!(fe.InstanceExpression is LocalVariableReference) && 
7591                                                 !(fe.InstanceExpression is This)) {
7592                                                 Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields");
7593                                                 return null;
7594                                         }
7595 // TODO: not sure whether it is correct
7596 //                                      if (!ec.InFixedInitializer) {
7597 //                                              Error (1666, "You cannot use fixed sized buffers contained in unfixed expressions. Try using the fixed statement");
7598 //                                              return null;
7599 //                                      }
7600                                         return MakePointerAccess (ec, ff.ElementType);
7601                                 }
7602                         }
7603                         return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7604                 }
7605                 
7606                 public override void Emit (EmitContext ec)
7607                 {
7608                         throw new Exception ("Should never be reached");
7609                 }
7610         }
7611
7612         /// <summary>
7613         ///   Implements array access 
7614         /// </summary>
7615         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7616                 //
7617                 // Points to our "data" repository
7618                 //
7619                 ElementAccess ea;
7620
7621                 LocalTemporary temp;
7622                 bool prepared;
7623                 
7624                 public ArrayAccess (ElementAccess ea_data, Location l)
7625                 {
7626                         ea = ea_data;
7627                         eclass = ExprClass.Variable;
7628                         loc = l;
7629                 }
7630
7631                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7632                 {
7633                         return DoResolve (ec);
7634                 }
7635
7636                 public override Expression DoResolve (EmitContext ec)
7637                 {
7638 #if false
7639                         ExprClass eclass = ea.Expr.eclass;
7640
7641                         // As long as the type is valid
7642                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7643                               eclass == ExprClass.Value)) {
7644                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7645                                 return null;
7646                         }
7647 #endif
7648
7649                         Type t = ea.Expr.Type;
7650                         if (t.GetArrayRank () != ea.Arguments.Count){
7651                                 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7652                                           ea.Arguments.Count, t.GetArrayRank ());
7653                                 return null;
7654                         }
7655
7656                         type = TypeManager.GetElementType (t);
7657                         if (type.IsPointer && !ec.InUnsafe){
7658                                 UnsafeError (ea.Location);
7659                                 return null;
7660                         }
7661
7662                         foreach (Argument a in ea.Arguments){
7663                                 Type argtype = a.Type;
7664
7665                                 if (argtype == TypeManager.int32_type ||
7666                                     argtype == TypeManager.uint32_type ||
7667                                     argtype == TypeManager.int64_type ||
7668                                     argtype == TypeManager.uint64_type) {
7669                                         Constant c = a.Expr as Constant;
7670                                         if (c != null && c.IsNegative) {
7671                                                 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7672                                         }
7673                                         continue;
7674                                 }
7675
7676                                 //
7677                                 // Mhm.  This is strage, because the Argument.Type is not the same as
7678                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7679                                 //
7680                                 // Wonder if I will run into trouble for this.
7681                                 //
7682                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7683                                 if (a.Expr == null)
7684                                         return null;
7685                         }
7686                         
7687                         eclass = ExprClass.Variable;
7688
7689                         return this;
7690                 }
7691
7692                 /// <summary>
7693                 ///    Emits the right opcode to load an object of Type `t'
7694                 ///    from an array of T
7695                 /// </summary>
7696                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7697                 {
7698                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7699                                 ig.Emit (OpCodes.Ldelem_U1);
7700                         else if (type == TypeManager.sbyte_type)
7701                                 ig.Emit (OpCodes.Ldelem_I1);
7702                         else if (type == TypeManager.short_type)
7703                                 ig.Emit (OpCodes.Ldelem_I2);
7704                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7705                                 ig.Emit (OpCodes.Ldelem_U2);
7706                         else if (type == TypeManager.int32_type)
7707                                 ig.Emit (OpCodes.Ldelem_I4);
7708                         else if (type == TypeManager.uint32_type)
7709                                 ig.Emit (OpCodes.Ldelem_U4);
7710                         else if (type == TypeManager.uint64_type)
7711                                 ig.Emit (OpCodes.Ldelem_I8);
7712                         else if (type == TypeManager.int64_type)
7713                                 ig.Emit (OpCodes.Ldelem_I8);
7714                         else if (type == TypeManager.float_type)
7715                                 ig.Emit (OpCodes.Ldelem_R4);
7716                         else if (type == TypeManager.double_type)
7717                                 ig.Emit (OpCodes.Ldelem_R8);
7718                         else if (type == TypeManager.intptr_type)
7719                                 ig.Emit (OpCodes.Ldelem_I);
7720                         else if (TypeManager.IsEnumType (type)){
7721                                 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7722                         } else if (type.IsValueType){
7723                                 ig.Emit (OpCodes.Ldelema, type);
7724                                 ig.Emit (OpCodes.Ldobj, type);
7725                         } else 
7726                                 ig.Emit (OpCodes.Ldelem_Ref);
7727                 }
7728
7729                 /// <summary>
7730                 ///    Returns the right opcode to store an object of Type `t'
7731                 ///    from an array of T.  
7732                 /// </summary>
7733                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj)
7734                 {
7735                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
7736                         is_stobj = false;
7737                         t = TypeManager.TypeToCoreType (t);
7738                         if (TypeManager.IsEnumType (t))
7739                                 t = TypeManager.EnumToUnderlying (t);
7740                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7741                             t == TypeManager.bool_type)
7742                                 return OpCodes.Stelem_I1;
7743                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7744                                  t == TypeManager.char_type)
7745                                 return OpCodes.Stelem_I2;
7746                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7747                                 return OpCodes.Stelem_I4;
7748                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7749                                 return OpCodes.Stelem_I8;
7750                         else if (t == TypeManager.float_type)
7751                                 return OpCodes.Stelem_R4;
7752                         else if (t == TypeManager.double_type)
7753                                 return OpCodes.Stelem_R8;
7754                         else if (t == TypeManager.intptr_type) {
7755                                 is_stobj = true;
7756                                 return OpCodes.Stobj;
7757                         } else if (t.IsValueType) {
7758                                 is_stobj = true;
7759                                 return OpCodes.Stobj;
7760                         } else
7761                                 return OpCodes.Stelem_Ref;
7762                 }
7763
7764                 MethodInfo FetchGetMethod ()
7765                 {
7766                         ModuleBuilder mb = CodeGen.Module.Builder;
7767                         int arg_count = ea.Arguments.Count;
7768                         Type [] args = new Type [arg_count];
7769                         MethodInfo get;
7770                         
7771                         for (int i = 0; i < arg_count; i++){
7772                                 //args [i++] = a.Type;
7773                                 args [i] = TypeManager.int32_type;
7774                         }
7775                         
7776                         get = mb.GetArrayMethod (
7777                                 ea.Expr.Type, "Get",
7778                                 CallingConventions.HasThis |
7779                                 CallingConventions.Standard,
7780                                 type, args);
7781                         return get;
7782                 }
7783                                 
7784
7785                 MethodInfo FetchAddressMethod ()
7786                 {
7787                         ModuleBuilder mb = CodeGen.Module.Builder;
7788                         int arg_count = ea.Arguments.Count;
7789                         Type [] args = new Type [arg_count];
7790                         MethodInfo address;
7791                         Type ret_type;
7792                         
7793                         ret_type = TypeManager.GetReferenceType (type);
7794                         
7795                         for (int i = 0; i < arg_count; i++){
7796                                 //args [i++] = a.Type;
7797                                 args [i] = TypeManager.int32_type;
7798                         }
7799                         
7800                         address = mb.GetArrayMethod (
7801                                 ea.Expr.Type, "Address",
7802                                 CallingConventions.HasThis |
7803                                 CallingConventions.Standard,
7804                                 ret_type, args);
7805
7806                         return address;
7807                 }
7808
7809                 //
7810                 // Load the array arguments into the stack.
7811                 //
7812                 // If we have been requested to cache the values (cached_locations array
7813                 // initialized), then load the arguments the first time and store them
7814                 // in locals.  otherwise load from local variables.
7815                 //
7816                 void LoadArrayAndArguments (EmitContext ec)
7817                 {
7818                         ILGenerator ig = ec.ig;
7819                         
7820                         ea.Expr.Emit (ec);
7821                         foreach (Argument a in ea.Arguments){
7822                                 Type argtype = a.Expr.Type;
7823                                 
7824                                 a.Expr.Emit (ec);
7825                                 
7826                                 if (argtype == TypeManager.int64_type)
7827                                         ig.Emit (OpCodes.Conv_Ovf_I);
7828                                 else if (argtype == TypeManager.uint64_type)
7829                                         ig.Emit (OpCodes.Conv_Ovf_I_Un);
7830                         }
7831                 }
7832
7833                 public void Emit (EmitContext ec, bool leave_copy)
7834                 {
7835                         int rank = ea.Expr.Type.GetArrayRank ();
7836                         ILGenerator ig = ec.ig;
7837
7838                         if (!prepared) {
7839                                 LoadArrayAndArguments (ec);
7840                                 
7841                                 if (rank == 1)
7842                                         EmitLoadOpcode (ig, type);
7843                                 else {
7844                                         MethodInfo method;
7845                                         
7846                                         method = FetchGetMethod ();
7847                                         ig.Emit (OpCodes.Call, method);
7848                                 }
7849                         } else
7850                                 LoadFromPtr (ec.ig, this.type);
7851                         
7852                         if (leave_copy) {
7853                                 ec.ig.Emit (OpCodes.Dup);
7854                                 temp = new LocalTemporary (ec, this.type);
7855                                 temp.Store (ec);
7856                         }
7857                 }
7858                 
7859                 public override void Emit (EmitContext ec)
7860                 {
7861                         Emit (ec, false);
7862                 }
7863
7864                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7865                 {
7866                         int rank = ea.Expr.Type.GetArrayRank ();
7867                         ILGenerator ig = ec.ig;
7868                         Type t = source.Type;
7869                         prepared = prepare_for_load;
7870
7871                         if (prepare_for_load) {
7872                                 AddressOf (ec, AddressOp.LoadStore);
7873                                 ec.ig.Emit (OpCodes.Dup);
7874                                 source.Emit (ec);
7875                                 if (leave_copy) {
7876                                         ec.ig.Emit (OpCodes.Dup);
7877                                         temp = new LocalTemporary (ec, this.type);
7878                                         temp.Store (ec);
7879                                 }
7880                                 StoreFromPtr (ec.ig, t);
7881                                 
7882                                 if (temp != null)
7883                                         temp.Emit (ec);
7884                                 
7885                                 return;
7886                         }
7887                         
7888                         LoadArrayAndArguments (ec);
7889
7890                         if (rank == 1) {
7891                                 bool is_stobj;
7892                                 OpCode op = GetStoreOpcode (t, out is_stobj);
7893                                 //
7894                                 // The stobj opcode used by value types will need
7895                                 // an address on the stack, not really an array/array
7896                                 // pair
7897                                 //
7898                                 if (is_stobj)
7899                                         ig.Emit (OpCodes.Ldelema, t);
7900                                 
7901                                 source.Emit (ec);
7902                                 if (leave_copy) {
7903                                         ec.ig.Emit (OpCodes.Dup);
7904                                         temp = new LocalTemporary (ec, this.type);
7905                                         temp.Store (ec);
7906                                 }
7907                                 
7908                                 if (is_stobj)
7909                                         ig.Emit (OpCodes.Stobj, t);
7910                                 else
7911                                         ig.Emit (op);
7912                         } else {
7913                                 ModuleBuilder mb = CodeGen.Module.Builder;
7914                                 int arg_count = ea.Arguments.Count;
7915                                 Type [] args = new Type [arg_count + 1];
7916                                 MethodInfo set;
7917                                 
7918                                 source.Emit (ec);
7919                                 if (leave_copy) {
7920                                         ec.ig.Emit (OpCodes.Dup);
7921                                         temp = new LocalTemporary (ec, this.type);
7922                                         temp.Store (ec);
7923                                 }
7924                                 
7925                                 for (int i = 0; i < arg_count; i++){
7926                                         //args [i++] = a.Type;
7927                                         args [i] = TypeManager.int32_type;
7928                                 }
7929
7930                                 args [arg_count] = type;
7931                                 
7932                                 set = mb.GetArrayMethod (
7933                                         ea.Expr.Type, "Set",
7934                                         CallingConventions.HasThis |
7935                                         CallingConventions.Standard,
7936                                         TypeManager.void_type, args);
7937                                 
7938                                 ig.Emit (OpCodes.Call, set);
7939                         }
7940                         
7941                         if (temp != null)
7942                                 temp.Emit (ec);
7943                 }
7944
7945                 public void AddressOf (EmitContext ec, AddressOp mode)
7946                 {
7947                         int rank = ea.Expr.Type.GetArrayRank ();
7948                         ILGenerator ig = ec.ig;
7949
7950                         LoadArrayAndArguments (ec);
7951
7952                         if (rank == 1){
7953                                 ig.Emit (OpCodes.Ldelema, type);
7954                         } else {
7955                                 MethodInfo address = FetchAddressMethod ();
7956                                 ig.Emit (OpCodes.Call, address);
7957                         }
7958                 }
7959
7960                 public void EmitGetLength (EmitContext ec, int dim)
7961                 {
7962                         int rank = ea.Expr.Type.GetArrayRank ();
7963                         ILGenerator ig = ec.ig;
7964
7965                         ea.Expr.Emit (ec);
7966                         if (rank == 1) {
7967                                 ig.Emit (OpCodes.Ldlen);
7968                                 ig.Emit (OpCodes.Conv_I4);
7969                         } else {
7970                                 IntLiteral.EmitInt (ig, dim);
7971                                 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7972                         }
7973                 }
7974         }
7975         
7976         class Indexers {
7977                 // note that the ArrayList itself in mutable.  We just can't assign to 'Properties' again.
7978                 public readonly ArrayList Properties;
7979                 static Indexers empty;
7980
7981                 public struct Indexer {
7982                         public readonly PropertyInfo PropertyInfo;
7983                         public readonly MethodInfo Getter, Setter;
7984
7985                         public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7986                         {
7987                                 this.PropertyInfo = property_info;
7988                                 this.Getter = get;
7989                                 this.Setter = set;
7990                         }
7991                 }
7992
7993                 static Indexers ()
7994                 {
7995                         empty = new Indexers (null);
7996                 }
7997
7998                 Indexers (ArrayList array)
7999                 {
8000                         Properties = array;
8001                 }
8002
8003                 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
8004                 {
8005                         bool dummy;
8006                         if (mi == null)
8007                                 return;
8008                         foreach (PropertyInfo property in mi){
8009                                 MethodInfo get, set;
8010                                 
8011                                 get = property.GetGetMethod (true);
8012                                 set = property.GetSetMethod (true);
8013                                 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
8014                                         get = null;
8015                                 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
8016                                         set = null;
8017                                 if (get != null || set != null) {
8018                                         if (ix == empty)
8019                                                 ix = new Indexers (new ArrayList ());
8020                                         ix.Properties.Add (new Indexer (property, get, set));
8021                                 }
8022                         }
8023                 }
8024
8025                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8026                 {
8027                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
8028
8029                         return TypeManager.MemberLookup (
8030                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
8031                                 BindingFlags.Public | BindingFlags.Instance |
8032                                 BindingFlags.DeclaredOnly, p_name, null);
8033                 }
8034                 
8035                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) 
8036                 {
8037                         Indexers ix = empty;
8038
8039                         Type copy = lookup_type;
8040                         while (copy != TypeManager.object_type && copy != null){
8041                                 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8042                                 copy = copy.BaseType;
8043                         }
8044
8045                         if (lookup_type.IsInterface) {
8046                                 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8047                                 if (ifaces != null) {
8048                                         foreach (Type itype in ifaces)
8049                                                 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8050                                 }
8051                         }
8052
8053                         return ix;
8054                 }
8055         }
8056
8057         /// <summary>
8058         ///   Expressions that represent an indexer call.
8059         /// </summary>
8060         public class IndexerAccess : Expression, IAssignMethod {
8061                 //
8062                 // Points to our "data" repository
8063                 //
8064                 MethodInfo get, set;
8065                 ArrayList set_arguments;
8066                 bool is_base_indexer;
8067
8068                 protected Type indexer_type;
8069                 protected Type current_type;
8070                 protected Expression instance_expr;
8071                 protected ArrayList arguments;
8072                 
8073                 public IndexerAccess (ElementAccess ea, Location loc)
8074                         : this (ea.Expr, false, loc)
8075                 {
8076                         this.arguments = ea.Arguments;
8077                 }
8078
8079                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8080                                          Location loc)
8081                 {
8082                         this.instance_expr = instance_expr;
8083                         this.is_base_indexer = is_base_indexer;
8084                         this.eclass = ExprClass.Value;
8085                         this.loc = loc;
8086                 }
8087
8088                 protected virtual bool CommonResolve (EmitContext ec)
8089                 {
8090                         indexer_type = instance_expr.Type;
8091                         current_type = ec.ContainerType;
8092
8093                         return true;
8094                 }
8095
8096                 public override Expression DoResolve (EmitContext ec)
8097                 {
8098                         ArrayList AllGetters = new ArrayList();
8099                         if (!CommonResolve (ec))
8100                                 return null;
8101
8102                         //
8103                         // Step 1: Query for all `Item' *properties*.  Notice
8104                         // that the actual methods are pointed from here.
8105                         //
8106                         // This is a group of properties, piles of them.  
8107
8108                         bool found_any = false, found_any_getters = false;
8109                         Type lookup_type = indexer_type;
8110
8111                         Indexers ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
8112                         if (ilist.Properties != null) {
8113                                 found_any = true;
8114                                 foreach (Indexers.Indexer ix in ilist.Properties) {
8115                                         if (ix.Getter != null)
8116                                                 AllGetters.Add (ix.Getter);
8117                                 }
8118                         }
8119
8120                         if (AllGetters.Count > 0) {
8121                                 found_any_getters = true;
8122                                 get = (MethodInfo) Invocation.OverloadResolve (
8123                                         ec, new MethodGroupExpr (AllGetters, loc),
8124                                         arguments, false, loc);
8125                         }
8126
8127                         if (!found_any) {
8128                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8129                                               TypeManager.CSharpName (indexer_type));
8130                                 return null;
8131                         }
8132
8133                         if (!found_any_getters) {
8134                                 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
8135                                        "XXXXXXXX");
8136                                 return null;
8137                         }
8138
8139                         if (get == null) {
8140                                 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
8141                                 return null;
8142                         }
8143
8144                         //
8145                         // Only base will allow this invocation to happen.
8146                         //
8147                         if (get.IsAbstract && this is BaseIndexerAccess){
8148                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
8149                                 return null;
8150                         }
8151
8152                         type = get.ReturnType;
8153                         if (type.IsPointer && !ec.InUnsafe){
8154                                 UnsafeError (loc);
8155                                 return null;
8156                         }
8157
8158                         instance_expr.CheckMarshallByRefAccess (ec.ContainerType);
8159                         
8160                         eclass = ExprClass.IndexerAccess;
8161                         return this;
8162                 }
8163
8164                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8165                 {
8166                         ArrayList AllSetters = new ArrayList();
8167                         if (!CommonResolve (ec))
8168                                 return null;
8169
8170                         bool found_any = false, found_any_setters = false;
8171
8172                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
8173                         if (ilist.Properties != null) {
8174                                 found_any = true;
8175                                 foreach (Indexers.Indexer ix in ilist.Properties) {
8176                                         if (ix.Setter != null)
8177                                                 AllSetters.Add (ix.Setter);
8178                                 }
8179                         }
8180                         if (AllSetters.Count > 0) {
8181                                 found_any_setters = true;
8182                                 set_arguments = (ArrayList) arguments.Clone ();
8183                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8184                                 set = (MethodInfo) Invocation.OverloadResolve (
8185                                         ec, new MethodGroupExpr (AllSetters, loc),
8186                                         set_arguments, false, loc);
8187                         }
8188
8189                         if (!found_any) {
8190                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8191                                               TypeManager.CSharpName (indexer_type));
8192                                 return null;
8193                         }
8194
8195                         if (!found_any_setters) {
8196                                 Error (154, "indexer can not be used in this context, because " +
8197                                        "it lacks a `set' accessor");
8198                                 return null;
8199                         }
8200
8201                         if (set == null) {
8202                                 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
8203                                 return null;
8204                         }
8205
8206                         //
8207                         // Only base will allow this invocation to happen.
8208                         //
8209                         if (set.IsAbstract && this is BaseIndexerAccess){
8210                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
8211                                 return null;
8212                         }
8213
8214                         //
8215                         // Now look for the actual match in the list of indexers to set our "return" type
8216                         //
8217                         type = TypeManager.void_type;   // default value
8218                         foreach (Indexers.Indexer ix in ilist.Properties){
8219                                 if (ix.Setter == set){
8220                                         type = ix.PropertyInfo.PropertyType;
8221                                         break;
8222                                 }
8223                         }
8224
8225                         instance_expr.CheckMarshallByRefAccess (ec.ContainerType);
8226
8227                         eclass = ExprClass.IndexerAccess;
8228                         return this;
8229                 }
8230                 
8231                 bool prepared = false;
8232                 LocalTemporary temp;
8233                 
8234                 public void Emit (EmitContext ec, bool leave_copy)
8235                 {
8236                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
8237                         if (leave_copy) {
8238                                 ec.ig.Emit (OpCodes.Dup);
8239                                 temp = new LocalTemporary (ec, Type);
8240                                 temp.Store (ec);
8241                         }
8242                 }
8243                 
8244                 //
8245                 // source is ignored, because we already have a copy of it from the
8246                 // LValue resolution and we have already constructed a pre-cached
8247                 // version of the arguments (ea.set_arguments);
8248                 //
8249                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8250                 {
8251                         prepared = prepare_for_load;
8252                         Argument a = (Argument) set_arguments [set_arguments.Count - 1];
8253                         
8254                         if (prepared) {
8255                                 source.Emit (ec);
8256                                 if (leave_copy) {
8257                                         ec.ig.Emit (OpCodes.Dup);
8258                                         temp = new LocalTemporary (ec, Type);
8259                                         temp.Store (ec);
8260                                 }
8261                         } else if (leave_copy) {
8262                                 temp = new LocalTemporary (ec, Type);
8263                                 source.Emit (ec);
8264                                 temp.Store (ec);
8265                                 a.Expr = temp;
8266                         }
8267                         
8268                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
8269                         
8270                         if (temp != null)
8271                                 temp.Emit (ec);
8272                 }
8273                 
8274                 
8275                 public override void Emit (EmitContext ec)
8276                 {
8277                         Emit (ec, false);
8278                 }
8279         }
8280
8281         /// <summary>
8282         ///   The base operator for method names
8283         /// </summary>
8284         public class BaseAccess : Expression {
8285                 string member;
8286                 
8287                 public BaseAccess (string member, Location l)
8288                 {
8289                         this.member = member;
8290                         loc = l;
8291                 }
8292
8293                 public override Expression DoResolve (EmitContext ec)
8294                 {
8295                         Expression c = CommonResolve (ec);
8296
8297                         if (c == null)
8298                                 return null;
8299
8300                         //
8301                         // MethodGroups use this opportunity to flag an error on lacking ()
8302                         //
8303                         if (!(c is MethodGroupExpr))
8304                                 return c.Resolve (ec);
8305                         return c;
8306                 }
8307
8308                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8309                 {
8310                         Expression c = CommonResolve (ec);
8311
8312                         if (c == null)
8313                                 return null;
8314
8315                         //
8316                         // MethodGroups use this opportunity to flag an error on lacking ()
8317                         //
8318                         if (! (c is MethodGroupExpr))
8319                                 return c.DoResolveLValue (ec, right_side);
8320
8321                         return c;
8322                 }
8323
8324                 Expression CommonResolve (EmitContext ec)
8325                 {
8326                         Expression member_lookup;
8327                         Type current_type = ec.ContainerType;
8328                         Type base_type = current_type.BaseType;
8329
8330                         if (ec.IsStatic){
8331                                 Error (1511, "Keyword `base' is not available in a static method");
8332                                 return null;
8333                         }
8334
8335                         if (ec.IsFieldInitializer){
8336                                 Error (1512, "Keyword `base' is not available in the current context");
8337                                 return null;
8338                         }
8339                         
8340                         member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type, member,
8341                                                       AllMemberTypes, AllBindingFlags, loc);
8342                         if (member_lookup == null) {
8343                                 MemberLookupFailed (ec, base_type, base_type, member, null, true, loc);
8344                                 return null;
8345                         }
8346
8347                         Expression left;
8348                         
8349                         if (ec.IsStatic)
8350                                 left = new TypeExpression (base_type, loc);
8351                         else
8352                                 left = ec.GetThis (loc);
8353
8354                         MemberExpr me = (MemberExpr) member_lookup;
8355                         
8356                         Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8357
8358                         if (e is PropertyExpr) {
8359                                 PropertyExpr pe = (PropertyExpr) e;
8360
8361                                 pe.IsBase = true;
8362                         }
8363                         
8364                         if (e is MethodGroupExpr)
8365                                 ((MethodGroupExpr) e).IsBase = true;
8366
8367                         return e;
8368                 }
8369
8370                 public override void Emit (EmitContext ec)
8371                 {
8372                         throw new Exception ("Should never be called"); 
8373                 }
8374         }
8375
8376         /// <summary>
8377         ///   The base indexer operator
8378         /// </summary>
8379         public class BaseIndexerAccess : IndexerAccess {
8380                 public BaseIndexerAccess (ArrayList args, Location loc)
8381                         : base (null, true, loc)
8382                 {
8383                         arguments = new ArrayList ();
8384                         foreach (Expression tmp in args)
8385                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8386                 }
8387
8388                 protected override bool CommonResolve (EmitContext ec)
8389                 {
8390                         instance_expr = ec.GetThis (loc);
8391
8392                         current_type = ec.ContainerType.BaseType;
8393                         indexer_type = current_type;
8394
8395                         foreach (Argument a in arguments){
8396                                 if (!a.Resolve (ec, loc))
8397                                         return false;
8398                         }
8399
8400                         return true;
8401                 }
8402         }
8403         
8404         /// <summary>
8405         ///   This class exists solely to pass the Type around and to be a dummy
8406         ///   that can be passed to the conversion functions (this is used by
8407         ///   foreach implementation to typecast the object return value from
8408         ///   get_Current into the proper type.  All code has been generated and
8409         ///   we only care about the side effect conversions to be performed
8410         ///
8411         ///   This is also now used as a placeholder where a no-action expression
8412         ///   is needed (the `New' class).
8413         /// </summary>
8414         public class EmptyExpression : Expression {
8415                 public static readonly EmptyExpression Null = new EmptyExpression ();
8416
8417                 static EmptyExpression temp = new EmptyExpression ();
8418                 public static EmptyExpression Grab ()
8419                 {
8420                         if (temp == null)
8421                                 throw new InternalErrorException ("Nested Grab");
8422                         EmptyExpression retval = temp;
8423                         temp = null;
8424                         return retval;
8425                 }
8426
8427                 public static void Release (EmptyExpression e)
8428                 {
8429                         if (temp != null)
8430                                 throw new InternalErrorException ("Already released");
8431                         temp = e;
8432                 }
8433
8434                 // TODO: should be protected
8435                 public EmptyExpression ()
8436                 {
8437                         type = TypeManager.object_type;
8438                         eclass = ExprClass.Value;
8439                         loc = Location.Null;
8440                 }
8441
8442                 public EmptyExpression (Type t)
8443                 {
8444                         type = t;
8445                         eclass = ExprClass.Value;
8446                         loc = Location.Null;
8447                 }
8448                 
8449                 public override Expression DoResolve (EmitContext ec)
8450                 {
8451                         return this;
8452                 }
8453
8454                 public override void Emit (EmitContext ec)
8455                 {
8456                         // nothing, as we only exist to not do anything.
8457                 }
8458
8459                 //
8460                 // This is just because we might want to reuse this bad boy
8461                 // instead of creating gazillions of EmptyExpressions.
8462                 // (CanImplicitConversion uses it)
8463                 //
8464                 public void SetType (Type t)
8465                 {
8466                         type = t;
8467                 }
8468         }
8469
8470         public class UserCast : Expression {
8471                 MethodBase method;
8472                 Expression source;
8473                 
8474                 public UserCast (MethodInfo method, Expression source, Location l)
8475                 {
8476                         this.method = method;
8477                         this.source = source;
8478                         type = method.ReturnType;
8479                         eclass = ExprClass.Value;
8480                         loc = l;
8481                 }
8482
8483                 public Expression Source {
8484                         get {
8485                                 return source;
8486                         }
8487                 }
8488                         
8489                 public override Expression DoResolve (EmitContext ec)
8490                 {
8491                         //
8492                         // We are born fully resolved
8493                         //
8494                         return this;
8495                 }
8496
8497                 public override void Emit (EmitContext ec)
8498                 {
8499                         ILGenerator ig = ec.ig;
8500
8501                         source.Emit (ec);
8502                         
8503                         if (method is MethodInfo)
8504                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8505                         else
8506                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8507
8508                 }
8509         }
8510
8511         // <summary>
8512         //   This class is used to "construct" the type during a typecast
8513         //   operation.  Since the Type.GetType class in .NET can parse
8514         //   the type specification, we just use this to construct the type
8515         //   one bit at a time.
8516         // </summary>
8517         public class ComposedCast : TypeExpr {
8518                 Expression left;
8519                 string dim;
8520                 
8521                 public ComposedCast (Expression left, string dim, Location l)
8522                 {
8523                         this.left = left;
8524                         this.dim = dim;
8525                         loc = l;
8526                 }
8527
8528                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
8529                 {
8530                         TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8531                         if (lexpr == null)
8532                                 return null;
8533
8534                         Type ltype = lexpr.ResolveType (ec);
8535
8536                         if ((ltype == TypeManager.void_type) && (dim != "*")) {
8537                                 Report.Error (1547, Location,
8538                                               "Keyword 'void' cannot be used in this context");
8539                                 return null;
8540                         }
8541
8542                         if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc)) {
8543                                 return null;
8544                         }
8545
8546                         type = TypeManager.GetConstructedType (ltype, dim);
8547                         if (type == null) {
8548                                 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8549                         }
8550
8551                         if (!ec.InUnsafe && type.IsPointer){
8552                                 UnsafeError (loc);
8553                                 return null;
8554                         }
8555
8556                         if (type.IsArray && (type.GetElementType () == TypeManager.arg_iterator_type ||
8557                                 type.GetElementType () == TypeManager.typed_reference_type)) {
8558                                 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (type.GetElementType ()));
8559                                 return null;
8560                         }
8561                         
8562                         eclass = ExprClass.Type;
8563                         return this;
8564                 }
8565
8566                 public override string Name {
8567                         get {
8568                                 return left + dim;
8569                         }
8570                 }
8571
8572                 public override string FullName {
8573                         get {
8574                                 return type.FullName;
8575                         }
8576                 }
8577         }
8578
8579         public class FixedBufferPtr: Expression {
8580                 Expression array;
8581
8582                 public FixedBufferPtr (Expression array, Type array_type, Location l)
8583                 {
8584                         this.array = array;
8585                         this.loc = l;
8586
8587                         type = TypeManager.GetPointerType (array_type);
8588                         eclass = ExprClass.Value;
8589                 }
8590
8591                 public override void Emit(EmitContext ec)
8592                 {
8593                         array.Emit (ec);
8594                 }
8595
8596                 public override Expression DoResolve (EmitContext ec)
8597                 {
8598                         //
8599                         // We are born fully resolved
8600                         //
8601                         return this;
8602                 }
8603         }
8604
8605
8606         //
8607         // This class is used to represent the address of an array, used
8608         // only by the Fixed statement, this generates "&a [0]" construct
8609         // for fixed (char *pa = a)
8610         //
8611         public class ArrayPtr : FixedBufferPtr {
8612                 Type array_type;
8613                 
8614                 public ArrayPtr (Expression array, Type array_type, Location l):
8615                         base (array, array_type, l)
8616                 {
8617                         this.array_type = array_type;
8618                 }
8619
8620                 public override void Emit (EmitContext ec)
8621                 {
8622                         base.Emit (ec);
8623                         
8624                         ILGenerator ig = ec.ig;
8625                         IntLiteral.EmitInt (ig, 0);
8626                         ig.Emit (OpCodes.Ldelema, array_type);
8627                 }
8628         }
8629
8630         //
8631         // Used by the fixed statement
8632         //
8633         public class StringPtr : Expression {
8634                 LocalBuilder b;
8635                 
8636                 public StringPtr (LocalBuilder b, Location l)
8637                 {
8638                         this.b = b;
8639                         eclass = ExprClass.Value;
8640                         type = TypeManager.char_ptr_type;
8641                         loc = l;
8642                 }
8643
8644                 public override Expression DoResolve (EmitContext ec)
8645                 {
8646                         // This should never be invoked, we are born in fully
8647                         // initialized state.
8648
8649                         return this;
8650                 }
8651
8652                 public override void Emit (EmitContext ec)
8653                 {
8654                         ILGenerator ig = ec.ig;
8655
8656                         ig.Emit (OpCodes.Ldloc, b);
8657                         ig.Emit (OpCodes.Conv_I);
8658                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8659                         ig.Emit (OpCodes.Add);
8660                 }
8661         }
8662         
8663         //
8664         // Implements the `stackalloc' keyword
8665         //
8666         public class StackAlloc : Expression {
8667                 Type otype;
8668                 Expression t;
8669                 Expression count;
8670                 
8671                 public StackAlloc (Expression type, Expression count, Location l)
8672                 {
8673                         t = type;
8674                         this.count = count;
8675                         loc = l;
8676                 }
8677
8678                 public override Expression DoResolve (EmitContext ec)
8679                 {
8680                         count = count.Resolve (ec);
8681                         if (count == null)
8682                                 return null;
8683                         
8684                         if (count.Type != TypeManager.int32_type){
8685                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8686                                 if (count == null)
8687                                         return null;
8688                         }
8689
8690                         Constant c = count as Constant;
8691                         if (c != null && c.IsNegative) {
8692                                 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8693                                 return null;
8694                         }
8695
8696                         if (ec.InCatch || ec.InFinally) {
8697                                 Error (255, "Cannot use stackalloc in finally or catch");
8698                                 return null;
8699                         }
8700
8701                         TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8702                         if (texpr == null)
8703                                 return null;
8704
8705                         otype = texpr.ResolveType (ec);
8706
8707                         if (!TypeManager.VerifyUnManaged (otype, loc))
8708                                 return null;
8709
8710                         type = TypeManager.GetPointerType (otype);
8711                         eclass = ExprClass.Value;
8712
8713                         return this;
8714                 }
8715
8716                 public override void Emit (EmitContext ec)
8717                 {
8718                         int size = GetTypeSize (otype);
8719                         ILGenerator ig = ec.ig;
8720                                 
8721                         if (size == 0)
8722                                 ig.Emit (OpCodes.Sizeof, otype);
8723                         else
8724                                 IntConstant.EmitInt (ig, size);
8725                         count.Emit (ec);
8726                         ig.Emit (OpCodes.Mul);
8727                         ig.Emit (OpCodes.Localloc);
8728                 }
8729         }
8730 }