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