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