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