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