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