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