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