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