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