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