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