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