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