Ooops.
[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                         //
327                         // Step 1: Default operations on CLI native types.
328                         //
329
330                         // Attempt to use a constant folding operation.
331                         if (Expr is Constant){
332                                 Expression result;
333                                 
334                                 if (Reduce (ec, (Constant) Expr, out result))
335                                         return result;
336                         }
337
338                         //
339                         // Step 2: Perform Operator Overload location
340                         //
341                         Type expr_type = Expr.Type;
342                         Expression mg;
343                         string op_name;
344                         
345                         op_name = oper_names [(int) Oper];
346
347                         mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
348                         
349                         if (mg != null) {
350                                 Expression e = StaticCallExpr.MakeSimpleCall (
351                                         ec, (MethodGroupExpr) mg, Expr, loc);
352
353                                 if (e == null){
354                                         Error23 (expr_type);
355                                         return null;
356                                 }
357                                 
358                                 return e;
359                         }
360
361                         // Only perform numeric promotions on:
362                         // +, - 
363
364                         if (expr_type == null)
365                                 return null;
366                         
367                         switch (Oper){
368                         case Operator.LogicalNot:
369                                 if (expr_type != TypeManager.bool_type) {
370                                         Expr = ResolveBoolean (ec, Expr, loc);
371                                         if (Expr == null){
372                                                 Error23 (expr_type);
373                                                 return null;
374                                         }
375                                 }
376                                 
377                                 type = TypeManager.bool_type;
378                                 return this;
379
380                         case Operator.OnesComplement:
381                                 if (!((expr_type == TypeManager.int32_type) ||
382                                       (expr_type == TypeManager.uint32_type) ||
383                                       (expr_type == TypeManager.int64_type) ||
384                                       (expr_type == TypeManager.uint64_type) ||
385                                       (expr_type.IsSubclassOf (TypeManager.enum_type)))){
386                                         Expression e;
387
388                                         e = Convert.ImplicitConversion (ec, Expr, TypeManager.int32_type, loc);
389                                         if (e != null){
390                                                 type = TypeManager.int32_type;
391                                                 return this;
392                                         }
393                                         e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint32_type, loc);
394                                         if (e != null){
395                                                 type = TypeManager.uint32_type;
396                                                 return this;
397                                         }
398                                         e = Convert.ImplicitConversion (ec, Expr, TypeManager.int64_type, loc);
399                                         if (e != null){
400                                                 type = TypeManager.int64_type;
401                                                 return this;
402                                         }
403                                         e = Convert.ImplicitConversion (ec, Expr, TypeManager.uint64_type, loc);
404                                         if (e != null){
405                                                 type = TypeManager.uint64_type;
406                                                 return this;
407                                         }
408                                         Error23 (expr_type);
409                                         return null;
410                                 }
411                                 type = expr_type;
412                                 return this;
413
414                         case Operator.AddressOf:
415                                 if (Expr.eclass != ExprClass.Variable){
416                                         Error (211, "Cannot take the address of non-variables");
417                                         return null;
418                                 }
419                                 
420                                 if (!ec.InUnsafe) {
421                                         UnsafeError (loc); 
422                                         return null;
423                                 }
424                                 
425                                 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
426                                         return null;
427                                 }
428
429                                 IVariable variable = Expr as IVariable;
430                                 if (!ec.InFixedInitializer && ((variable == null) || !variable.VerifyFixed (false))) {
431                                         Error (212, "You can only take the address of an unfixed expression inside " +
432                                                "of a fixed statement initializer");
433                                         return null;
434                                 }
435
436                                 if (ec.InFixedInitializer && ((variable != null) && variable.VerifyFixed (false))) {
437                                         Error (213, "You can not fix an already fixed expression");
438                                         return null;
439                                 }
440
441                                 LocalVariableReference lr = Expr as LocalVariableReference;
442                                 if (lr != null){
443                                         if (lr.local_info.IsCaptured){
444                                                 AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
445                                                 return null;
446                                         }
447                                         lr.local_info.AddressTaken = true;
448                                         lr.local_info.Used = 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);
3592
3593                                 // is out param
3594                                 if (lvalue_right_side == EmptyExpression.Null)
3595                                         local_info.Used = true;
3596
3597                                 is_readonly = local_info.ReadOnly;
3598                         }
3599
3600                         type = local_info.VariableType;
3601
3602                         VariableInfo variable_info = local_info.VariableInfo;
3603                         if (lvalue_right_side != null){
3604                                 if (is_readonly){
3605                                         Error (1604, "cannot assign to `" + Name + "' because it is readonly");
3606                                         return null;
3607                                 }
3608                                 
3609                                 if (variable_info != null)
3610                                         variable_info.SetAssigned (ec);
3611                         }
3612                         
3613                         Expression e = Block.GetConstantExpression (Name);
3614                         if (e != null) {
3615                                 local_info.Used = true;
3616                                 eclass = ExprClass.Value;
3617                                 return e.Resolve (ec);
3618                         }
3619
3620                         if ((variable_info != null) && !variable_info.IsAssigned (ec, loc))
3621                                 return null;
3622
3623                         if (lvalue_right_side == null)
3624                                 local_info.Used = true;
3625
3626                         if (ec.CurrentAnonymousMethod != null){
3627                                 //
3628                                 // If we are referencing a variable from the external block
3629                                 // flag it for capturing
3630                                 //
3631                                 if (local_info.Block.Toplevel != ec.CurrentBlock.Toplevel){
3632                                         if (local_info.AddressTaken){
3633                                                 AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3634                                                 return null;
3635                                         }
3636                                         ec.CaptureVariable (local_info);
3637                                 }
3638                         }
3639
3640                         return this;
3641                 }
3642                 
3643                 public override Expression DoResolve (EmitContext ec)
3644                 {
3645                         return DoResolveBase (ec, null);
3646                 }
3647
3648                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3649                 {
3650                         Expression ret = DoResolveBase (ec, right_side);
3651                         if (ret != null)
3652                                 CheckObsoleteAttribute (ret.Type);
3653                         
3654                         return ret;
3655                 }
3656
3657                 public bool VerifyFixed (bool is_expression)
3658                 {
3659                         return !is_expression || local_info.IsFixed;
3660                 }
3661
3662                 public override void Emit (EmitContext ec)
3663                 {
3664                         ILGenerator ig = ec.ig;
3665
3666                         if (local_info.FieldBuilder == null){
3667                                 //
3668                                 // A local variable on the local CLR stack
3669                                 //
3670                                 ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
3671                         } else {
3672                                 //
3673                                 // A local variable captured by anonymous methods.
3674                                 //
3675                                 if (!prepared)
3676                                         ec.EmitCapturedVariableInstance (local_info);
3677                                 
3678                                 ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder);
3679                         }
3680                 }
3681                 
3682                 public void Emit (EmitContext ec, bool leave_copy)
3683                 {
3684                         Emit (ec);
3685                         if (leave_copy){
3686                                 ec.ig.Emit (OpCodes.Dup);
3687                                 if (local_info.FieldBuilder != null){
3688                                         temp = new LocalTemporary (ec, Type);
3689                                         temp.Store (ec);
3690                                 }
3691                         }
3692                 }
3693                 
3694                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3695                 {
3696                         ILGenerator ig = ec.ig;
3697                         prepared = prepare_for_load;
3698
3699                         if (local_info.FieldBuilder == null){
3700                                 //
3701                                 // A local variable on the local CLR stack
3702                                 //
3703                                 if (local_info.LocalBuilder == null)
3704                                         throw new Exception ("This should not happen: both Field and Local are null");
3705                                 
3706                                 source.Emit (ec);
3707                                 if (leave_copy)
3708                                         ec.ig.Emit (OpCodes.Dup);
3709                                 ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
3710                         } else {
3711                                 //
3712                                 // A local variable captured by anonymous methods or itereators.
3713                                 //
3714                                 ec.EmitCapturedVariableInstance (local_info);
3715
3716                                 if (prepare_for_load)
3717                                         ig.Emit (OpCodes.Dup);
3718                                 source.Emit (ec);
3719                                 if (leave_copy){
3720                                         ig.Emit (OpCodes.Dup);
3721                                         temp = new LocalTemporary (ec, Type);
3722                                         temp.Store (ec);
3723                                 }
3724                                 ig.Emit (OpCodes.Stfld, local_info.FieldBuilder);
3725                                 if (temp != null)
3726                                         temp.Emit (ec);
3727                         }
3728                 }
3729                 
3730                 public void AddressOf (EmitContext ec, AddressOp mode)
3731                 {
3732                         ILGenerator ig = ec.ig;
3733
3734                         if (local_info.FieldBuilder == null){
3735                                 //
3736                                 // A local variable on the local CLR stack
3737                                 //
3738                                 ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
3739                         } else {
3740                                 //
3741                                 // A local variable captured by anonymous methods or iterators
3742                                 //
3743                                 ec.EmitCapturedVariableInstance (local_info);
3744                                 ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder);
3745                         }
3746                 }
3747
3748                 public override string ToString ()
3749                 {
3750                         return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3751                 }
3752         }
3753
3754         /// <summary>
3755         ///   This represents a reference to a parameter in the intermediate
3756         ///   representation.
3757         /// </summary>
3758         public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3759                 Parameters pars;
3760                 String name;
3761                 int idx;
3762                 Block block;
3763                 VariableInfo vi;
3764                 public Parameter.Modifier mod;
3765                 public bool is_ref, is_out, prepared;
3766
3767                 public bool IsOut {
3768                         get {
3769                                 return is_out;
3770                         }
3771                 }
3772
3773                 public bool IsRef {
3774                         get {
3775                                 return is_ref;
3776                         }
3777                 }
3778
3779                 LocalTemporary temp;
3780                 
3781                 public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc)
3782                 {
3783                         this.pars = pars;
3784                         this.block = block;
3785                         this.idx  = idx;
3786                         this.name = name;
3787                         this.loc = loc;
3788                         eclass = ExprClass.Variable;
3789                 }
3790
3791                 public VariableInfo VariableInfo {
3792                         get { return vi; }
3793                 }
3794
3795                 public bool VerifyFixed (bool is_expression)
3796                 {
3797                         return !is_expression || TypeManager.IsValueType (type);
3798                 }
3799
3800                 public bool IsAssigned (EmitContext ec, Location loc)
3801                 {
3802                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (vi))
3803                                 return true;
3804
3805                         Report.Error (165, loc,
3806                                       "Use of unassigned parameter `" + name + "'");
3807                         return false;
3808                 }
3809
3810                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3811                 {
3812                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (vi, field_name))
3813                                 return true;
3814
3815                         Report.Error (170, loc,
3816                                       "Use of possibly unassigned field `" + field_name + "'");
3817                         return false;
3818                 }
3819
3820                 public void SetAssigned (EmitContext ec)
3821                 {
3822                         if (is_out && ec.DoFlowAnalysis)
3823                                 ec.CurrentBranching.SetAssigned (vi);
3824                 }
3825
3826                 public void SetFieldAssigned (EmitContext ec, string field_name)        
3827                 {
3828                         if (is_out && ec.DoFlowAnalysis)
3829                                 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
3830                 }
3831
3832                 protected void DoResolveBase (EmitContext ec)
3833                 {
3834                         type = pars.GetParameterInfo (ec, idx, out mod);
3835                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3836                         is_out = (mod & Parameter.Modifier.OUT) != 0;
3837                         eclass = ExprClass.Variable;
3838
3839                         if (is_out)
3840                                 vi = block.ParameterMap [idx];
3841
3842                         if (ec.CurrentAnonymousMethod != null){
3843                                 if (is_ref){
3844                                         Report.Error (1628, Location,
3845                                                       "Can not reference a ref or out parameter in an anonymous method");
3846                                         return;
3847                                 }
3848                                 
3849                                 //
3850                                 // If we are referencing the parameter from the external block
3851                                 // flag it for capturing
3852                                 //
3853                                 //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name));
3854                                 if (!block.IsLocalParameter (name)){
3855                                         ec.CaptureParameter (name, type, idx);
3856                                 }
3857                         }
3858                 }
3859
3860                 //
3861                 // Notice that for ref/out parameters, the type exposed is not the
3862                 // same type exposed externally.
3863                 //
3864                 // for "ref int a":
3865                 //   externally we expose "int&"
3866                 //   here we expose       "int".
3867                 //
3868                 // We record this in "is_ref".  This means that the type system can treat
3869                 // the type as it is expected, but when we generate the code, we generate
3870                 // the alternate kind of code.
3871                 //
3872                 public override Expression DoResolve (EmitContext ec)
3873                 {
3874                         DoResolveBase (ec);
3875
3876                         if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3877                                 return null;
3878
3879                         if (ec.RemapToProxy)
3880                                 return ec.RemapParameter (idx);
3881                         
3882                         return this;
3883                 }
3884
3885                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3886                 {
3887                         DoResolveBase (ec);
3888
3889                         SetAssigned (ec);
3890
3891                         if (ec.RemapToProxy)
3892                                 return ec.RemapParameterLValue (idx, right_side);
3893                         
3894                         return this;
3895                 }
3896
3897                 static public void EmitLdArg (ILGenerator ig, int x)
3898                 {
3899                         if (x <= 255){
3900                                 switch (x){
3901                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3902                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3903                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3904                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3905                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3906                                 }
3907                         } else
3908                                 ig.Emit (OpCodes.Ldarg, x);
3909                 }
3910                 
3911                 //
3912                 // This method is used by parameters that are references, that are
3913                 // being passed as references:  we only want to pass the pointer (that
3914                 // is already stored in the parameter, not the address of the pointer,
3915                 // and not the value of the variable).
3916                 //
3917                 public void EmitLoad (EmitContext ec)
3918                 {
3919                         ILGenerator ig = ec.ig;
3920                         int arg_idx = idx;
3921
3922                         if (!ec.IsStatic)
3923                                 arg_idx++;
3924
3925                         EmitLdArg (ig, arg_idx);
3926
3927                         //
3928                         // FIXME: Review for anonymous methods
3929                         //
3930                 }
3931                 
3932                 public override void Emit (EmitContext ec)
3933                 {
3934                         if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
3935                                 ec.EmitParameter (name);
3936                                 return;
3937                         }
3938                         
3939                         Emit (ec, false);
3940                 }
3941                 
3942                 public void Emit (EmitContext ec, bool leave_copy)
3943                 {
3944                         ILGenerator ig = ec.ig;
3945                         int arg_idx = idx;
3946
3947                         if (!ec.IsStatic)
3948                                 arg_idx++;
3949
3950                         EmitLdArg (ig, arg_idx);
3951
3952                         if (is_ref) {
3953                                 if (prepared)
3954                                         ec.ig.Emit (OpCodes.Dup);
3955         
3956                                 //
3957                                 // If we are a reference, we loaded on the stack a pointer
3958                                 // Now lets load the real value
3959                                 //
3960                                 LoadFromPtr (ig, type);
3961                         }
3962                         
3963                         if (leave_copy) {
3964                                 ec.ig.Emit (OpCodes.Dup);
3965                                 
3966                                 if (is_ref) {
3967                                         temp = new LocalTemporary (ec, type);
3968                                         temp.Store (ec);
3969                                 }
3970                         }
3971                 }
3972                 
3973                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
3974                 {
3975                         if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
3976                                 ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load);
3977                                 return;
3978                         }
3979
3980                         ILGenerator ig = ec.ig;
3981                         int arg_idx = idx;
3982                         
3983                         prepared = prepare_for_load;
3984                         
3985                         if (!ec.IsStatic)
3986                                 arg_idx++;
3987
3988                         if (is_ref && !prepared)
3989                                 EmitLdArg (ig, arg_idx);
3990                         
3991                         source.Emit (ec);
3992
3993                         if (leave_copy)
3994                                 ec.ig.Emit (OpCodes.Dup);
3995                         
3996                         if (is_ref) {
3997                                 if (leave_copy) {
3998                                         temp = new LocalTemporary (ec, type);
3999                                         temp.Store (ec);
4000                                 }
4001                                 
4002                                 StoreFromPtr (ig, type);
4003                                 
4004                                 if (temp != null)
4005                                         temp.Emit (ec);
4006                         } else {
4007                                 if (arg_idx <= 255)
4008                                         ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
4009                                 else
4010                                         ig.Emit (OpCodes.Starg, arg_idx);
4011                         }
4012                 }
4013
4014                 public void AddressOf (EmitContext ec, AddressOp mode)
4015                 {
4016                         if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
4017                                 ec.EmitAddressOfParameter (name);
4018                                 return;
4019                         }
4020                         
4021                         int arg_idx = idx;
4022
4023                         if (!ec.IsStatic)
4024                                 arg_idx++;
4025
4026                         if (is_ref){
4027                                 if (arg_idx <= 255)
4028                                         ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
4029                                 else
4030                                         ec.ig.Emit (OpCodes.Ldarg, arg_idx);
4031                         } else {
4032                                 if (arg_idx <= 255)
4033                                         ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
4034                                 else
4035                                         ec.ig.Emit (OpCodes.Ldarga, arg_idx);
4036                         }
4037                 }
4038
4039         }
4040         
4041         /// <summary>
4042         ///   Used for arguments to New(), Invocation()
4043         /// </summary>
4044         public class Argument {
4045                 public enum AType : byte {
4046                         Expression,
4047                         Ref,
4048                         Out,
4049                         ArgList
4050                 };
4051
4052                 public readonly AType ArgType;
4053                 public Expression Expr;
4054                 
4055                 public Argument (Expression expr, AType type)
4056                 {
4057                         this.Expr = expr;
4058                         this.ArgType = type;
4059                 }
4060
4061                 public Argument (Expression expr)
4062                 {
4063                         this.Expr = expr;
4064                         this.ArgType = AType.Expression;
4065                 }
4066
4067                 public Type Type {
4068                         get {
4069                                 if (ArgType == AType.Ref || ArgType == AType.Out)
4070                                         return TypeManager.GetReferenceType (Expr.Type);
4071                                 else
4072                                         return Expr.Type;
4073                         }
4074                 }
4075
4076                 public Parameter.Modifier GetParameterModifier ()
4077                 {
4078                         switch (ArgType) {
4079                         case AType.Out:
4080                                 return Parameter.Modifier.OUT | Parameter.Modifier.ISBYREF;
4081
4082                         case AType.Ref:
4083                                 return Parameter.Modifier.REF | Parameter.Modifier.ISBYREF;
4084
4085                         default:
4086                                 return Parameter.Modifier.NONE;
4087                         }
4088                 }
4089
4090                 public static string FullDesc (Argument a)
4091                 {
4092                         if (a.ArgType == AType.ArgList)
4093                                 return "__arglist";
4094
4095                         return (a.ArgType == AType.Ref ? "ref " :
4096                                 (a.ArgType == AType.Out ? "out " : "")) +
4097                                 TypeManager.CSharpName (a.Expr.Type);
4098                 }
4099
4100                 public bool ResolveMethodGroup (EmitContext ec, Location loc)
4101                 {
4102                         // FIXME: csc doesn't report any error if you try to use `ref' or
4103                         //        `out' in a delegate creation expression.
4104                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4105                         if (Expr == null)
4106                                 return false;
4107
4108                         return true;
4109                 }
4110                 
4111                 public bool Resolve (EmitContext ec, Location loc)
4112                 {
4113                         if (ArgType == AType.Ref) {
4114                                 Expr = Expr.Resolve (ec);
4115                                 if (Expr == null)
4116                                         return false;
4117
4118                                 if (!ec.IsConstructor) {
4119                                         FieldExpr fe = Expr as FieldExpr;
4120                                         if (fe != null && fe.FieldInfo.IsInitOnly) {
4121                                                 if (fe.FieldInfo.IsStatic)
4122                                                         Report.Error (199, loc, "A static readonly field cannot be passed ref or out (except in a static constructor)");
4123                                                 else
4124                                                         Report.Error (192, loc, "A readonly field cannot be passed ref or out (except in a constructor)");
4125                                                 return false;
4126                                         }
4127                                 }
4128                                 Expr = Expr.ResolveLValue (ec, Expr);
4129                         } else if (ArgType == AType.Out)
4130                                 Expr = Expr.ResolveLValue (ec, EmptyExpression.Null);
4131                         else
4132                                 Expr = Expr.Resolve (ec);
4133
4134                         if (Expr == null)
4135                                 return false;
4136
4137                         if (ArgType == AType.Expression)
4138                                 return true;
4139                         else {
4140                                 //
4141                                 // Catch errors where fields of a MarshalByRefObject are passed as ref or out
4142                                 // This is only allowed for `this'
4143                                 //
4144                                 FieldExpr fe = Expr as FieldExpr;
4145                                 if (fe != null && !fe.IsStatic){
4146                                         Expression instance = fe.InstanceExpression;
4147
4148                                         if (instance.GetType () != typeof (This)){
4149                                                 if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){
4150                                                         Report.SymbolRelatedToPreviousError (fe.InstanceExpression.Type);
4151                                                         Report.Error (197, loc, "Cannot pass '{0}' as ref or out or take its address because it is a member of a marshal-by-reference class",
4152                                                                 fe.Name);
4153                                                         return false;
4154                                                 }
4155                                         }
4156                                 }
4157                         }
4158
4159                         if (Expr.eclass != ExprClass.Variable){
4160                                 //
4161                                 // We just probe to match the CSC output
4162                                 //
4163                                 if (Expr.eclass == ExprClass.PropertyAccess ||
4164                                     Expr.eclass == ExprClass.IndexerAccess){
4165                                         Report.Error (
4166                                                 206, loc,
4167                                                 "A property or indexer can not be passed as an out or ref " +
4168                                                 "parameter");
4169                                 } else {
4170                                         Report.Error (
4171                                                 1510, loc,
4172                                                 "An lvalue is required as an argument to out or ref");
4173                                 }
4174                                 return false;
4175                         }
4176                                 
4177                         return true;
4178                 }
4179
4180                 public void Emit (EmitContext ec)
4181                 {
4182                         //
4183                         // Ref and Out parameters need to have their addresses taken.
4184                         //
4185                         // ParameterReferences might already be references, so we want
4186                         // to pass just the value
4187                         //
4188                         if (ArgType == AType.Ref || ArgType == AType.Out){
4189                                 AddressOp mode = AddressOp.Store;
4190
4191                                 if (ArgType == AType.Ref)
4192                                         mode |= AddressOp.Load;
4193                                 
4194                                 if (Expr is ParameterReference){
4195                                         ParameterReference pr = (ParameterReference) Expr;
4196
4197                                         if (pr.IsRef)
4198                                                 pr.EmitLoad (ec);
4199                                         else {
4200                                                 
4201                                                 pr.AddressOf (ec, mode);
4202                                         }
4203                                 } else {
4204                                         ((IMemoryLocation)Expr).AddressOf (ec, mode);
4205                                 }
4206                         } else
4207                                 Expr.Emit (ec);
4208                 }
4209         }
4210
4211         /// <summary>
4212         ///   Invocation of methods or delegates.
4213         /// </summary>
4214         public class Invocation : ExpressionStatement {
4215                 public readonly ArrayList Arguments;
4216
4217                 Expression expr;
4218                 MethodBase method = null;
4219                 
4220                 static Hashtable method_parameter_cache;
4221
4222                 static Invocation ()
4223                 {
4224                         method_parameter_cache = new PtrHashtable ();
4225                 }
4226                         
4227                 //
4228                 // arguments is an ArrayList, but we do not want to typecast,
4229                 // as it might be null.
4230                 //
4231                 // FIXME: only allow expr to be a method invocation or a
4232                 // delegate invocation (7.5.5)
4233                 //
4234                 public Invocation (Expression expr, ArrayList arguments, Location l)
4235                 {
4236                         this.expr = expr;
4237                         Arguments = arguments;
4238                         loc = l;
4239                 }
4240
4241                 public Expression Expr {
4242                         get {
4243                                 return expr;
4244                         }
4245                 }
4246
4247                 /// <summary>
4248                 ///   Returns the Parameters (a ParameterData interface) for the
4249                 ///   Method `mb'
4250                 /// </summary>
4251                 public static ParameterData GetParameterData (MethodBase mb)
4252                 {
4253                         object pd = method_parameter_cache [mb];
4254                         object ip;
4255                         
4256                         if (pd != null)
4257                                 return (ParameterData) pd;
4258
4259                         
4260                         ip = TypeManager.LookupParametersByBuilder (mb);
4261                         if (ip != null){
4262                                 method_parameter_cache [mb] = ip;
4263
4264                                 return (ParameterData) ip;
4265                         } else {
4266                                 ReflectionParameters rp = new ReflectionParameters (mb);
4267                                 method_parameter_cache [mb] = rp;
4268
4269                                 return (ParameterData) rp;
4270                         }
4271                 }
4272
4273                 /// <summary>
4274                 ///   Determines "better conversion" as specified in 7.4.2.3
4275                 ///
4276                 ///    Returns : p    if a->p is better,
4277                 ///              q    if a->q is better,
4278                 ///              null if neither is better
4279                 /// </summary>
4280                 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
4281                 {
4282                         Type argument_type = a.Type;
4283                         Expression argument_expr = a.Expr;
4284
4285                         if (argument_type == null)
4286                                 throw new Exception ("Expression of type " + a.Expr +
4287                                                      " does not resolve its type");
4288
4289                         if (p == null || q == null)
4290                                 throw new InternalErrorException ("BetterConversion Got a null conversion");
4291
4292                         if (p == q)
4293                                 return null;
4294
4295                         if (argument_expr is NullLiteral) {
4296                                 //
4297                                 // If the argument is null and one of the types to compare is 'object' and
4298                                 // the other is a reference type, we prefer the other.
4299                                 //
4300                                 // This follows from the usual rules:
4301                                 //   * There is an implicit conversion from 'null' to type 'object'
4302                                 //   * There is an implicit conversion from 'null' to any reference type
4303                                 //   * There is an implicit conversion from any reference type to type 'object'
4304                                 //   * There is no implicit conversion from type 'object' to other reference types
4305                                 //  => Conversion of 'null' to a reference type is better than conversion to 'object'
4306                                 //
4307                                 //  FIXME: This probably isn't necessary, since the type of a NullLiteral is the 
4308                                 //         null type. I think it used to be 'object' and thus needed a special 
4309                                 //         case to avoid the immediately following two checks.
4310                                 //
4311                                 if (!p.IsValueType && q == TypeManager.object_type)
4312                                         return p;
4313                                 if (!q.IsValueType && p == TypeManager.object_type)
4314                                         return q;
4315                         }
4316                                 
4317                         if (argument_type == p)
4318                                 return p;
4319
4320                         if (argument_type == q)
4321                                 return q;
4322
4323                         Expression p_tmp = new EmptyExpression (p);
4324                         Expression q_tmp = new EmptyExpression (q);
4325
4326                         bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4327                         bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4328
4329                         if (p_to_q && !q_to_p)
4330                                 return p;
4331
4332                         if (q_to_p && !p_to_q)
4333                                 return q;
4334
4335                         if (p == TypeManager.sbyte_type)
4336                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4337                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4338                                         return p;
4339                         if (q == TypeManager.sbyte_type)
4340                                 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
4341                                     p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4342                                         return q;
4343
4344                         if (p == TypeManager.short_type)
4345                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4346                                     q == TypeManager.uint64_type)
4347                                         return p;
4348                         if (q == TypeManager.short_type)
4349                                 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
4350                                     p == TypeManager.uint64_type)
4351                                         return q;
4352
4353                         if (p == TypeManager.int32_type)
4354                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4355                                         return p;
4356                         if (q == TypeManager.int32_type)
4357                                 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4358                                         return q;
4359
4360                         if (p == TypeManager.int64_type)
4361                                 if (q == TypeManager.uint64_type)
4362                                         return p;
4363                         if (q == TypeManager.int64_type)
4364                                 if (p == TypeManager.uint64_type)
4365                                         return q;
4366
4367                         return null;
4368                 }
4369                 
4370                 /// <summary>
4371                 ///   Determines "Better function" between candidate
4372                 ///   and the current best match
4373                 /// </summary>
4374                 /// <remarks>
4375                 ///    Returns an integer indicating :
4376                 ///     false if candidate ain't better
4377                 ///     true if candidate is better than the current best match
4378                 /// </remarks>
4379                 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
4380                                             MethodBase candidate, bool candidate_params,
4381                                             MethodBase best, bool best_params, Location loc)
4382                 {
4383                         ParameterData candidate_pd = GetParameterData (candidate);
4384                         ParameterData best_pd = GetParameterData (best);
4385                 
4386                         int cand_count = candidate_pd.Count;
4387                         
4388                         //
4389                         // If there is no best method, than this one
4390                         // is better, however, if we already found a
4391                         // best method, we cant tell. This happens
4392                         // if we have:
4393                         // 
4394                         //      interface IFoo {
4395                         //              void DoIt ();
4396                         //      }
4397                         //      
4398                         //      interface IBar {
4399                         //              void DoIt ();
4400                         //      }
4401                         //      
4402                         //      interface IFooBar : IFoo, IBar {}
4403                         //
4404                         // We cant tell if IFoo.DoIt is better than IBar.DoIt
4405                         //
4406                         // However, we have to consider that
4407                         // Trim (); is better than Trim (params char[] chars);
4408                         //
4409                         if (cand_count == 0 && argument_count == 0)
4410                                 return !candidate_params && best_params;
4411
4412                         if ((candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS) &&
4413                             (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.ARGLIST))
4414                                 if (cand_count != argument_count)
4415                                         return false;
4416
4417                         bool better_at_least_one = false;
4418                         for (int j = 0; j < argument_count; ++j) {
4419                                 Argument a = (Argument) args [j];
4420
4421                                 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (j));
4422                                 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (j));
4423
4424                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4425                                         if (candidate_params)
4426                                                 ct = TypeManager.GetElementType (ct);
4427
4428                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4429                                         if (best_params)
4430                                                 bt = TypeManager.GetElementType (bt);
4431
4432                                 Type better = BetterConversion (ec, a, ct, bt, loc);
4433
4434                                 // for each argument, the conversion to 'ct' should be no worse than 
4435                                 // the conversion to 'bt'.
4436                                 if (better == bt)
4437                                         return false;
4438
4439                                 // for at least one argument, the conversion to 'ct' should be better than 
4440                                 // the conversion to 'bt'.
4441                                 if (better == ct)
4442                                         better_at_least_one = true;
4443                         }
4444
4445                         //
4446                         // If a method (in the normal form) with the
4447                         // same signature as the expanded form of the
4448                         // current best params method already exists,
4449                         // the expanded form is not applicable so we
4450                         // force it to select the candidate
4451                         //
4452                         if (!candidate_params && best_params && cand_count == argument_count)
4453                                 return true;
4454
4455                         return better_at_least_one;
4456                 }
4457
4458                 public static string FullMethodDesc (MethodBase mb)
4459                 {
4460                         string ret_type = "";
4461
4462                         if (mb == null)
4463                                 return "";
4464
4465                         if (mb is MethodInfo)
4466                                 ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
4467                         
4468                         StringBuilder sb = new StringBuilder (ret_type);
4469                         sb.Append (" ");
4470                         sb.Append (mb.ReflectedType.ToString ());
4471                         sb.Append (".");
4472                         sb.Append (mb.Name);
4473                         
4474                         ParameterData pd = GetParameterData (mb);
4475
4476                         int count = pd.Count;
4477                         sb.Append (" (");
4478                         
4479                         for (int i = count; i > 0; ) {
4480                                 i--;
4481
4482                                 sb.Append (pd.ParameterDesc (count - i - 1));
4483                                 if (i != 0)
4484                                         sb.Append (", ");
4485                         }
4486                         
4487                         sb.Append (")");
4488                         return sb.ToString ();
4489                 }
4490
4491                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4492                 {
4493                         MemberInfo [] miset;
4494                         MethodGroupExpr union;
4495
4496                         if (mg1 == null) {
4497                                 if (mg2 == null)
4498                                         return null;
4499                                 return (MethodGroupExpr) mg2;
4500                         } else {
4501                                 if (mg2 == null)
4502                                         return (MethodGroupExpr) mg1;
4503                         }
4504                         
4505                         MethodGroupExpr left_set = null, right_set = null;
4506                         int length1 = 0, length2 = 0;
4507                         
4508                         left_set = (MethodGroupExpr) mg1;
4509                         length1 = left_set.Methods.Length;
4510                         
4511                         right_set = (MethodGroupExpr) mg2;
4512                         length2 = right_set.Methods.Length;
4513                         
4514                         ArrayList common = new ArrayList ();
4515
4516                         foreach (MethodBase r in right_set.Methods){
4517                                 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4518                                         common.Add (r);
4519                         }
4520
4521                         miset = new MemberInfo [length1 + length2 - common.Count];
4522                         left_set.Methods.CopyTo (miset, 0);
4523                         
4524                         int k = length1;
4525
4526                         foreach (MethodBase r in right_set.Methods) {
4527                                 if (!common.Contains (r))
4528                                         miset [k++] = r;
4529                         }
4530
4531                         union = new MethodGroupExpr (miset, loc);
4532                         
4533                         return union;
4534                 }
4535
4536                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4537                                                       ArrayList arguments, int arg_count,
4538                                                       ref MethodBase candidate)
4539                 {
4540                         return IsParamsMethodApplicable (
4541                                 ec, me, arguments, arg_count, false, ref candidate) ||
4542                                 IsParamsMethodApplicable (
4543                                         ec, me, arguments, arg_count, true, ref candidate);
4544
4545
4546                 }
4547
4548                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4549                                                       ArrayList arguments, int arg_count,
4550                                                       bool do_varargs, ref MethodBase candidate)
4551                 {
4552                         return IsParamsMethodApplicable (
4553                                 ec, arguments, arg_count, candidate, do_varargs);
4554                 }
4555
4556                 /// <summary>
4557                 ///   Determines if the candidate method, if a params method, is applicable
4558                 ///   in its expanded form to the given set of arguments
4559                 /// </summary>
4560                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4561                                                       int arg_count, MethodBase candidate,
4562                                                       bool do_varargs)
4563                 {
4564                         ParameterData pd = GetParameterData (candidate);
4565
4566                         int pd_count = pd.Count;
4567                         if (pd_count == 0)
4568                                 return false;
4569
4570                         int count = pd_count - 1;
4571                         if (do_varargs) {
4572                                 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4573                                         return false;
4574                                 if (pd_count != arg_count)
4575                                         return false;
4576                         } else {
4577                                 if (pd.ParameterModifier (count) != Parameter.Modifier.PARAMS)
4578                                         return false;
4579                         }
4580                         
4581                         if (count > arg_count)
4582                                 return false;
4583                         
4584                         if (pd_count == 1 && arg_count == 0)
4585                                 return true;
4586
4587                         //
4588                         // If we have come this far, the case which
4589                         // remains is when the number of parameters is
4590                         // less than or equal to the argument count.
4591                         //
4592                         for (int i = 0; i < count; ++i) {
4593
4594                                 Argument a = (Argument) arguments [i];
4595
4596                                 Parameter.Modifier a_mod = a.GetParameterModifier () & 
4597                                         (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4598                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4599                                         (unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF)));
4600
4601                                 if (a_mod == p_mod) {
4602
4603                                         if (a_mod == Parameter.Modifier.NONE)
4604                                                 if (!Convert.ImplicitConversionExists (ec,
4605                                                                                        a.Expr,
4606                                                                                        pd.ParameterType (i)))
4607                                                         return false;
4608                                                                                 
4609                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4610                                                 Type pt = pd.ParameterType (i);
4611
4612                                                 if (!pt.IsByRef)
4613                                                         pt = TypeManager.GetReferenceType (pt);
4614                                                 
4615                                                 if (pt != a.Type)
4616                                                         return false;
4617                                         }
4618                                 } else
4619                                         return false;
4620                                 
4621                         }
4622
4623                         if (do_varargs) {
4624                                 Argument a = (Argument) arguments [count];
4625                                 if (!(a.Expr is Arglist))
4626                                         return false;
4627
4628                                 return true;
4629                         }
4630
4631                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
4632
4633                         for (int i = pd_count - 1; i < arg_count; i++) {
4634                                 Argument a = (Argument) arguments [i];
4635
4636                                 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4637                                         return false;
4638                         }
4639                         
4640                         return true;
4641                 }
4642
4643                 static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4644                                           ArrayList arguments, int arg_count,
4645                                           ref MethodBase candidate)
4646                 {
4647                         return IsApplicable (ec, arguments, arg_count, candidate);
4648                 }
4649
4650                 /// <summary>
4651                 ///   Determines if the candidate method is applicable (section 14.4.2.1)
4652                 ///   to the given set of arguments
4653                 /// </summary>
4654                 static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4655                                           MethodBase candidate)
4656                 {
4657                         ParameterData pd = GetParameterData (candidate);
4658
4659                         if (arg_count != pd.Count)
4660                                 return false;
4661
4662                         for (int i = arg_count; i > 0; ) {
4663                                 i--;
4664
4665                                 Argument a = (Argument) arguments [i];
4666
4667                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
4668                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
4669                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4670                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
4671
4672
4673                                 if (a_mod == p_mod ||
4674                                     (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
4675                                         if (a_mod == Parameter.Modifier.NONE) {
4676                                                 if (!Convert.ImplicitConversionExists (ec,
4677                                                                                        a.Expr,
4678                                                                                        pd.ParameterType (i)))
4679                                                         return false;
4680                                         }
4681                                         
4682                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4683                                                 Type pt = pd.ParameterType (i);
4684
4685                                                 if (!pt.IsByRef)
4686                                                         pt = TypeManager.GetReferenceType (pt);
4687                                                 
4688                                                 if (pt != a.Type)
4689                                                         return false;
4690                                         }
4691                                 } else
4692                                         return false;
4693                         }
4694
4695                         return true;
4696                 }
4697
4698                 static private bool IsAncestralType (Type first_type, Type second_type)
4699                 {
4700                         return first_type != second_type &&
4701                                 (second_type.IsSubclassOf (first_type) ||
4702                                  TypeManager.ImplementsInterface (second_type, first_type));
4703                 }
4704                 
4705                 /// <summary>
4706                 ///   Find the Applicable Function Members (7.4.2.1)
4707                 ///
4708                 ///   me: Method Group expression with the members to select.
4709                 ///       it might contain constructors or methods (or anything
4710                 ///       that maps to a method).
4711                 ///
4712                 ///   Arguments: ArrayList containing resolved Argument objects.
4713                 ///
4714                 ///   loc: The location if we want an error to be reported, or a Null
4715                 ///        location for "probing" purposes.
4716                 ///
4717                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4718                 ///            that is the best match of me on Arguments.
4719                 ///
4720                 /// </summary>
4721                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4722                                                           ArrayList Arguments, bool may_fail, 
4723                                                           Location loc)
4724                 {
4725                         MethodBase method = null;
4726                         bool method_params = false;
4727                         Type applicable_type = null;
4728                         int arg_count = 0;
4729                         ArrayList candidates = new ArrayList ();
4730
4731                         //
4732                         // Used to keep a map between the candidate
4733                         // and whether it is being considered in its
4734                         // normal or expanded form
4735                         //
4736                         // false is normal form, true is expanded form
4737                         //
4738                         Hashtable candidate_to_form = null;
4739
4740                         if (Arguments != null)
4741                                 arg_count = Arguments.Count;
4742
4743                         if ((me.Name == "Invoke") &&
4744                             TypeManager.IsDelegateType (me.DeclaringType)) {
4745                                 Error_InvokeOnDelegate (loc);
4746                                 return null;
4747                         }
4748
4749                         MethodBase[] methods = me.Methods;
4750
4751                         //
4752                         // First we construct the set of applicable methods
4753                         //
4754                         bool is_sorted = true;
4755                         for (int i = 0; i < methods.Length; i++){
4756                                 Type decl_type = methods [i].DeclaringType;
4757
4758                                 //
4759                                 // If we have already found an applicable method
4760                                 // we eliminate all base types (Section 14.5.5.1)
4761                                 //
4762                                 if ((applicable_type != null) &&
4763                                     IsAncestralType (decl_type, applicable_type))
4764                                         continue;
4765
4766                                 //
4767                                 // Check if candidate is applicable (section 14.4.2.1)
4768                                 //   Is candidate applicable in normal form?
4769                                 //
4770                                 bool is_applicable = IsApplicable (
4771                                         ec, me, Arguments, arg_count, ref methods [i]);
4772
4773                                 if (!is_applicable &&
4774                                     (IsParamsMethodApplicable (
4775                                             ec, me, Arguments, arg_count, ref methods [i]))) {
4776                                         MethodBase candidate = methods [i];
4777                                         if (candidate_to_form == null)
4778                                                 candidate_to_form = new PtrHashtable ();
4779                                         candidate_to_form [candidate] = candidate;
4780                                         // Candidate is applicable in expanded form
4781                                         is_applicable = true;
4782                                 }
4783
4784                                 if (!is_applicable)
4785                                         continue;
4786
4787                                 candidates.Add (methods [i]);
4788
4789                                 if (applicable_type == null)
4790                                         applicable_type = decl_type;
4791                                 else if (applicable_type != decl_type) {
4792                                         is_sorted = false;
4793                                         if (IsAncestralType (applicable_type, decl_type))
4794                                                 applicable_type = decl_type;
4795                                 }
4796                         }
4797
4798                         int candidate_top = candidates.Count;
4799
4800                         if (candidate_top == 0) {
4801                                 //
4802                                 // Okay so we have failed to find anything so we
4803                                 // return by providing info about the closest match
4804                                 //
4805                                 for (int i = 0; i < methods.Length; ++i) {
4806                                         MethodBase c = (MethodBase) methods [i];
4807                                         ParameterData pd = GetParameterData (c);
4808
4809                                         if (pd.Count != arg_count)
4810                                                 continue;
4811
4812                                         VerifyArgumentsCompat (ec, Arguments, arg_count,
4813                                                                c, false, null, may_fail, loc);
4814                                         break;
4815                                 }
4816
4817                                 if (!may_fail) {
4818                                         string report_name = me.Name;
4819                                         if (report_name == ".ctor")
4820                                                 report_name = me.DeclaringType.ToString ();
4821                                         
4822                                         Error_WrongNumArguments (
4823                                                 loc, report_name, arg_count);
4824                                         return null;
4825                                 }
4826                                 
4827                                 return null;
4828                         }
4829
4830                         if (!is_sorted) {
4831                                 //
4832                                 // At this point, applicable_type is _one_ of the most derived types
4833                                 // in the set of types containing the methods in this MethodGroup.
4834                                 // Filter the candidates so that they only contain methods from the
4835                                 // most derived types.
4836                                 //
4837
4838                                 int finalized = 0; // Number of finalized candidates
4839
4840                                 do {
4841                                         // Invariant: applicable_type is a most derived type
4842
4843                                         // We'll try to complete Section 14.5.5.1 for 'applicable_type' by 
4844                                         // eliminating all it's base types.  At the same time, we'll also move
4845                                         // every unrelated type to the end of the array, and pick the next
4846                                         // 'applicable_type'.
4847
4848                                         Type next_applicable_type = null;
4849                                         int j = finalized; // where to put the next finalized candidate
4850                                         int k = finalized; // where to put the next undiscarded candidate
4851                                         for (int i = finalized; i < candidate_top; ++i) {
4852                                                 Type decl_type = ((MethodBase) candidates[i]).DeclaringType;
4853
4854                                                 if (decl_type == applicable_type) {
4855                                                         candidates[k++] = candidates[j];
4856                                                         candidates[j++] = candidates[i];
4857                                                         continue;
4858                                                 }
4859
4860                                                 if (IsAncestralType (decl_type, applicable_type))
4861                                                         continue;
4862
4863                                                 if (next_applicable_type != null &&
4864                                                     IsAncestralType (decl_type, next_applicable_type))
4865                                                         continue;
4866
4867                                                 candidates[k++] = candidates[i];
4868
4869                                                 if (next_applicable_type == null ||
4870                                                     IsAncestralType (next_applicable_type, decl_type))
4871                                                         next_applicable_type = decl_type;
4872                                         }
4873
4874                                         applicable_type = next_applicable_type;
4875                                         finalized = j;
4876                                         candidate_top = k;
4877                                 } while (applicable_type != null);
4878                         }
4879
4880                         //
4881                         // Now we actually find the best method
4882                         //
4883
4884                         method = (MethodBase) candidates[0];
4885                         method_params = candidate_to_form != null && candidate_to_form.Contains (method);
4886                         for (int ix = 1; ix < candidate_top; ix++){
4887                                 MethodBase candidate = (MethodBase) candidates [ix];
4888                                 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4889                                 
4890                                 if (BetterFunction (ec, Arguments, arg_count, 
4891                                                     candidate, cand_params,
4892                                                     method, method_params, loc)) {
4893                                         method = candidate;
4894                                         method_params = cand_params;
4895                                 }
4896                         }
4897
4898                         //
4899                         // Now check that there are no ambiguities i.e the selected method
4900                         // should be better than all the others
4901                         //
4902                         bool ambiguous = false;
4903                         for (int ix = 0; ix < candidate_top; ix++){
4904                                 MethodBase candidate = (MethodBase) candidates [ix];
4905
4906                                 if (candidate == method)
4907                                         continue;
4908
4909                                 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4910                                 if (!BetterFunction (ec, Arguments, arg_count,
4911                                                      method, method_params,
4912                                                      candidate, cand_params,
4913                                                      loc)) {
4914                                         Report.SymbolRelatedToPreviousError (candidate);
4915                                         ambiguous = true;
4916                                 }
4917                         }
4918
4919                         if (ambiguous) {
4920                                 Report.SymbolRelatedToPreviousError (method);
4921                                 Report.Error (121, loc, "Ambiguous call when selecting function due to implicit casts");
4922                                 return null;
4923                         }
4924
4925
4926                         //
4927                         // And now check if the arguments are all
4928                         // compatible, perform conversions if
4929                         // necessary etc. and return if everything is
4930                         // all right
4931                         //
4932                         if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method,
4933                                                     method_params, null, may_fail, loc))
4934                                 return null;
4935
4936                         return method;
4937                 }
4938
4939                 static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4940                 {
4941                         Report.Error (1501, loc,
4942                                       "No overload for method `" + name + "' takes `" +
4943                                       arg_count + "' arguments");
4944                 }
4945
4946                 static void Error_InvokeOnDelegate (Location loc)
4947                 {
4948                         Report.Error (1533, loc,
4949                                       "Invoke cannot be called directly on a delegate");
4950                 }
4951                         
4952                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4953                                                     Type delegate_type, string arg_sig, string par_desc)
4954                 {
4955                         if (delegate_type == null) 
4956                                 Report.Error (1502, loc,
4957                                               "The best overloaded match for method '" +
4958                                               FullMethodDesc (method) +
4959                                               "' has some invalid arguments");
4960                         else
4961                                 Report.Error (1594, loc,
4962                                               "Delegate '" + delegate_type.ToString () +
4963                                               "' has some invalid arguments.");
4964                         Report.Error (1503, loc,
4965                                       String.Format ("Argument {0}: Cannot convert from '{1}' to '{2}'",
4966                                                      idx, arg_sig, par_desc));
4967                 }
4968                 
4969                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4970                                                           int arg_count, MethodBase method, 
4971                                                           bool chose_params_expanded,
4972                                                           Type delegate_type, bool may_fail,
4973                                                           Location loc)
4974                 {
4975                         ParameterData pd = GetParameterData (method);
4976                         int pd_count = pd.Count;
4977
4978                         for (int j = 0; j < arg_count; j++) {
4979                                 Argument a = (Argument) Arguments [j];
4980                                 Expression a_expr = a.Expr;
4981                                 Type parameter_type = pd.ParameterType (j);
4982                                 Parameter.Modifier pm = pd.ParameterModifier (j);
4983                                 
4984                                 if (pm == Parameter.Modifier.PARAMS){
4985                                         if ((pm & ~Parameter.Modifier.PARAMS) != a.GetParameterModifier ()) {
4986                                                 if (!may_fail)
4987                                                         Error_InvalidArguments (
4988                                                                 loc, j, method, delegate_type,
4989                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
4990                                                 return false;
4991                                         }
4992
4993                                         if (chose_params_expanded)
4994                                                 parameter_type = TypeManager.GetElementType (parameter_type);
4995                                 } else if (pm == Parameter.Modifier.ARGLIST){
4996                                         continue;
4997                                 } else {
4998                                         //
4999                                         // Check modifiers
5000                                         //
5001                                         if (pd.ParameterModifier (j) != a.GetParameterModifier ()){
5002                                                 if (!may_fail)
5003                                                         Error_InvalidArguments (
5004                                                                 loc, j, method, delegate_type,
5005                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
5006                                                 return false;
5007                                         }
5008                                 }
5009
5010                                 //
5011                                 // Check Type
5012                                 //
5013                                 if (!a.Type.Equals (parameter_type)){
5014                                         Expression conv;
5015                                         
5016                                         conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
5017
5018                                         if (conv == null) {
5019                                                 if (!may_fail)
5020                                                         Error_InvalidArguments (
5021                                                                 loc, j, method, delegate_type,
5022                                                                 Argument.FullDesc (a), pd.ParameterDesc (j));
5023                                                 return false;
5024                                         }
5025                                         
5026                                         //
5027                                         // Update the argument with the implicit conversion
5028                                         //
5029                                         if (a_expr != conv)
5030                                                 a.Expr = conv;
5031                                 }
5032
5033                                 if (parameter_type.IsPointer){
5034                                         if (!ec.InUnsafe){
5035                                                 UnsafeError (loc);
5036                                                 return false;
5037                                         }
5038                                 }
5039                                 
5040                                 Parameter.Modifier a_mod = a.GetParameterModifier () &
5041                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5042                                 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
5043                                         unchecked (~(Parameter.Modifier.OUT | Parameter.Modifier.REF));
5044                                 
5045                                 if (a_mod != p_mod &&
5046                                     pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
5047                                         if (!may_fail) {
5048                                                 Report.Error (1502, loc,
5049                                                        "The best overloaded match for method '" + FullMethodDesc (method)+
5050                                                        "' has some invalid arguments");
5051                                                 Report.Error (1503, loc,
5052                                                        "Argument " + (j+1) +
5053                                                        ": Cannot convert from '" + Argument.FullDesc (a) 
5054                                                        + "' to '" + pd.ParameterDesc (j) + "'");
5055                                         }
5056                                         
5057                                         return false;
5058                                 }
5059                         }
5060
5061                         return true;
5062                 }
5063
5064                 public override Expression DoResolve (EmitContext ec)
5065                 {
5066                         //
5067                         // First, resolve the expression that is used to
5068                         // trigger the invocation
5069                         //
5070                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
5071                         if (expr == null)
5072                                 return null;
5073
5074                         if (!(expr is MethodGroupExpr)) {
5075                                 Type expr_type = expr.Type;
5076
5077                                 if (expr_type != null){
5078                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
5079                                         if (IsDelegate)
5080                                                 return (new DelegateInvocation (
5081                                                         this.expr, Arguments, loc)).Resolve (ec);
5082                                 }
5083                         }
5084
5085                         if (!(expr is MethodGroupExpr)){
5086                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
5087                                 return null;
5088                         }
5089
5090                         //
5091                         // Next, evaluate all the expressions in the argument list
5092                         //
5093                         if (Arguments != null){
5094                                 foreach (Argument a in Arguments){
5095                                         if (!a.Resolve (ec, loc))
5096                                                 return null;
5097                                 }
5098                         }
5099
5100                         MethodGroupExpr mg = (MethodGroupExpr) expr;
5101                         method = OverloadResolve (ec, mg, Arguments, false, loc);
5102
5103                         if (method == null)
5104                                 return null;
5105
5106                         MethodInfo mi = method as MethodInfo;
5107                         if (mi != null) {
5108                                 type = TypeManager.TypeToCoreType (mi.ReturnType);
5109                                 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null)) {
5110                                         SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
5111                                         return null;
5112                                 }
5113
5114                                 Expression iexpr = mg.InstanceExpression;
5115                                 if (mi.IsStatic && (iexpr != null) && !(iexpr is This)) {
5116                                         if (mg.IdenticalTypeName)
5117                                                 mg.InstanceExpression = null;
5118                                         else {
5119                                                 MemberAccess.error176 (loc, mi.Name);
5120                                                 return null;
5121                                         }
5122                                 }
5123                         }
5124
5125                         if (type.IsPointer){
5126                                 if (!ec.InUnsafe){
5127                                         UnsafeError (loc);
5128                                         return null;
5129                                 }
5130                         }
5131                         
5132                         //
5133                         // Only base will allow this invocation to happen.
5134                         //
5135                         if (mg.IsBase && method.IsAbstract){
5136                                 Report.Error (205, loc, "Cannot call an abstract base member: " +
5137                                               FullMethodDesc (method));
5138                                 return null;
5139                         }
5140
5141                         if (method.Name == "Finalize" && Arguments == null) {
5142                                 if (mg.IsBase)
5143                                         Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5144                                 else
5145                                         Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5146                                 return null;
5147                         }
5148
5149                         if ((method.Attributes & MethodAttributes.SpecialName) != 0) {
5150                                 if (TypeManager.LookupDeclSpace (method.DeclaringType) != null || TypeManager.IsSpecialMethod (method)) {
5151                                         Report.Error (571, loc, TypeManager.CSharpSignature (method) + ": can not call operator or accessor");
5152                                         return null;
5153                                 }
5154                         }
5155
5156                         if (mg.InstanceExpression != null)
5157                                 mg.InstanceExpression.CheckMarshallByRefAccess (ec.ContainerType);
5158
5159                         eclass = ExprClass.Value;
5160                         return this;
5161                 }
5162
5163                 // <summary>
5164                 //   Emits the list of arguments as an array
5165                 // </summary>
5166                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
5167                 {
5168                         ILGenerator ig = ec.ig;
5169                         int count = arguments.Count - idx;
5170                         Argument a = (Argument) arguments [idx];
5171                         Type t = a.Expr.Type;
5172                         
5173                         IntConstant.EmitInt (ig, count);
5174                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5175
5176                         int top = arguments.Count;
5177                         for (int j = idx; j < top; j++){
5178                                 a = (Argument) arguments [j];
5179                                 
5180                                 ig.Emit (OpCodes.Dup);
5181                                 IntConstant.EmitInt (ig, j - idx);
5182
5183                                 bool is_stobj;
5184                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj);
5185                                 if (is_stobj)
5186                                         ig.Emit (OpCodes.Ldelema, t);
5187
5188                                 a.Emit (ec);
5189
5190                                 if (is_stobj)
5191                                         ig.Emit (OpCodes.Stobj, t);
5192                                 else
5193                                         ig.Emit (op);
5194                         }
5195                 }
5196                 
5197                 /// <summary>
5198                 ///   Emits a list of resolved Arguments that are in the arguments
5199                 ///   ArrayList.
5200                 /// 
5201                 ///   The MethodBase argument might be null if the
5202                 ///   emission of the arguments is known not to contain
5203                 ///   a `params' field (for example in constructors or other routines
5204                 ///   that keep their arguments in this structure)
5205                 ///   
5206                 ///   if `dup_args' is true, a copy of the arguments will be left
5207                 ///   on the stack. If `dup_args' is true, you can specify `this_arg'
5208                 ///   which will be duplicated before any other args. Only EmitCall
5209                 ///   should be using this interface.
5210                 /// </summary>
5211                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
5212                 {
5213                         ParameterData pd;
5214                         if (mb != null)
5215                                 pd = GetParameterData (mb);
5216                         else
5217                                 pd = null;
5218                         
5219                         LocalTemporary [] temps = null;
5220                         
5221                         if (dup_args)
5222                                 temps = new LocalTemporary [arguments.Count];
5223
5224                         //
5225                         // If we are calling a params method with no arguments, special case it
5226                         //
5227                         if (arguments == null){
5228                                 if (pd != null && pd.Count > 0 &&
5229                                     pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
5230                                         ILGenerator ig = ec.ig;
5231
5232                                         IntConstant.EmitInt (ig, 0);
5233                                         ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (0)));
5234                                 }
5235
5236                                 return;
5237                         }
5238
5239                         int top = arguments.Count;
5240
5241                         for (int i = 0; i < top; i++){
5242                                 Argument a = (Argument) arguments [i];
5243
5244                                 if (pd != null){
5245                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5246                                                 //
5247                                                 // Special case if we are passing the same data as the
5248                                                 // params argument, do not put it in an array.
5249                                                 //
5250                                                 if (pd.ParameterType (i) == a.Type)
5251                                                         a.Emit (ec);
5252                                                 else
5253                                                         EmitParams (ec, i, arguments);
5254                                                 return;
5255                                         }
5256                                 }
5257                                             
5258                                 a.Emit (ec);
5259                                 if (dup_args) {
5260                                         ec.ig.Emit (OpCodes.Dup);
5261                                         (temps [i] = new LocalTemporary (ec, a.Type)).Store (ec);
5262                                 }
5263                         }
5264                         
5265                         if (dup_args) {
5266                                 if (this_arg != null)
5267                                         this_arg.Emit (ec);
5268                                 
5269                                 for (int i = 0; i < top; i ++)
5270                                         temps [i].Emit (ec);
5271                         }
5272
5273                         if (pd != null && pd.Count > top &&
5274                             pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
5275                                 ILGenerator ig = ec.ig;
5276
5277                                 IntConstant.EmitInt (ig, 0);
5278                                 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
5279                         }
5280                 }
5281
5282                 static Type[] GetVarargsTypes (EmitContext ec, MethodBase mb,
5283                                                ArrayList arguments)
5284                 {
5285                         ParameterData pd = GetParameterData (mb);
5286
5287                         if (arguments == null)
5288                                 return new Type [0];
5289
5290                         Argument a = (Argument) arguments [pd.Count - 1];
5291                         Arglist list = (Arglist) a.Expr;
5292
5293                         return list.ArgumentTypes;
5294                 }
5295
5296                 /// <summary>
5297                 /// This checks the ConditionalAttribute on the method 
5298                 /// </summary>
5299                 static bool IsMethodExcluded (MethodBase method, EmitContext ec)
5300                 {
5301                         if (method.IsConstructor)
5302                                 return false;
5303
5304                         IMethodData md = TypeManager.GetMethod (method);
5305                         if (md != null)
5306                                 return md.IsExcluded (ec);
5307
5308                         // For some methods (generated by delegate class) GetMethod returns null
5309                         // because they are not included in builder_to_method table
5310                         if (method.DeclaringType is TypeBuilder)
5311                                 return false;
5312
5313                         return AttributeTester.IsConditionalMethodExcluded (method);
5314                 }
5315
5316                 /// <remarks>
5317                 ///   is_base tells whether we want to force the use of the `call'
5318                 ///   opcode instead of using callvirt.  Call is required to call
5319                 ///   a specific method, while callvirt will always use the most
5320                 ///   recent method in the vtable.
5321                 ///
5322                 ///   is_static tells whether this is an invocation on a static method
5323                 ///
5324                 ///   instance_expr is an expression that represents the instance
5325                 ///   it must be non-null if is_static is false.
5326                 ///
5327                 ///   method is the method to invoke.
5328                 ///
5329                 ///   Arguments is the list of arguments to pass to the method or constructor.
5330                 /// </remarks>
5331                 public static void EmitCall (EmitContext ec, bool is_base,
5332                                              bool is_static, Expression instance_expr,
5333                                              MethodBase method, ArrayList Arguments, Location loc)
5334                 {
5335                         EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
5336                 }
5337                 
5338                 // `dup_args' leaves an extra copy of the arguments on the stack
5339                 // `omit_args' does not leave any arguments at all.
5340                 // So, basically, you could make one call with `dup_args' set to true,
5341                 // and then another with `omit_args' set to true, and the two calls
5342                 // would have the same set of arguments. However, each argument would
5343                 // only have been evaluated once.
5344                 public static void EmitCall (EmitContext ec, bool is_base,
5345                                              bool is_static, Expression instance_expr,
5346                                              MethodBase method, ArrayList Arguments, Location loc,
5347                                              bool dup_args, bool omit_args)
5348                 {
5349                         ILGenerator ig = ec.ig;
5350                         bool struct_call = false;
5351                         bool this_call = false;
5352                         LocalTemporary this_arg = null;
5353
5354                         Type decl_type = method.DeclaringType;
5355
5356                         if (!RootContext.StdLib) {
5357                                 // Replace any calls to the system's System.Array type with calls to
5358                                 // the newly created one.
5359                                 if (method == TypeManager.system_int_array_get_length)
5360                                         method = TypeManager.int_array_get_length;
5361                                 else if (method == TypeManager.system_int_array_get_rank)
5362                                         method = TypeManager.int_array_get_rank;
5363                                 else if (method == TypeManager.system_object_array_clone)
5364                                         method = TypeManager.object_array_clone;
5365                                 else if (method == TypeManager.system_int_array_get_length_int)
5366                                         method = TypeManager.int_array_get_length_int;
5367                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5368                                         method = TypeManager.int_array_get_lower_bound_int;
5369                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5370                                         method = TypeManager.int_array_get_upper_bound_int;
5371                                 else if (method == TypeManager.system_void_array_copyto_array_int)
5372                                         method = TypeManager.void_array_copyto_array_int;
5373                         }
5374
5375                         if (ec.TestObsoleteMethodUsage) {
5376                                 //
5377                                 // This checks ObsoleteAttribute on the method and on the declaring type
5378                                 //
5379                                 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
5380                                 if (oa != null)
5381                                         AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
5382
5383
5384                                 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5385                                 if (oa != null) {
5386                                         AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5387                                 }
5388                         }
5389
5390                         if (IsMethodExcluded (method, ec))
5391                 return; 
5392                         
5393                         if (!is_static){
5394                                 this_call = instance_expr == null;
5395                                 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5396                                         struct_call = true;
5397                                 
5398                                 //
5399                                 // If this is ourselves, push "this"
5400                                 //
5401                                 if (!omit_args) {
5402                                 Type t = null;
5403                                 if (this_call) {
5404                                         ig.Emit (OpCodes.Ldarg_0);
5405                                         t = decl_type;
5406                                 } else {
5407                                         //
5408                                         // Push the instance expression
5409                                         //
5410                                         if (instance_expr.Type.IsValueType) {
5411                                                 //
5412                                                 // Special case: calls to a function declared in a 
5413                                                 // reference-type with a value-type argument need
5414                                                 // to have their value boxed.
5415                                                 if (decl_type.IsValueType) {
5416                                                         //
5417                                                         // If the expression implements IMemoryLocation, then
5418                                                         // we can optimize and use AddressOf on the
5419                                                         // return.
5420                                                         //
5421                                                         // If not we have to use some temporary storage for
5422                                                         // it.
5423                                                         if (instance_expr is IMemoryLocation) {
5424                                                                 ((IMemoryLocation)instance_expr).
5425                                                                         AddressOf (ec, AddressOp.LoadStore);
5426                                                         } else {
5427                                                                 LocalTemporary temp = new LocalTemporary (ec, instance_expr.Type);
5428                                                                 instance_expr.Emit (ec);
5429                                                                 temp.Store (ec);
5430                                                                 temp.AddressOf (ec, AddressOp.Load);
5431                                                         }
5432                                                         
5433                                                         // avoid the overhead of doing this all the time.
5434                                                         if (dup_args)
5435                                                                 t = TypeManager.GetReferenceType (instance_expr.Type);
5436                                                 } else {
5437                                                         instance_expr.Emit (ec);
5438                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
5439                                                         t = TypeManager.object_type;
5440                                                 } 
5441                                         } else {
5442                                                 instance_expr.Emit (ec);
5443                                                 t = instance_expr.Type;
5444                                         }
5445                                 }
5446                                 
5447                                 if (dup_args) {
5448                                         this_arg = new LocalTemporary (ec, t);
5449                                         ig.Emit (OpCodes.Dup);
5450                                         this_arg.Store (ec);
5451                                 }
5452                                 }
5453                         }
5454
5455                         if (!omit_args)
5456                                 EmitArguments (ec, method, Arguments, dup_args, this_arg);
5457
5458                         OpCode call_op;
5459                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5460                                 call_op = OpCodes.Call;
5461                         else
5462                                 call_op = OpCodes.Callvirt;
5463
5464                         if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5465                                 Type[] varargs_types = GetVarargsTypes (ec, method, Arguments);
5466                                 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5467                                 return;
5468                         }
5469
5470                         //
5471                         // If you have:
5472                         // this.DoFoo ();
5473                         // and DoFoo is not virtual, you can omit the callvirt,
5474                         // because you don't need the null checking behavior.
5475                         //
5476                         if (method is MethodInfo)
5477                                 ig.Emit (call_op, (MethodInfo) method);
5478                         else
5479                                 ig.Emit (call_op, (ConstructorInfo) method);
5480                 }
5481                 
5482                 public override void Emit (EmitContext ec)
5483                 {
5484                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5485
5486                         EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5487                 }
5488                 
5489                 public override void EmitStatement (EmitContext ec)
5490                 {
5491                         Emit (ec);
5492
5493                         // 
5494                         // Pop the return value if there is one
5495                         //
5496                         if (method is MethodInfo){
5497                                 Type ret = ((MethodInfo)method).ReturnType;
5498                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5499                                         ec.ig.Emit (OpCodes.Pop);
5500                         }
5501                 }
5502         }
5503
5504         public class InvocationOrCast : ExpressionStatement
5505         {
5506                 Expression expr;
5507                 Expression argument;
5508
5509                 public InvocationOrCast (Expression expr, Expression argument, Location loc)
5510                 {
5511                         this.expr = expr;
5512                         this.argument = argument;
5513                         this.loc = loc;
5514                 }
5515
5516                 public override Expression DoResolve (EmitContext ec)
5517                 {
5518                         //
5519                         // First try to resolve it as a cast.
5520                         //
5521                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5522                         if (te != null) {
5523                                 Cast cast = new Cast (te, argument, loc);
5524                                 return cast.Resolve (ec);
5525                         }
5526
5527                         //
5528                         // This can either be a type or a delegate invocation.
5529                         // Let's just resolve it and see what we'll get.
5530                         //
5531                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5532                         if (expr == null)
5533                                 return null;
5534
5535                         //
5536                         // Ok, so it's a Cast.
5537                         //
5538                         if (expr.eclass == ExprClass.Type) {
5539                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5540                                 return cast.Resolve (ec);
5541                         }
5542
5543                         //
5544                         // It's a delegate invocation.
5545                         //
5546                         if (!TypeManager.IsDelegateType (expr.Type)) {
5547                                 Error (149, "Method name expected");
5548                                 return null;
5549                         }
5550
5551                         ArrayList args = new ArrayList ();
5552                         args.Add (new Argument (argument, Argument.AType.Expression));
5553                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5554                         return invocation.Resolve (ec);
5555                 }
5556
5557                 void error201 ()
5558                 {
5559                         Error (201, "Only assignment, call, increment, decrement and new object " +
5560                                "expressions can be used as a statement");
5561                 }
5562
5563                 public override ExpressionStatement ResolveStatement (EmitContext ec)
5564                 {
5565                         //
5566                         // First try to resolve it as a cast.
5567                         //
5568                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5569                         if (te != null) {
5570                                 error201 ();
5571                                 return null;
5572                         }
5573
5574                         //
5575                         // This can either be a type or a delegate invocation.
5576                         // Let's just resolve it and see what we'll get.
5577                         //
5578                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5579                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5580                                 error201 ();
5581                                 return null;
5582                         }
5583
5584                         //
5585                         // It's a delegate invocation.
5586                         //
5587                         if (!TypeManager.IsDelegateType (expr.Type)) {
5588                                 Error (149, "Method name expected");
5589                                 return null;
5590                         }
5591
5592                         ArrayList args = new ArrayList ();
5593                         args.Add (new Argument (argument, Argument.AType.Expression));
5594                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5595                         return invocation.ResolveStatement (ec);
5596                 }
5597
5598                 public override void Emit (EmitContext ec)
5599                 {
5600                         throw new Exception ("Cannot happen");
5601                 }
5602
5603                 public override void EmitStatement (EmitContext ec)
5604                 {
5605                         throw new Exception ("Cannot happen");
5606                 }
5607         }
5608
5609         //
5610         // This class is used to "disable" the code generation for the
5611         // temporary variable when initializing value types.
5612         //
5613         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5614                 public void AddressOf (EmitContext ec, AddressOp Mode)
5615                 {
5616                         // nothing
5617                 }
5618         }
5619         
5620         /// <summary>
5621         ///    Implements the new expression 
5622         /// </summary>
5623         public class New : ExpressionStatement, IMemoryLocation {
5624                 public readonly ArrayList Arguments;
5625
5626                 //
5627                 // During bootstrap, it contains the RequestedType,
5628                 // but if `type' is not null, it *might* contain a NewDelegate
5629                 // (because of field multi-initialization)
5630                 //
5631                 public Expression RequestedType;
5632
5633                 MethodBase method = null;
5634
5635                 //
5636                 // If set, the new expression is for a value_target, and
5637                 // we will not leave anything on the stack.
5638                 //
5639                 Expression value_target;
5640                 bool value_target_set = false;
5641                 
5642                 public New (Expression requested_type, ArrayList arguments, Location l)
5643                 {
5644                         RequestedType = requested_type;
5645                         Arguments = arguments;
5646                         loc = l;
5647                 }
5648
5649                 public bool SetValueTypeVariable (Expression value)
5650                 {
5651                         value_target = value;
5652                         value_target_set = true;
5653                         if (!(value_target is IMemoryLocation)){
5654                                 Error_UnexpectedKind ("variable", loc);
5655                                 return false;
5656                         }
5657                         return true;
5658                 }
5659
5660                 //
5661                 // This function is used to disable the following code sequence for
5662                 // value type initialization:
5663                 //
5664                 // AddressOf (temporary)
5665                 // Construct/Init
5666                 // LoadTemporary
5667                 //
5668                 // Instead the provide will have provided us with the address on the
5669                 // stack to store the results.
5670                 //
5671                 static Expression MyEmptyExpression;
5672                 
5673                 public void DisableTemporaryValueType ()
5674                 {
5675                         if (MyEmptyExpression == null)
5676                                 MyEmptyExpression = new EmptyAddressOf ();
5677
5678                         //
5679                         // To enable this, look into:
5680                         // test-34 and test-89 and self bootstrapping.
5681                         //
5682                         // For instance, we can avoid a copy by using `newobj'
5683                         // instead of Call + Push-temp on value types.
5684 //                      value_target = MyEmptyExpression;
5685                 }
5686
5687                 public override Expression DoResolve (EmitContext ec)
5688                 {
5689                         //
5690                         // The New DoResolve might be called twice when initializing field
5691                         // expressions (see EmitFieldInitializers, the call to
5692                         // GetInitializerExpression will perform a resolve on the expression,
5693                         // and later the assign will trigger another resolution
5694                         //
5695                         // This leads to bugs (#37014)
5696                         //
5697                         if (type != null){
5698                                 if (RequestedType is NewDelegate)
5699                                         return RequestedType;
5700                                 return this;
5701                         }
5702                         
5703                         TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5704                         if (texpr == null)
5705                                 return null;
5706
5707                         type = texpr.ResolveType (ec);
5708                         
5709                         CheckObsoleteAttribute (type);
5710
5711                         bool IsDelegate = TypeManager.IsDelegateType (type);
5712                         
5713                         if (IsDelegate){
5714                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5715                                 if (RequestedType != null)
5716                                         if (!(RequestedType is DelegateCreation))
5717                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5718                                 return RequestedType;
5719                         }
5720
5721                         if (type.IsAbstract && type.IsSealed) {
5722                                 Report.Error (712, loc, "Cannot create an instance of the static class '{0}'", TypeManager.CSharpName (type));
5723                                 return null;
5724                         }
5725
5726                         if (type.IsInterface || type.IsAbstract){
5727                                 Error (144, "It is not possible to create instances of interfaces or abstract classes");
5728                                 return null;
5729                         }
5730                         
5731                         bool is_struct = type.IsValueType;
5732                         eclass = ExprClass.Value;
5733
5734                         //
5735                         // SRE returns a match for .ctor () on structs (the object constructor), 
5736                         // so we have to manually ignore it.
5737                         //
5738                         if (is_struct && Arguments == null)
5739                                 return this;
5740                         
5741                         Expression ml;
5742                         // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5743                         ml = MemberLookupFinal (ec, type, type, ".ctor",
5744                                                 MemberTypes.Constructor,
5745                                                 AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5746
5747                         if (ml == null)
5748                                 return null;
5749                         
5750                         if (! (ml is MethodGroupExpr)){
5751                                 if (!is_struct){
5752                                         ml.Error_UnexpectedKind ("method group", loc);
5753                                         return null;
5754                                 }
5755                         }
5756
5757                         if (ml != null) {
5758                                 if (Arguments != null){
5759                                         foreach (Argument a in Arguments){
5760                                                 if (!a.Resolve (ec, loc))
5761                                                         return null;
5762                                         }
5763                                 }
5764
5765                                 method = Invocation.OverloadResolve (
5766                                         ec, (MethodGroupExpr) ml, Arguments, false, loc);
5767                                 
5768                         }
5769
5770                         if (method == null) { 
5771                                 if (!is_struct || Arguments.Count > 0) {
5772                                         Error (1501, String.Format (
5773                                             "New invocation: Can not find a constructor in `{0}' for this argument list",
5774                                             TypeManager.CSharpName (type)));
5775                                         return null;
5776                                 }
5777                         }
5778
5779                         return this;
5780                 }
5781
5782                 //
5783                 // This DoEmit can be invoked in two contexts:
5784                 //    * As a mechanism that will leave a value on the stack (new object)
5785                 //    * As one that wont (init struct)
5786                 //
5787                 // You can control whether a value is required on the stack by passing
5788                 // need_value_on_stack.  The code *might* leave a value on the stack
5789                 // so it must be popped manually
5790                 //
5791                 // If we are dealing with a ValueType, we have a few
5792                 // situations to deal with:
5793                 //
5794                 //    * The target is a ValueType, and we have been provided
5795                 //      the instance (this is easy, we are being assigned).
5796                 //
5797                 //    * The target of New is being passed as an argument,
5798                 //      to a boxing operation or a function that takes a
5799                 //      ValueType.
5800                 //
5801                 //      In this case, we need to create a temporary variable
5802                 //      that is the argument of New.
5803                 //
5804                 // Returns whether a value is left on the stack
5805                 //
5806                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5807                 {
5808                         bool is_value_type = type.IsValueType;
5809                         ILGenerator ig = ec.ig;
5810
5811                         if (is_value_type){
5812                                 IMemoryLocation ml;
5813
5814                                 // Allow DoEmit() to be called multiple times.
5815                                 // We need to create a new LocalTemporary each time since
5816                                 // you can't share LocalBuilders among ILGeneators.
5817                                 if (!value_target_set)
5818                                         value_target = new LocalTemporary (ec, type);
5819
5820                                 ml = (IMemoryLocation) value_target;
5821                                 ml.AddressOf (ec, AddressOp.Store);
5822                         }
5823
5824                         if (method != null)
5825                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
5826
5827                         if (is_value_type){
5828                                 if (method == null)
5829                                         ig.Emit (OpCodes.Initobj, type);
5830                                 else 
5831                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5832                                 if (need_value_on_stack){
5833                                         value_target.Emit (ec);
5834                                         return true;
5835                                 }
5836                                 return false;
5837                         } else {
5838                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5839                                 return true;
5840                         }
5841                 }
5842
5843                 public override void Emit (EmitContext ec)
5844                 {
5845                         DoEmit (ec, true);
5846                 }
5847                 
5848                 public override void EmitStatement (EmitContext ec)
5849                 {
5850                         if (DoEmit (ec, false))
5851                                 ec.ig.Emit (OpCodes.Pop);
5852                 }
5853
5854                 public void AddressOf (EmitContext ec, AddressOp Mode)
5855                 {
5856                         if (!type.IsValueType){
5857                                 //
5858                                 // We throw an exception.  So far, I believe we only need to support
5859                                 // value types:
5860                                 // foreach (int j in new StructType ())
5861                                 // see bug 42390
5862                                 //
5863                                 throw new Exception ("AddressOf should not be used for classes");
5864                         }
5865
5866                         if (!value_target_set)
5867                                 value_target = new LocalTemporary (ec, type);
5868                                         
5869                         IMemoryLocation ml = (IMemoryLocation) value_target;
5870                         ml.AddressOf (ec, AddressOp.Store);
5871                         if (method != null)
5872                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
5873
5874                         if (method == null)
5875                                 ec.ig.Emit (OpCodes.Initobj, type);
5876                         else 
5877                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5878                         
5879                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5880                 }
5881         }
5882
5883         /// <summary>
5884         ///   14.5.10.2: Represents an array creation expression.
5885         /// </summary>
5886         ///
5887         /// <remarks>
5888         ///   There are two possible scenarios here: one is an array creation
5889         ///   expression that specifies the dimensions and optionally the
5890         ///   initialization data and the other which does not need dimensions
5891         ///   specified but where initialization data is mandatory.
5892         /// </remarks>
5893         public class ArrayCreation : Expression {
5894                 Expression requested_base_type;
5895                 ArrayList initializers;
5896
5897                 //
5898                 // The list of Argument types.
5899                 // This is used to construct the `newarray' or constructor signature
5900                 //
5901                 ArrayList arguments;
5902
5903                 //
5904                 // Method used to create the array object.
5905                 //
5906                 MethodBase new_method = null;
5907                 
5908                 Type array_element_type;
5909                 Type underlying_type;
5910                 bool is_one_dimensional = false;
5911                 bool is_builtin_type = false;
5912                 bool expect_initializers = false;
5913                 int num_arguments = 0;
5914                 int dimensions = 0;
5915                 string rank;
5916
5917                 ArrayList array_data;
5918
5919                 Hashtable bounds;
5920
5921                 //
5922                 // The number of array initializers that we can handle
5923                 // via the InitializeArray method - through EmitStaticInitializers
5924                 //
5925                 int num_automatic_initializers;
5926
5927                 const int max_automatic_initializers = 6;
5928                 
5929                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5930                 {
5931                         this.requested_base_type = requested_base_type;
5932                         this.initializers = initializers;
5933                         this.rank = rank;
5934                         loc = l;
5935
5936                         arguments = new ArrayList ();
5937
5938                         foreach (Expression e in exprs) {
5939                                 arguments.Add (new Argument (e, Argument.AType.Expression));
5940                                 num_arguments++;
5941                         }
5942                 }
5943
5944                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5945                 {
5946                         this.requested_base_type = requested_base_type;
5947                         this.initializers = initializers;
5948                         this.rank = rank;
5949                         loc = l;
5950
5951                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5952                         //
5953                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
5954                         //
5955                         //dimensions = tmp.Length - 1;
5956                         expect_initializers = true;
5957                 }
5958
5959                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5960                 {
5961                         StringBuilder sb = new StringBuilder (rank);
5962                         
5963                         sb.Append ("[");
5964                         for (int i = 1; i < idx_count; i++)
5965                                 sb.Append (",");
5966                         
5967                         sb.Append ("]");
5968
5969                         return new ComposedCast (base_type, sb.ToString (), loc);
5970                 }
5971
5972                 void Error_IncorrectArrayInitializer ()
5973                 {
5974                         Error (178, "Incorrectly structured array initializer");
5975                 }
5976                 
5977                 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5978                 {
5979                         if (specified_dims) { 
5980                                 Argument a = (Argument) arguments [idx];
5981                                 
5982                                 if (!a.Resolve (ec, loc))
5983                                         return false;
5984                                 
5985                                 if (!(a.Expr is Constant)) {
5986                                         Error (150, "A constant value is expected");
5987                                         return false;
5988                                 }
5989                                 
5990                                 int value = (int) ((Constant) a.Expr).GetValue ();
5991                                 
5992                                 if (value != probe.Count) {
5993                                         Error_IncorrectArrayInitializer ();
5994                                         return false;
5995                                 }
5996                                 
5997                                 bounds [idx] = value;
5998                         }
5999
6000                         int child_bounds = -1;
6001                         foreach (object o in probe) {
6002                                 if (o is ArrayList) {
6003                                         int current_bounds = ((ArrayList) o).Count;
6004                                         
6005                                         if (child_bounds == -1) 
6006                                                 child_bounds = current_bounds;
6007
6008                                         else if (child_bounds != current_bounds){
6009                                                 Error_IncorrectArrayInitializer ();
6010                                                 return false;
6011                                         }
6012                                         if (specified_dims && (idx + 1 >= arguments.Count)){
6013                                                 Error (623, "Array initializers can only be used in a variable or field initializer, try using the new expression");
6014                                                 return false;
6015                                         }
6016                                         
6017                                         bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
6018                                         if (!ret)
6019                                                 return false;
6020                                 } else {
6021                                         if (child_bounds != -1){
6022                                                 Error_IncorrectArrayInitializer ();
6023                                                 return false;
6024                                         }
6025                                         
6026                                         Expression tmp = (Expression) o;
6027                                         tmp = tmp.Resolve (ec);
6028                                         if (tmp == null)
6029                                                 return false;
6030
6031                                         // Console.WriteLine ("I got: " + tmp);
6032                                         // Handle initialization from vars, fields etc.
6033
6034                                         Expression conv = Convert.ImplicitConversionRequired (
6035                                                 ec, tmp, underlying_type, loc);
6036                                         
6037                                         if (conv == null) 
6038                                                 return false;
6039                                         
6040                                         if (conv is StringConstant || conv is DecimalConstant || conv is NullCast) {
6041                                                 // These are subclasses of Constant that can appear as elements of an
6042                                                 // array that cannot be statically initialized (with num_automatic_initializers
6043                                                 // > max_automatic_initializers), so num_automatic_initializers should be left as zero.
6044                                                 array_data.Add (conv);
6045                                         } else if (conv is Constant) {
6046                                                 // These are the types of Constant that can appear in arrays that can be
6047                                                 // statically allocated.
6048                                                 array_data.Add (conv);
6049                                                 num_automatic_initializers++;
6050                                         } else
6051                                                 array_data.Add (conv);
6052                                 }
6053                         }
6054
6055                         return true;
6056                 }
6057                 
6058                 public void UpdateIndices (EmitContext ec)
6059                 {
6060                         int i = 0;
6061                         for (ArrayList probe = initializers; probe != null;) {
6062                                 if (probe.Count > 0 && probe [0] is ArrayList) {
6063                                         Expression e = new IntConstant (probe.Count);
6064                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6065
6066                                         bounds [i++] =  probe.Count;
6067                                         
6068                                         probe = (ArrayList) probe [0];
6069                                         
6070                                 } else {
6071                                         Expression e = new IntConstant (probe.Count);
6072                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6073
6074                                         bounds [i++] = probe.Count;
6075                                         probe = null;
6076                                 }
6077                         }
6078
6079                 }
6080                 
6081                 public bool ValidateInitializers (EmitContext ec, Type array_type)
6082                 {
6083                         if (initializers == null) {
6084                                 if (expect_initializers)
6085                                         return false;
6086                                 else
6087                                         return true;
6088                         }
6089                         
6090                         if (underlying_type == null)
6091                                 return false;
6092                         
6093                         //
6094                         // We use this to store all the date values in the order in which we
6095                         // will need to store them in the byte blob later
6096                         //
6097                         array_data = new ArrayList ();
6098                         bounds = new Hashtable ();
6099                         
6100                         bool ret;
6101
6102                         if (arguments != null) {
6103                                 ret = CheckIndices (ec, initializers, 0, true);
6104                                 return ret;
6105                         } else {
6106                                 arguments = new ArrayList ();
6107
6108                                 ret = CheckIndices (ec, initializers, 0, false);
6109                                 
6110                                 if (!ret)
6111                                         return false;
6112                                 
6113                                 UpdateIndices (ec);
6114                                 
6115                                 if (arguments.Count != dimensions) {
6116                                         Error_IncorrectArrayInitializer ();
6117                                         return false;
6118                                 }
6119
6120                                 return ret;
6121                         }
6122                 }
6123
6124                 //
6125                 // Converts `source' to an int, uint, long or ulong.
6126                 //
6127                 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
6128                 {
6129                         Expression target;
6130                         
6131                         bool old_checked = ec.CheckState;
6132                         ec.CheckState = true;
6133                         
6134                         target = Convert.ImplicitConversion (ec, source, TypeManager.int32_type, loc);
6135                         if (target == null){
6136                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint32_type, loc);
6137                                 if (target == null){
6138                                         target = Convert.ImplicitConversion (ec, source, TypeManager.int64_type, loc);
6139                                         if (target == null){
6140                                                 target = Convert.ImplicitConversion (ec, source, TypeManager.uint64_type, loc);
6141                                                 if (target == null)
6142                                                         Convert.Error_CannotImplicitConversion (loc, source.Type, TypeManager.int32_type);
6143                                         }
6144                                 }
6145                         } 
6146                         ec.CheckState = old_checked;
6147
6148                         //
6149                         // Only positive constants are allowed at compile time
6150                         //
6151                         if (target is Constant){
6152                                 if (target is IntConstant){
6153                                         if (((IntConstant) target).Value < 0){
6154                                                 Expression.Error_NegativeArrayIndex (loc);
6155                                                 return null;
6156                                         }
6157                                 }
6158
6159                                 if (target is LongConstant){
6160                                         if (((LongConstant) target).Value < 0){
6161                                                 Expression.Error_NegativeArrayIndex (loc);
6162                                                 return null;
6163                                         }
6164                                 }
6165                                 
6166                         }
6167
6168                         return target;
6169                 }
6170
6171                 //
6172                 // Creates the type of the array
6173                 //
6174                 bool LookupType (EmitContext ec)
6175                 {
6176                         StringBuilder array_qualifier = new StringBuilder (rank);
6177
6178                         //
6179                         // `In the first form allocates an array instace of the type that results
6180                         // from deleting each of the individual expression from the expression list'
6181                         //
6182                         if (num_arguments > 0) {
6183                                 array_qualifier.Append ("[");
6184                                 for (int i = num_arguments-1; i > 0; i--)
6185                                         array_qualifier.Append (",");
6186                                 array_qualifier.Append ("]");                           
6187                         }
6188
6189                         //
6190                         // Lookup the type
6191                         //
6192                         TypeExpr array_type_expr;
6193                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6194                         array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6195                         if (array_type_expr == null)
6196                                 return false;
6197
6198                         type = array_type_expr.ResolveType (ec);
6199                         
6200                         if (!type.IsArray) {
6201                                 Error (622, "Can only use array initializer expressions to assign to array types. Try using a new expression instead.");
6202                                 return false;
6203                         }
6204                         underlying_type = TypeManager.GetElementType (type);
6205                         dimensions = type.GetArrayRank ();
6206
6207                         return true;
6208                 }
6209                 
6210                 public override Expression DoResolve (EmitContext ec)
6211                 {
6212                         int arg_count;
6213
6214                         if (!LookupType (ec))
6215                                 return null;
6216                         
6217                         //
6218                         // First step is to validate the initializers and fill
6219                         // in any missing bits
6220                         //
6221                         if (!ValidateInitializers (ec, type))
6222                                 return null;
6223
6224                         if (arguments == null)
6225                                 arg_count = 0;
6226                         else {
6227                                 arg_count = arguments.Count;
6228                                 foreach (Argument a in arguments){
6229                                         if (!a.Resolve (ec, loc))
6230                                                 return null;
6231
6232                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6233                                         if (real_arg == null)
6234                                                 return null;
6235
6236                                         a.Expr = real_arg;
6237                                 }
6238                         }
6239                         
6240                         array_element_type = TypeManager.GetElementType (type);
6241
6242                         if (array_element_type.IsAbstract && array_element_type.IsSealed) {
6243                                 Report.Error (719, loc, "'{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
6244                                 return null;
6245                         }
6246
6247                         if (arg_count == 1) {
6248                                 is_one_dimensional = true;
6249                                 eclass = ExprClass.Value;
6250                                 return this;
6251                         }
6252
6253                         is_builtin_type = TypeManager.IsBuiltinType (type);
6254
6255                         if (is_builtin_type) {
6256                                 Expression ml;
6257                                 
6258                                 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
6259                                                    AllBindingFlags, loc);
6260                                 
6261                                 if (!(ml is MethodGroupExpr)) {
6262                                         ml.Error_UnexpectedKind ("method group", loc);
6263                                         return null;
6264                                 }
6265                                 
6266                                 if (ml == null) {
6267                                         Error (-6, "New invocation: Can not find a constructor for " +
6268                                                       "this argument list");
6269                                         return null;
6270                                 }
6271                                 
6272                                 new_method = Invocation.OverloadResolve (
6273                                         ec, (MethodGroupExpr) ml, arguments, false, loc);
6274
6275                                 if (new_method == null) {
6276                                         Error (-6, "New invocation: Can not find a constructor for " +
6277                                                       "this argument list");
6278                                         return null;
6279                                 }
6280                                 
6281                                 eclass = ExprClass.Value;
6282                                 return this;
6283                         } else {
6284                                 ModuleBuilder mb = CodeGen.Module.Builder;
6285                                 ArrayList args = new ArrayList ();
6286                                 
6287                                 if (arguments != null) {
6288                                         for (int i = 0; i < arg_count; i++)
6289                                                 args.Add (TypeManager.int32_type);
6290                                 }
6291                                 
6292                                 Type [] arg_types = null;
6293
6294                                 if (args.Count > 0)
6295                                         arg_types = new Type [args.Count];
6296                                 
6297                                 args.CopyTo (arg_types, 0);
6298                                 
6299                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6300                                                             arg_types);
6301
6302                                 if (new_method == null) {
6303                                         Error (-6, "New invocation: Can not find a constructor for " +
6304                                                       "this argument list");
6305                                         return null;
6306                                 }
6307                                 
6308                                 eclass = ExprClass.Value;
6309                                 return this;
6310                         }
6311                 }
6312
6313                 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
6314                 {
6315                         int factor;
6316                         byte [] data;
6317                         byte [] element;
6318                         int count = array_data.Count;
6319
6320                         if (underlying_type.IsEnum)
6321                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6322                         
6323                         factor = GetTypeSize (underlying_type);
6324                         if (factor == 0)
6325                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6326
6327                         data = new byte [(count * factor + 4) & ~3];
6328                         int idx = 0;
6329                         
6330                         for (int i = 0; i < count; ++i) {
6331                                 object v = array_data [i];
6332
6333                                 if (v is EnumConstant)
6334                                         v = ((EnumConstant) v).Child;
6335                                 
6336                                 if (v is Constant && !(v is StringConstant))
6337                                         v = ((Constant) v).GetValue ();
6338                                 else {
6339                                         idx += factor;
6340                                         continue;
6341                                 }
6342                                 
6343                                 if (underlying_type == TypeManager.int64_type){
6344                                         if (!(v is Expression)){
6345                                                 long val = (long) v;
6346                                                 
6347                                                 for (int j = 0; j < factor; ++j) {
6348                                                         data [idx + j] = (byte) (val & 0xFF);
6349                                                         val = (val >> 8);
6350                                                 }
6351                                         }
6352                                 } else if (underlying_type == TypeManager.uint64_type){
6353                                         if (!(v is Expression)){
6354                                                 ulong val = (ulong) v;
6355
6356                                                 for (int j = 0; j < factor; ++j) {
6357                                                         data [idx + j] = (byte) (val & 0xFF);
6358                                                         val = (val >> 8);
6359                                                 }
6360                                         }
6361                                 } else if (underlying_type == TypeManager.float_type) {
6362                                         if (!(v is Expression)){
6363                                                 element = BitConverter.GetBytes ((float) v);
6364                                                         
6365                                                 for (int j = 0; j < factor; ++j)
6366                                                         data [idx + j] = element [j];
6367                                         }
6368                                 } else if (underlying_type == TypeManager.double_type) {
6369                                         if (!(v is Expression)){
6370                                                 element = BitConverter.GetBytes ((double) v);
6371
6372                                                 for (int j = 0; j < factor; ++j)
6373                                                         data [idx + j] = element [j];
6374                                         }
6375                                 } else if (underlying_type == TypeManager.char_type){
6376                                         if (!(v is Expression)){
6377                                                 int val = (int) ((char) v);
6378                                                 
6379                                                 data [idx] = (byte) (val & 0xff);
6380                                                 data [idx+1] = (byte) (val >> 8);
6381                                         }
6382                                 } else if (underlying_type == TypeManager.short_type){
6383                                         if (!(v is Expression)){
6384                                                 int val = (int) ((short) v);
6385                                         
6386                                                 data [idx] = (byte) (val & 0xff);
6387                                                 data [idx+1] = (byte) (val >> 8);
6388                                         }
6389                                 } else if (underlying_type == TypeManager.ushort_type){
6390                                         if (!(v is Expression)){
6391                                                 int val = (int) ((ushort) v);
6392                                         
6393                                                 data [idx] = (byte) (val & 0xff);
6394                                                 data [idx+1] = (byte) (val >> 8);
6395                                         }
6396                                 } else if (underlying_type == TypeManager.int32_type) {
6397                                         if (!(v is Expression)){
6398                                                 int val = (int) v;
6399                                         
6400                                                 data [idx]   = (byte) (val & 0xff);
6401                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6402                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6403                                                 data [idx+3] = (byte) (val >> 24);
6404                                         }
6405                                 } else if (underlying_type == TypeManager.uint32_type) {
6406                                         if (!(v is Expression)){
6407                                                 uint val = (uint) v;
6408                                         
6409                                                 data [idx]   = (byte) (val & 0xff);
6410                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6411                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6412                                                 data [idx+3] = (byte) (val >> 24);
6413                                         }
6414                                 } else if (underlying_type == TypeManager.sbyte_type) {
6415                                         if (!(v is Expression)){
6416                                                 sbyte val = (sbyte) v;
6417                                                 data [idx] = (byte) val;
6418                                         }
6419                                 } else if (underlying_type == TypeManager.byte_type) {
6420                                         if (!(v is Expression)){
6421                                                 byte val = (byte) v;
6422                                                 data [idx] = (byte) val;
6423                                         }
6424                                 } else if (underlying_type == TypeManager.bool_type) {
6425                                         if (!(v is Expression)){
6426                                                 bool val = (bool) v;
6427                                                 data [idx] = (byte) (val ? 1 : 0);
6428                                         }
6429                                 } else if (underlying_type == TypeManager.decimal_type){
6430                                         if (!(v is Expression)){
6431                                                 int [] bits = Decimal.GetBits ((decimal) v);
6432                                                 int p = idx;
6433
6434                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
6435                                                 int [] nbits = new int [4];
6436                                                 nbits [0] = bits [3];
6437                                                 nbits [1] = bits [2];
6438                                                 nbits [2] = bits [0];
6439                                                 nbits [3] = bits [1];
6440                                                 
6441                                                 for (int j = 0; j < 4; j++){
6442                                                         data [p++] = (byte) (nbits [j] & 0xff);
6443                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6444                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6445                                                         data [p++] = (byte) (nbits [j] >> 24);
6446                                                 }
6447                                         }
6448                                 } else
6449                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6450
6451                                 idx += factor;
6452                         }
6453
6454                         return data;
6455                 }
6456
6457                 //
6458                 // Emits the initializers for the array
6459                 //
6460                 void EmitStaticInitializers (EmitContext ec)
6461                 {
6462                         //
6463                         // First, the static data
6464                         //
6465                         FieldBuilder fb;
6466                         ILGenerator ig = ec.ig;
6467                         
6468                         byte [] data = MakeByteBlob (array_data, underlying_type, loc);
6469
6470                         fb = RootContext.MakeStaticData (data);
6471
6472                         ig.Emit (OpCodes.Dup);
6473                         ig.Emit (OpCodes.Ldtoken, fb);
6474                         ig.Emit (OpCodes.Call,
6475                                  TypeManager.void_initializearray_array_fieldhandle);
6476                 }
6477
6478                 //
6479                 // Emits pieces of the array that can not be computed at compile
6480                 // time (variables and string locations).
6481                 //
6482                 // This always expect the top value on the stack to be the array
6483                 //
6484                 void EmitDynamicInitializers (EmitContext ec)
6485                 {
6486                         ILGenerator ig = ec.ig;
6487                         int dims = bounds.Count;
6488                         int [] current_pos = new int [dims];
6489                         int top = array_data.Count;
6490
6491                         MethodInfo set = null;
6492
6493                         if (dims != 1){
6494                                 Type [] args;
6495                                 ModuleBuilder mb = null;
6496                                 mb = CodeGen.Module.Builder;
6497                                 args = new Type [dims + 1];
6498
6499                                 int j;
6500                                 for (j = 0; j < dims; j++)
6501                                         args [j] = TypeManager.int32_type;
6502
6503                                 args [j] = array_element_type;
6504                                 
6505                                 set = mb.GetArrayMethod (
6506                                         type, "Set",
6507                                         CallingConventions.HasThis | CallingConventions.Standard,
6508                                         TypeManager.void_type, args);
6509                         }
6510                         
6511                         for (int i = 0; i < top; i++){
6512
6513                                 Expression e = null;
6514
6515                                 if (array_data [i] is Expression)
6516                                         e = (Expression) array_data [i];
6517
6518                                 if (e != null) {
6519                                         //
6520                                         // Basically we do this for string literals and
6521                                         // other non-literal expressions
6522                                         //
6523                                         if (e is EnumConstant){
6524                                                 e = ((EnumConstant) e).Child;
6525                                         }
6526                                         
6527                                         if (e is StringConstant || e is DecimalConstant || !(e is Constant) ||
6528                                             num_automatic_initializers <= max_automatic_initializers) {
6529                                                 Type etype = e.Type;
6530                                                 
6531                                                 ig.Emit (OpCodes.Dup);
6532
6533                                                 for (int idx = 0; idx < dims; idx++) 
6534                                                         IntConstant.EmitInt (ig, current_pos [idx]);
6535
6536                                                 //
6537                                                 // If we are dealing with a struct, get the
6538                                                 // address of it, so we can store it.
6539                                                 //
6540                                                 if ((dims == 1) && 
6541                                                     etype.IsSubclassOf (TypeManager.value_type) &&
6542                                                     (!TypeManager.IsBuiltinOrEnum (etype) ||
6543                                                      etype == TypeManager.decimal_type)) {
6544                                                         if (e is New){
6545                                                                 New n = (New) e;
6546
6547                                                                 //
6548                                                                 // Let new know that we are providing
6549                                                                 // the address where to store the results
6550                                                                 //
6551                                                                 n.DisableTemporaryValueType ();
6552                                                         }
6553
6554                                                         ig.Emit (OpCodes.Ldelema, etype);
6555                                                 }
6556
6557                                                 e.Emit (ec);
6558
6559                                                 if (dims == 1) {
6560                                                         bool is_stobj;
6561                                                         OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj);
6562                                                         if (is_stobj)
6563                                                                 ig.Emit (OpCodes.Stobj, etype);
6564                                                         else
6565                                                                 ig.Emit (op);
6566                                                 } else 
6567                                                         ig.Emit (OpCodes.Call, set);
6568
6569                                         }
6570                                 }
6571                                 
6572                                 //
6573                                 // Advance counter
6574                                 //
6575                                 for (int j = dims - 1; j >= 0; j--){
6576                                         current_pos [j]++;
6577                                         if (current_pos [j] < (int) bounds [j])
6578                                                 break;
6579                                         current_pos [j] = 0;
6580                                 }
6581                         }
6582                 }
6583
6584                 void EmitArrayArguments (EmitContext ec)
6585                 {
6586                         ILGenerator ig = ec.ig;
6587                         
6588                         foreach (Argument a in arguments) {
6589                                 Type atype = a.Type;
6590                                 a.Emit (ec);
6591
6592                                 if (atype == TypeManager.uint64_type)
6593                                         ig.Emit (OpCodes.Conv_Ovf_U4);
6594                                 else if (atype == TypeManager.int64_type)
6595                                         ig.Emit (OpCodes.Conv_Ovf_I4);
6596                         }
6597                 }
6598                 
6599                 public override void Emit (EmitContext ec)
6600                 {
6601                         ILGenerator ig = ec.ig;
6602                         
6603                         EmitArrayArguments (ec);
6604                         if (is_one_dimensional)
6605                                 ig.Emit (OpCodes.Newarr, array_element_type);
6606                         else {
6607                                 if (is_builtin_type) 
6608                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6609                                 else 
6610                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6611                         }
6612                         
6613                         if (initializers != null){
6614                                 //
6615                                 // FIXME: Set this variable correctly.
6616                                 // 
6617                                 bool dynamic_initializers = true;
6618
6619                                 // This will never be true for array types that cannot be statically
6620                                 // initialized. num_automatic_initializers will always be zero.  See
6621                                 // CheckIndices.
6622                                 if (num_automatic_initializers > max_automatic_initializers)
6623                                         EmitStaticInitializers (ec);
6624                                 
6625                                 if (dynamic_initializers)
6626                                         EmitDynamicInitializers (ec);
6627                         }
6628                 }
6629
6630                 public object EncodeAsAttribute ()
6631                 {
6632                         if (!is_one_dimensional){
6633                                 Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6634                                 return null;
6635                         }
6636
6637                         if (array_data == null){
6638                                 Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6639                                 return null;
6640                         }
6641                         
6642                         object [] ret = new object [array_data.Count];
6643                         int i = 0;
6644                         foreach (Expression e in array_data){
6645                                 object v;
6646                                 
6647                                 if (e is NullLiteral)
6648                                         v = null;
6649                                 else {
6650                                         if (!Attribute.GetAttributeArgumentExpression (e, Location, array_element_type, out v))
6651                                                 return null;
6652                                 }
6653                                 ret [i++] = v;
6654                         }
6655                         return ret;
6656                 }
6657         }
6658         
6659         /// <summary>
6660         ///   Represents the `this' construct
6661         /// </summary>
6662         public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
6663
6664                 Block block;
6665                 VariableInfo variable_info;
6666                 
6667                 public This (Block block, Location loc)
6668                 {
6669                         this.loc = loc;
6670                         this.block = block;
6671                 }
6672
6673                 public This (Location loc)
6674                 {
6675                         this.loc = loc;
6676                 }
6677
6678                 public VariableInfo VariableInfo {
6679                         get { return variable_info; }
6680                 }
6681
6682                 public bool VerifyFixed (bool is_expression)
6683                 {
6684                         if ((variable_info == null) || (variable_info.LocalInfo == null))
6685                                 return false;
6686                         else
6687                                 return variable_info.LocalInfo.IsFixed;
6688                 }
6689
6690                 public bool ResolveBase (EmitContext ec)
6691                 {
6692                         eclass = ExprClass.Variable;
6693                         type = ec.ContainerType;
6694
6695                         if (ec.IsStatic) {
6696                                 Error (26, "Keyword this not valid in static code");
6697                                 return false;
6698                         }
6699
6700                         if ((block != null) && (block.ThisVariable != null))
6701                                 variable_info = block.ThisVariable.VariableInfo;
6702
6703                         return true;
6704                 }
6705
6706                 public override Expression DoResolve (EmitContext ec)
6707                 {
6708                         if (!ResolveBase (ec))
6709                                 return null;
6710
6711                         if ((variable_info != null) && !variable_info.IsAssigned (ec)) {
6712                                 Error (188, "The this object cannot be used before all " +
6713                                        "of its fields are assigned to");
6714                                 variable_info.SetAssigned (ec);
6715                                 return this;
6716                         }
6717
6718                         if (ec.IsFieldInitializer) {
6719                                 Error (27, "Keyword `this' can't be used outside a constructor, " +
6720                                        "a method or a property.");
6721                                 return null;
6722                         }
6723
6724                         return this;
6725                 }
6726
6727                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6728                 {
6729                         if (!ResolveBase (ec))
6730                                 return null;
6731
6732                         if (variable_info != null)
6733                                 variable_info.SetAssigned (ec);
6734                         
6735                         if (ec.TypeContainer is Class){
6736                                 Error (1604, "Cannot assign to `this'");
6737                                 return null;
6738                         }
6739
6740                         return this;
6741                 }
6742
6743                 public void Emit (EmitContext ec, bool leave_copy)
6744                 {
6745                         Emit (ec);
6746                         if (leave_copy)
6747                                 ec.ig.Emit (OpCodes.Dup);
6748                 }
6749                 
6750                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
6751                 {
6752                         ILGenerator ig = ec.ig;
6753                         
6754                         if (ec.TypeContainer is Struct){
6755                                 ec.EmitThis ();
6756                                 source.Emit (ec);
6757                                 if (leave_copy)
6758                                         ec.ig.Emit (OpCodes.Dup);
6759                                 ig.Emit (OpCodes.Stobj, type);
6760                         } else {
6761                                 throw new Exception ("how did you get here");
6762                         }
6763                 }
6764                 
6765                 public override void Emit (EmitContext ec)
6766                 {
6767                         ILGenerator ig = ec.ig;
6768
6769                         ec.EmitThis ();
6770                         if (ec.TypeContainer is Struct)
6771                                 ig.Emit (OpCodes.Ldobj, type);
6772                 }
6773
6774                 public void AddressOf (EmitContext ec, AddressOp mode)
6775                 {
6776                         ec.EmitThis ();
6777
6778                         // FIMXE
6779                         // FIGURE OUT WHY LDARG_S does not work
6780                         //
6781                         // consider: struct X { int val; int P { set { val = value; }}}
6782                         //
6783                         // Yes, this looks very bad. Look at `NOTAS' for
6784                         // an explanation.
6785                         // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6786                 }
6787         }
6788
6789         /// <summary>
6790         ///   Represents the `__arglist' construct
6791         /// </summary>
6792         public class ArglistAccess : Expression
6793         {
6794                 public ArglistAccess (Location loc)
6795                 {
6796                         this.loc = loc;
6797                 }
6798
6799                 public bool ResolveBase (EmitContext ec)
6800                 {
6801                         eclass = ExprClass.Variable;
6802                         type = TypeManager.runtime_argument_handle_type;
6803                         return true;
6804                 }
6805
6806                 public override Expression DoResolve (EmitContext ec)
6807                 {
6808                         if (!ResolveBase (ec))
6809                                 return null;
6810
6811                         if (ec.IsFieldInitializer || !ec.CurrentBlock.HasVarargs) {
6812                                 Error (190, "The __arglist construct is valid only within " +
6813                                        "a variable argument method.");
6814                                 return null;
6815                         }
6816
6817                         return this;
6818                 }
6819
6820                 public override void Emit (EmitContext ec)
6821                 {
6822                         ec.ig.Emit (OpCodes.Arglist);
6823                 }
6824         }
6825
6826         /// <summary>
6827         ///   Represents the `__arglist (....)' construct
6828         /// </summary>
6829         public class Arglist : Expression
6830         {
6831                 public readonly Argument[] Arguments;
6832
6833                 public Arglist (Argument[] args, Location l)
6834                 {
6835                         Arguments = args;
6836                         loc = l;
6837                 }
6838
6839                 public Type[] ArgumentTypes {
6840                         get {
6841                                 Type[] retval = new Type [Arguments.Length];
6842                                 for (int i = 0; i < Arguments.Length; i++)
6843                                         retval [i] = Arguments [i].Type;
6844                                 return retval;
6845                         }
6846                 }
6847
6848                 public override Expression DoResolve (EmitContext ec)
6849                 {
6850                         eclass = ExprClass.Variable;
6851                         type = TypeManager.runtime_argument_handle_type;
6852
6853                         foreach (Argument arg in Arguments) {
6854                                 if (!arg.Resolve (ec, loc))
6855                                         return null;
6856                         }
6857
6858                         return this;
6859                 }
6860
6861                 public override void Emit (EmitContext ec)
6862                 {
6863                         foreach (Argument arg in Arguments)
6864                                 arg.Emit (ec);
6865                 }
6866         }
6867
6868         //
6869         // This produces the value that renders an instance, used by the iterators code
6870         //
6871         public class ProxyInstance : Expression, IMemoryLocation  {
6872                 public override Expression DoResolve (EmitContext ec)
6873                 {
6874                         eclass = ExprClass.Variable;
6875                         type = ec.ContainerType;
6876                         return this;
6877                 }
6878                 
6879                 public override void Emit (EmitContext ec)
6880                 {
6881                         ec.ig.Emit (OpCodes.Ldarg_0);
6882
6883                 }
6884                 
6885                 public void AddressOf (EmitContext ec, AddressOp mode)
6886                 {
6887                         ec.ig.Emit (OpCodes.Ldarg_0);
6888                 }
6889         }
6890
6891         /// <summary>
6892         ///   Implements the typeof operator
6893         /// </summary>
6894         public class TypeOf : Expression {
6895                 public Expression QueriedType;
6896                 protected Type typearg;
6897                 
6898                 public TypeOf (Expression queried_type, Location l)
6899                 {
6900                         QueriedType = queried_type;
6901                         loc = l;
6902                 }
6903
6904                 public override Expression DoResolve (EmitContext ec)
6905                 {
6906                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6907                         if (texpr == null)
6908                                 return null;
6909
6910                         typearg = texpr.ResolveType (ec);
6911
6912                         if (typearg == TypeManager.void_type) {
6913                                 Error (673, "System.Void cannot be used from C# - " +
6914                                        "use typeof (void) to get the void type object");
6915                                 return null;
6916                         }
6917
6918                         if (typearg.IsPointer && !ec.InUnsafe){
6919                                 UnsafeError (loc);
6920                                 return null;
6921                         }
6922                         CheckObsoleteAttribute (typearg);
6923
6924                         type = TypeManager.type_type;
6925                         eclass = ExprClass.Type;
6926                         return this;
6927                 }
6928
6929                 public override void Emit (EmitContext ec)
6930                 {
6931                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
6932                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6933                 }
6934
6935                 public Type TypeArg { 
6936                         get { return typearg; }
6937                 }
6938         }
6939
6940         /// <summary>
6941         ///   Implements the `typeof (void)' operator
6942         /// </summary>
6943         public class TypeOfVoid : TypeOf {
6944                 public TypeOfVoid (Location l) : base (null, l)
6945                 {
6946                         loc = l;
6947                 }
6948
6949                 public override Expression DoResolve (EmitContext ec)
6950                 {
6951                         type = TypeManager.type_type;
6952                         typearg = TypeManager.void_type;
6953                         eclass = ExprClass.Type;
6954                         return this;
6955                 }
6956         }
6957
6958         /// <summary>
6959         ///   Implements the sizeof expression
6960         /// </summary>
6961         public class SizeOf : Expression {
6962                 public Expression QueriedType;
6963                 Type type_queried;
6964                 
6965                 public SizeOf (Expression queried_type, Location l)
6966                 {
6967                         this.QueriedType = queried_type;
6968                         loc = l;
6969                 }
6970
6971                 public override Expression DoResolve (EmitContext ec)
6972                 {
6973                         if (!ec.InUnsafe) {
6974                                 Report.Error (
6975                                         233, loc, "Sizeof may only be used in an unsafe context " +
6976                                         "(consider using System.Runtime.InteropServices.Marshal.SizeOf");
6977                                 return null;
6978                         }
6979
6980                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6981                         if (texpr == null)
6982                                 return null;
6983
6984                         type_queried = texpr.ResolveType (ec);
6985
6986                         CheckObsoleteAttribute (type_queried);
6987
6988                         if (!TypeManager.IsUnmanagedType (type_queried)){
6989                                 Report.Error (208, loc, "Cannot take the size of an unmanaged type (" + TypeManager.CSharpName (type_queried) + ")");
6990                                 return null;
6991                         }
6992                         
6993                         type = TypeManager.int32_type;
6994                         eclass = ExprClass.Value;
6995                         return this;
6996                 }
6997
6998                 public override void Emit (EmitContext ec)
6999                 {
7000                         int size = GetTypeSize (type_queried);
7001
7002                         if (size == 0)
7003                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7004                         else
7005                                 IntConstant.EmitInt (ec.ig, size);
7006                 }
7007         }
7008
7009         /// <summary>
7010         ///   Implements the member access expression
7011         /// </summary>
7012         public class MemberAccess : Expression {
7013                 public readonly string Identifier;
7014                 Expression expr;
7015                 
7016                 public MemberAccess (Expression expr, string id, Location l)
7017                 {
7018                         this.expr = expr;
7019                         Identifier = id;
7020                         loc = l;
7021                 }
7022
7023                 public Expression Expr {
7024                         get {
7025                                 return expr;
7026                         }
7027                 }
7028
7029                 public static void error176 (Location loc, string name)
7030                 {
7031                         Report.Error (176, loc, "Static member `" +
7032                                       name + "' cannot be accessed " +
7033                                       "with an instance reference, qualify with a " +
7034                                       "type name instead");
7035                 }
7036
7037                 public static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Expression left, Location loc)
7038                 {
7039                         SimpleName sn = left_original as SimpleName;
7040                         if (sn == null || left == null || left.Type.Name != sn.Name)
7041                                 return false;
7042
7043                         return RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc) != null;
7044                 }
7045                 
7046                 // TODO: possible optimalization
7047                 // Cache resolved constant result in FieldBuilder <-> expresion map
7048                 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
7049                                                               Expression left, Location loc,
7050                                                               Expression left_original)
7051                 {
7052                         bool left_is_type, left_is_explicit;
7053
7054                         // If `left' is null, then we're called from SimpleNameResolve and this is
7055                         // a member in the currently defining class.
7056                         if (left == null) {
7057                                 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
7058                                 left_is_explicit = false;
7059
7060                                 // Implicitly default to `this' unless we're static.
7061                                 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
7062                                         left = ec.GetThis (loc);
7063                         } else {
7064                                 left_is_type = left is TypeExpr;
7065                                 left_is_explicit = true;
7066                         }
7067
7068                         if (member_lookup is FieldExpr){
7069                                 FieldExpr fe = (FieldExpr) member_lookup;
7070                                 FieldInfo fi = fe.FieldInfo;
7071                                 Type decl_type = fi.DeclaringType;
7072
7073                                 bool is_emitted = fi is FieldBuilder;
7074                                 Type t = fi.FieldType;
7075
7076                                 if (is_emitted) {
7077                                         Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
7078                                         
7079                                         if (c != null) {
7080                                                 object o;
7081                                                 if (!c.LookupConstantValue (out o))
7082                                                         return null;
7083
7084                                                 object real_value = ((Constant) c.Expr).GetValue ();
7085
7086                                                 return Constantify (real_value, t);
7087                                         }
7088                                 }
7089
7090                                 // IsInitOnly is because of MS compatibility, I don't know why but they emit decimal constant as InitOnly
7091                                 if (fi.IsInitOnly && !is_emitted && t == TypeManager.decimal_type) {
7092                                         object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
7093                                         if (attrs.Length == 1)
7094                                                 return new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
7095                                 }
7096
7097                                 if (fi.IsLiteral) {
7098                                         object o;
7099
7100                                         if (is_emitted)
7101                                                 o = TypeManager.GetValue ((FieldBuilder) fi);
7102                                         else
7103                                                 o = fi.GetValue (fi);
7104                                         
7105                                         if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
7106                                                 if (left_is_explicit && !left_is_type &&
7107                                                     !IdenticalNameAndTypeName (ec, left_original, member_lookup, loc)) {
7108                                                         error176 (loc, fe.FieldInfo.Name);
7109                                                         return null;
7110                                                 }                                       
7111                                                 
7112                                                 Expression enum_member = MemberLookup (
7113                                                         ec, decl_type, "value__", MemberTypes.Field,
7114                                                         AllBindingFlags, loc); 
7115
7116                                                 Enum en = TypeManager.LookupEnum (decl_type);
7117
7118                                                 Constant c;
7119                                                 if (en != null)
7120                                                         c = Constantify (o, en.UnderlyingType);
7121                                                 else 
7122                                                         c = Constantify (o, enum_member.Type);
7123                                                 
7124                                                 return new EnumConstant (c, decl_type);
7125                                         }
7126                                         
7127                                         Expression exp = Constantify (o, t);
7128
7129                                         if (left_is_explicit && !left_is_type) {
7130                                                 error176 (loc, fe.FieldInfo.Name);
7131                                                 return null;
7132                                         }
7133                                         
7134                                         return exp;
7135                                 }
7136
7137                                 if (t.IsPointer && !ec.InUnsafe){
7138                                         UnsafeError (loc);
7139                                         return null;
7140                                 }
7141                         }
7142
7143                         if (member_lookup is EventExpr) {
7144                                 EventExpr ee = (EventExpr) member_lookup;
7145                                 
7146                                 //
7147                                 // If the event is local to this class, we transform ourselves into
7148                                 // a FieldExpr
7149                                 //
7150
7151                                 if (ee.EventInfo.DeclaringType == ec.ContainerType ||
7152                                     TypeManager.IsNestedChildOf(ec.ContainerType, ee.EventInfo.DeclaringType)) {
7153                                         MemberInfo mi = GetFieldFromEvent (ee);
7154
7155                                         if (mi == null) {
7156                                                 //
7157                                                 // If this happens, then we have an event with its own
7158                                                 // accessors and private field etc so there's no need
7159                                                 // to transform ourselves.
7160                                                 //
7161                                                 ee.InstanceExpression = left;
7162                                                 return ee;
7163                                         }
7164
7165                                         Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
7166                                         
7167                                         if (ml == null) {
7168                                                 Report.Error (-200, loc, "Internal error!!");
7169                                                 return null;
7170                                         }
7171
7172                                         if (!left_is_explicit)
7173                                                 left = null;
7174
7175                                         ee.InstanceExpression = left;
7176
7177                                         return ResolveMemberAccess (ec, ml, left, loc, left_original);
7178                                 }
7179                         }
7180
7181                         if (member_lookup is IMemberExpr) {
7182                                 IMemberExpr me = (IMemberExpr) member_lookup;
7183                                 MethodGroupExpr mg = me as MethodGroupExpr;
7184
7185                                 if (left_is_type){
7186                                         if ((mg != null) && left_is_explicit && left.Type.IsInterface)
7187                                                 mg.IsExplicitImpl = left_is_explicit;
7188
7189                                         if (!me.IsStatic){
7190                                                 if ((ec.IsFieldInitializer || ec.IsStatic) &&
7191                                                     IdenticalNameAndTypeName (ec, left_original, member_lookup, loc))
7192                                                         return member_lookup;
7193                                                 
7194                                                 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
7195                                                 return null;
7196                                         }
7197
7198                                 } else {
7199                                         if (!me.IsInstance) {
7200                                                 if (IdenticalNameAndTypeName (ec, left_original, left, loc))
7201                                                         return member_lookup;
7202
7203                                                 if (left_is_explicit) {
7204                                                         error176 (loc, me.Name);
7205                                                         return null;
7206                                                 }
7207                                         }                       
7208
7209                                         //
7210                                         // Since we can not check for instance objects in SimpleName,
7211                                         // becaue of the rule that allows types and variables to share
7212                                         // the name (as long as they can be de-ambiguated later, see 
7213                                         // IdenticalNameAndTypeName), we have to check whether left 
7214                                         // is an instance variable in a static context
7215                                         //
7216                                         // However, if the left-hand value is explicitly given, then
7217                                         // it is already our instance expression, so we aren't in
7218                                         // static context.
7219                                         //
7220
7221                                         if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
7222                                                 IMemberExpr mexp = (IMemberExpr) left;
7223
7224                                                 if (!mexp.IsStatic){
7225                                                         SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
7226                                                         return null;
7227                                                 }
7228                                         }
7229
7230                                         if ((mg != null) && IdenticalNameAndTypeName (ec, left_original, left, loc))
7231                                                 mg.IdenticalTypeName = true;
7232
7233                                         me.InstanceExpression = left;
7234                                 }
7235
7236                                 return member_lookup;
7237                         }
7238
7239                         Console.WriteLine ("Left is: " + left);
7240                         Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
7241                         Environment.Exit (1);
7242                         return null;
7243                 }
7244                 
7245                 public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
7246                 {
7247                         if (type != null)
7248                                 throw new Exception ();
7249
7250                         //
7251                         // Resolve the expression with flow analysis turned off, we'll do the definite
7252                         // assignment checks later.  This is because we don't know yet what the expression
7253                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7254                         // definite assignment check on the actual field and not on the whole struct.
7255                         //
7256
7257                         Expression original = expr;
7258                         expr = expr.Resolve (ec, flags | ResolveFlags.Intermediate | ResolveFlags.DisableFlowAnalysis);
7259                         if (expr == null)
7260                                 return null;
7261
7262                         if (expr is SimpleName){
7263                                 SimpleName child_expr = (SimpleName) expr;
7264
7265                                 Expression new_expr = new SimpleName (child_expr.Name, Identifier, loc);
7266
7267                                 return new_expr.Resolve (ec, flags);
7268                         }
7269                                         
7270                         //
7271                         // TODO: I mailed Ravi about this, and apparently we can get rid
7272                         // of this and put it in the right place.
7273                         // 
7274                         // Handle enums here when they are in transit.
7275                         // Note that we cannot afford to hit MemberLookup in this case because
7276                         // it will fail to find any members at all
7277                         //
7278
7279                         Type expr_type = expr.Type;
7280                         if (expr is TypeExpr){
7281                                 if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
7282                                         Report.Error (122, loc, "'{0}' is inaccessible due to its protection level", expr_type);
7283                                         return null;
7284                                 }
7285
7286                                 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
7287                                         Enum en = TypeManager.LookupEnum (expr_type);
7288
7289                                         if (en != null) {
7290                                                 object value = en.LookupEnumValue (ec, Identifier, loc);
7291                                                 
7292                                                 if (value != null){
7293                                                         MemberCore mc = en.GetDefinition (Identifier);
7294                                                         ObsoleteAttribute oa = mc.GetObsoleteAttribute (en);
7295                                                         if (oa != null) {
7296                                                                 AttributeTester.Report_ObsoleteMessage (oa, mc.GetSignatureForError (), Location);
7297                                                         }
7298                                                         oa = en.GetObsoleteAttribute (en);
7299                                                         if (oa != null) {
7300                                                                 AttributeTester.Report_ObsoleteMessage (oa, en.GetSignatureForError (), Location);
7301                                                         }
7302
7303                                                         Constant c = Constantify (value, en.UnderlyingType);
7304                                                         return new EnumConstant (c, expr_type);
7305                                                 }
7306                                         } else {
7307                                                 CheckObsoleteAttribute (expr_type);
7308
7309                                                 FieldInfo fi = expr_type.GetField (Identifier);
7310                                                 if (fi != null) {
7311                                                         ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (fi);
7312                                                         if (oa != null)
7313                                                                 AttributeTester.Report_ObsoleteMessage (oa, TypeManager.GetFullNameSignature (fi), Location);
7314                                                 }
7315                                         }
7316                                 }
7317                         }
7318                         
7319                         if (expr_type.IsPointer){
7320                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7321                                        TypeManager.CSharpName (expr_type) + ")");
7322                                 return null;
7323                         }
7324
7325                         Expression member_lookup;
7326                         member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
7327                         if (member_lookup == null)
7328                                 return null;
7329
7330                         if (member_lookup is TypeExpr) {
7331                                 if (!(expr is TypeExpr) && !(expr is SimpleName)) {
7332                                         Error (572, "Can't reference type `" + Identifier + "' through an expression; try `" +
7333                                                member_lookup.Type + "' instead");
7334                                         return null;
7335                                 }
7336
7337                                 return member_lookup;
7338                         }
7339                         
7340                         member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
7341                         if (member_lookup == null)
7342                                 return null;
7343
7344                         // The following DoResolve/DoResolveLValue will do the definite assignment
7345                         // check.
7346
7347                         if (right_side != null)
7348                                 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
7349                         else
7350                                 member_lookup = member_lookup.DoResolve (ec);
7351
7352                         return member_lookup;
7353                 }
7354
7355                 public override Expression DoResolve (EmitContext ec)
7356                 {
7357                         return DoResolve (ec, null, ResolveFlags.VariableOrValue |
7358                                           ResolveFlags.SimpleName | ResolveFlags.Type);
7359                 }
7360
7361                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7362                 {
7363                         return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
7364                                           ResolveFlags.SimpleName | ResolveFlags.Type);
7365                 }
7366
7367                 public override Expression ResolveAsTypeStep (EmitContext ec)
7368                 {
7369                         string fname = null;
7370                         MemberAccess full_expr = this;
7371                         while (full_expr != null) {
7372                                 if (fname != null)
7373                                         fname = String.Concat (full_expr.Identifier, ".", fname);
7374                                 else
7375                                         fname = full_expr.Identifier;
7376
7377                                 if (full_expr.Expr is SimpleName) {
7378                                         string full_name = String.Concat (((SimpleName) full_expr.Expr).Name, ".", fname);
7379                                         Type fully_qualified = ec.DeclSpace.FindType (loc, full_name);
7380                                         if (fully_qualified != null)
7381                                                 return new TypeExpression (fully_qualified, loc);
7382                                 }
7383
7384                                 full_expr = full_expr.Expr as MemberAccess;
7385                         }
7386
7387                         Expression new_expr = expr.ResolveAsTypeStep (ec);
7388
7389                         if (new_expr == null)
7390                                 return null;
7391
7392                         if (new_expr is SimpleName){
7393                                 SimpleName child_expr = (SimpleName) new_expr;
7394                                 
7395                                 new_expr = new SimpleName (child_expr.Name, Identifier, loc);
7396
7397                                 return new_expr.ResolveAsTypeStep (ec);
7398                         }
7399
7400                         Type expr_type = new_expr.Type;
7401                       
7402                         if (expr_type.IsPointer){
7403                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7404                                        TypeManager.CSharpName (expr_type) + ")");
7405                                 return null;
7406                         }
7407                         
7408                         Expression member_lookup;
7409                         member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
7410                         if (member_lookup == null)
7411                                 return null;
7412
7413                         if (member_lookup is TypeExpr){
7414                                 member_lookup.Resolve (ec, ResolveFlags.Type);
7415                                 return member_lookup;
7416                         } 
7417
7418                         return null;                    
7419                 }
7420
7421                 public override void Emit (EmitContext ec)
7422                 {
7423                         throw new Exception ("Should not happen");
7424                 }
7425
7426                 public override string ToString ()
7427                 {
7428                         return expr + "." + Identifier;
7429                 }
7430         }
7431
7432         /// <summary>
7433         ///   Implements checked expressions
7434         /// </summary>
7435         public class CheckedExpr : Expression {
7436
7437                 public Expression Expr;
7438
7439                 public CheckedExpr (Expression e, Location l)
7440                 {
7441                         Expr = e;
7442                         loc = l;
7443                 }
7444
7445                 public override Expression DoResolve (EmitContext ec)
7446                 {
7447                         bool last_check = ec.CheckState;
7448                         bool last_const_check = ec.ConstantCheckState;
7449
7450                         ec.CheckState = true;
7451                         ec.ConstantCheckState = true;
7452                         Expr = Expr.Resolve (ec);
7453                         ec.CheckState = last_check;
7454                         ec.ConstantCheckState = last_const_check;
7455                         
7456                         if (Expr == null)
7457                                 return null;
7458
7459                         if (Expr is Constant)
7460                                 return Expr;
7461                         
7462                         eclass = Expr.eclass;
7463                         type = Expr.Type;
7464                         return this;
7465                 }
7466
7467                 public override void Emit (EmitContext ec)
7468                 {
7469                         bool last_check = ec.CheckState;
7470                         bool last_const_check = ec.ConstantCheckState;
7471                         
7472                         ec.CheckState = true;
7473                         ec.ConstantCheckState = true;
7474                         Expr.Emit (ec);
7475                         ec.CheckState = last_check;
7476                         ec.ConstantCheckState = last_const_check;
7477                 }
7478                 
7479         }
7480
7481         /// <summary>
7482         ///   Implements the unchecked expression
7483         /// </summary>
7484         public class UnCheckedExpr : Expression {
7485
7486                 public Expression Expr;
7487
7488                 public UnCheckedExpr (Expression e, Location l)
7489                 {
7490                         Expr = e;
7491                         loc = l;
7492                 }
7493
7494                 public override Expression DoResolve (EmitContext ec)
7495                 {
7496                         bool last_check = ec.CheckState;
7497                         bool last_const_check = ec.ConstantCheckState;
7498
7499                         ec.CheckState = false;
7500                         ec.ConstantCheckState = false;
7501                         Expr = Expr.Resolve (ec);
7502                         ec.CheckState = last_check;
7503                         ec.ConstantCheckState = last_const_check;
7504
7505                         if (Expr == null)
7506                                 return null;
7507
7508                         if (Expr is Constant)
7509                                 return Expr;
7510                         
7511                         eclass = Expr.eclass;
7512                         type = Expr.Type;
7513                         return this;
7514                 }
7515
7516                 public override void Emit (EmitContext ec)
7517                 {
7518                         bool last_check = ec.CheckState;
7519                         bool last_const_check = ec.ConstantCheckState;
7520                         
7521                         ec.CheckState = false;
7522                         ec.ConstantCheckState = false;
7523                         Expr.Emit (ec);
7524                         ec.CheckState = last_check;
7525                         ec.ConstantCheckState = last_const_check;
7526                 }
7527                 
7528         }
7529
7530         /// <summary>
7531         ///   An Element Access expression.
7532         ///
7533         ///   During semantic analysis these are transformed into 
7534         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7535         /// </summary>
7536         public class ElementAccess : Expression {
7537                 public ArrayList  Arguments;
7538                 public Expression Expr;
7539                 
7540                 public ElementAccess (Expression e, ArrayList e_list, Location l)
7541                 {
7542                         Expr = e;
7543
7544                         loc  = l;
7545                         
7546                         if (e_list == null)
7547                                 return;
7548                         
7549                         Arguments = new ArrayList ();
7550                         foreach (Expression tmp in e_list)
7551                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7552                         
7553                 }
7554
7555                 bool CommonResolve (EmitContext ec)
7556                 {
7557                         Expr = Expr.Resolve (ec);
7558
7559                         if (Expr == null) 
7560                                 return false;
7561
7562                         if (Arguments == null)
7563                                 return false;
7564
7565                         foreach (Argument a in Arguments){
7566                                 if (!a.Resolve (ec, loc))
7567                                         return false;
7568                         }
7569
7570                         return true;
7571                 }
7572
7573                 Expression MakePointerAccess (EmitContext ec)
7574                 {
7575                         Type t = Expr.Type;
7576
7577                         if (t == TypeManager.void_ptr_type){
7578                                 Error (242, "The array index operation is not valid for void pointers");
7579                                 return null;
7580                         }
7581                         if (Arguments.Count != 1){
7582                                 Error (196, "A pointer must be indexed by a single value");
7583                                 return null;
7584                         }
7585                         Expression p;
7586
7587                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7588                         if (p == null)
7589                                 return null;
7590                         return new Indirection (p, loc).Resolve (ec);
7591                 }
7592                 
7593                 public override Expression DoResolve (EmitContext ec)
7594                 {
7595                         if (!CommonResolve (ec))
7596                                 return null;
7597
7598                         //
7599                         // We perform some simple tests, and then to "split" the emit and store
7600                         // code we create an instance of a different class, and return that.
7601                         //
7602                         // I am experimenting with this pattern.
7603                         //
7604                         Type t = Expr.Type;
7605
7606                         if (t == TypeManager.array_type){
7607                                 Report.Error (21, loc, "Cannot use indexer on System.Array");
7608                                 return null;
7609                         }
7610                         
7611                         if (t.IsArray)
7612                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7613                         else if (t.IsPointer)
7614                                 return MakePointerAccess (ec);
7615                         else
7616                                 return (new IndexerAccess (this, loc)).Resolve (ec);
7617                 }
7618
7619                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7620                 {
7621                         if (!CommonResolve (ec))
7622                                 return null;
7623
7624                         Type t = Expr.Type;
7625                         if (t.IsArray)
7626                                 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
7627                         else if (t.IsPointer)
7628                                 return MakePointerAccess (ec);
7629                         else
7630                                 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
7631                 }
7632                 
7633                 public override void Emit (EmitContext ec)
7634                 {
7635                         throw new Exception ("Should never be reached");
7636                 }
7637         }
7638
7639         /// <summary>
7640         ///   Implements array access 
7641         /// </summary>
7642         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7643                 //
7644                 // Points to our "data" repository
7645                 //
7646                 ElementAccess ea;
7647
7648                 LocalTemporary temp;
7649                 bool prepared;
7650                 
7651                 public ArrayAccess (ElementAccess ea_data, Location l)
7652                 {
7653                         ea = ea_data;
7654                         eclass = ExprClass.Variable;
7655                         loc = l;
7656                 }
7657
7658                 public override Expression DoResolve (EmitContext ec)
7659                 {
7660 #if false
7661                         ExprClass eclass = ea.Expr.eclass;
7662
7663                         // As long as the type is valid
7664                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7665                               eclass == ExprClass.Value)) {
7666                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7667                                 return null;
7668                         }
7669 #endif
7670
7671                         Type t = ea.Expr.Type;
7672                         if (t.GetArrayRank () != ea.Arguments.Count){
7673                                 ea.Error (22,
7674                                           "Incorrect number of indexes for array " +
7675                                           " expected: " + t.GetArrayRank () + " got: " +
7676                                           ea.Arguments.Count);
7677                                 return null;
7678                         }
7679
7680                         type = TypeManager.GetElementType (t);
7681                         if (type.IsPointer && !ec.InUnsafe){
7682                                 UnsafeError (ea.Location);
7683                                 return null;
7684                         }
7685
7686                         foreach (Argument a in ea.Arguments){
7687                                 Type argtype = a.Type;
7688
7689                                 if (argtype == TypeManager.int32_type ||
7690                                     argtype == TypeManager.uint32_type ||
7691                                     argtype == TypeManager.int64_type ||
7692                                     argtype == TypeManager.uint64_type) {
7693                                         Constant c = a.Expr as Constant;
7694                                         if (c != null && c.IsNegative) {
7695                                                 Report.Warning (251, 2, a.Expr.Location, "Indexing an array with a negative index (array indices always start at zero)");
7696                                         }
7697                                         continue;
7698                                 }
7699
7700                                 //
7701                                 // Mhm.  This is strage, because the Argument.Type is not the same as
7702                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7703                                 //
7704                                 // Wonder if I will run into trouble for this.
7705                                 //
7706                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7707                                 if (a.Expr == null)
7708                                         return null;
7709                         }
7710                         
7711                         eclass = ExprClass.Variable;
7712
7713                         return this;
7714                 }
7715
7716                 /// <summary>
7717                 ///    Emits the right opcode to load an object of Type `t'
7718                 ///    from an array of T
7719                 /// </summary>
7720                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7721                 {
7722                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7723                                 ig.Emit (OpCodes.Ldelem_U1);
7724                         else if (type == TypeManager.sbyte_type)
7725                                 ig.Emit (OpCodes.Ldelem_I1);
7726                         else if (type == TypeManager.short_type)
7727                                 ig.Emit (OpCodes.Ldelem_I2);
7728                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7729                                 ig.Emit (OpCodes.Ldelem_U2);
7730                         else if (type == TypeManager.int32_type)
7731                                 ig.Emit (OpCodes.Ldelem_I4);
7732                         else if (type == TypeManager.uint32_type)
7733                                 ig.Emit (OpCodes.Ldelem_U4);
7734                         else if (type == TypeManager.uint64_type)
7735                                 ig.Emit (OpCodes.Ldelem_I8);
7736                         else if (type == TypeManager.int64_type)
7737                                 ig.Emit (OpCodes.Ldelem_I8);
7738                         else if (type == TypeManager.float_type)
7739                                 ig.Emit (OpCodes.Ldelem_R4);
7740                         else if (type == TypeManager.double_type)
7741                                 ig.Emit (OpCodes.Ldelem_R8);
7742                         else if (type == TypeManager.intptr_type)
7743                                 ig.Emit (OpCodes.Ldelem_I);
7744                         else if (TypeManager.IsEnumType (type)){
7745                                 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7746                         } else if (type.IsValueType){
7747                                 ig.Emit (OpCodes.Ldelema, type);
7748                                 ig.Emit (OpCodes.Ldobj, type);
7749                         } else 
7750                                 ig.Emit (OpCodes.Ldelem_Ref);
7751                 }
7752
7753                 /// <summary>
7754                 ///    Returns the right opcode to store an object of Type `t'
7755                 ///    from an array of T.  
7756                 /// </summary>
7757                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj)
7758                 {
7759                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
7760                         is_stobj = false;
7761                         t = TypeManager.TypeToCoreType (t);
7762                         if (TypeManager.IsEnumType (t))
7763                                 t = TypeManager.EnumToUnderlying (t);
7764                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7765                             t == TypeManager.bool_type)
7766                                 return OpCodes.Stelem_I1;
7767                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7768                                  t == TypeManager.char_type)
7769                                 return OpCodes.Stelem_I2;
7770                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7771                                 return OpCodes.Stelem_I4;
7772                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7773                                 return OpCodes.Stelem_I8;
7774                         else if (t == TypeManager.float_type)
7775                                 return OpCodes.Stelem_R4;
7776                         else if (t == TypeManager.double_type)
7777                                 return OpCodes.Stelem_R8;
7778                         else if (t == TypeManager.intptr_type) {
7779                                 is_stobj = true;
7780                                 return OpCodes.Stobj;
7781                         } else if (t.IsValueType) {
7782                                 is_stobj = true;
7783                                 return OpCodes.Stobj;
7784                         } else
7785                                 return OpCodes.Stelem_Ref;
7786                 }
7787
7788                 MethodInfo FetchGetMethod ()
7789                 {
7790                         ModuleBuilder mb = CodeGen.Module.Builder;
7791                         int arg_count = ea.Arguments.Count;
7792                         Type [] args = new Type [arg_count];
7793                         MethodInfo get;
7794                         
7795                         for (int i = 0; i < arg_count; i++){
7796                                 //args [i++] = a.Type;
7797                                 args [i] = TypeManager.int32_type;
7798                         }
7799                         
7800                         get = mb.GetArrayMethod (
7801                                 ea.Expr.Type, "Get",
7802                                 CallingConventions.HasThis |
7803                                 CallingConventions.Standard,
7804                                 type, args);
7805                         return get;
7806                 }
7807                                 
7808
7809                 MethodInfo FetchAddressMethod ()
7810                 {
7811                         ModuleBuilder mb = CodeGen.Module.Builder;
7812                         int arg_count = ea.Arguments.Count;
7813                         Type [] args = new Type [arg_count];
7814                         MethodInfo address;
7815                         Type ret_type;
7816                         
7817                         ret_type = TypeManager.GetReferenceType (type);
7818                         
7819                         for (int i = 0; i < arg_count; i++){
7820                                 //args [i++] = a.Type;
7821                                 args [i] = TypeManager.int32_type;
7822                         }
7823                         
7824                         address = mb.GetArrayMethod (
7825                                 ea.Expr.Type, "Address",
7826                                 CallingConventions.HasThis |
7827                                 CallingConventions.Standard,
7828                                 ret_type, args);
7829
7830                         return address;
7831                 }
7832
7833                 //
7834                 // Load the array arguments into the stack.
7835                 //
7836                 // If we have been requested to cache the values (cached_locations array
7837                 // initialized), then load the arguments the first time and store them
7838                 // in locals.  otherwise load from local variables.
7839                 //
7840                 void LoadArrayAndArguments (EmitContext ec)
7841                 {
7842                         ILGenerator ig = ec.ig;
7843                         
7844                         ea.Expr.Emit (ec);
7845                         foreach (Argument a in ea.Arguments){
7846                                 Type argtype = a.Expr.Type;
7847                                 
7848                                 a.Expr.Emit (ec);
7849                                 
7850                                 if (argtype == TypeManager.int64_type)
7851                                         ig.Emit (OpCodes.Conv_Ovf_I);
7852                                 else if (argtype == TypeManager.uint64_type)
7853                                         ig.Emit (OpCodes.Conv_Ovf_I_Un);
7854                         }
7855                 }
7856
7857                 public void Emit (EmitContext ec, bool leave_copy)
7858                 {
7859                         int rank = ea.Expr.Type.GetArrayRank ();
7860                         ILGenerator ig = ec.ig;
7861
7862                         if (!prepared) {
7863                                 LoadArrayAndArguments (ec);
7864                                 
7865                                 if (rank == 1)
7866                                         EmitLoadOpcode (ig, type);
7867                                 else {
7868                                         MethodInfo method;
7869                                         
7870                                         method = FetchGetMethod ();
7871                                         ig.Emit (OpCodes.Call, method);
7872                                 }
7873                         } else
7874                                 LoadFromPtr (ec.ig, this.type);
7875                         
7876                         if (leave_copy) {
7877                                 ec.ig.Emit (OpCodes.Dup);
7878                                 temp = new LocalTemporary (ec, this.type);
7879                                 temp.Store (ec);
7880                         }
7881                 }
7882                 
7883                 public override void Emit (EmitContext ec)
7884                 {
7885                         Emit (ec, false);
7886                 }
7887
7888                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7889                 {
7890                         int rank = ea.Expr.Type.GetArrayRank ();
7891                         ILGenerator ig = ec.ig;
7892                         Type t = source.Type;
7893                         prepared = prepare_for_load;
7894
7895                         if (prepare_for_load) {
7896                                 AddressOf (ec, AddressOp.LoadStore);
7897                                 ec.ig.Emit (OpCodes.Dup);
7898                                 source.Emit (ec);
7899                                 if (leave_copy) {
7900                                         ec.ig.Emit (OpCodes.Dup);
7901                                         temp = new LocalTemporary (ec, this.type);
7902                                         temp.Store (ec);
7903                                 }
7904                                 StoreFromPtr (ec.ig, t);
7905                                 
7906                                 if (temp != null)
7907                                         temp.Emit (ec);
7908                                 
7909                                 return;
7910                         }
7911                         
7912                         LoadArrayAndArguments (ec);
7913
7914                         if (rank == 1) {
7915                                 bool is_stobj;
7916                                 OpCode op = GetStoreOpcode (t, out is_stobj);
7917                                 //
7918                                 // The stobj opcode used by value types will need
7919                                 // an address on the stack, not really an array/array
7920                                 // pair
7921                                 //
7922                                 if (is_stobj)
7923                                         ig.Emit (OpCodes.Ldelema, t);
7924                                 
7925                                 source.Emit (ec);
7926                                 if (leave_copy) {
7927                                         ec.ig.Emit (OpCodes.Dup);
7928                                         temp = new LocalTemporary (ec, this.type);
7929                                         temp.Store (ec);
7930                                 }
7931                                 
7932                                 if (is_stobj)
7933                                         ig.Emit (OpCodes.Stobj, t);
7934                                 else
7935                                         ig.Emit (op);
7936                         } else {
7937                                 ModuleBuilder mb = CodeGen.Module.Builder;
7938                                 int arg_count = ea.Arguments.Count;
7939                                 Type [] args = new Type [arg_count + 1];
7940                                 MethodInfo set;
7941                                 
7942                                 source.Emit (ec);
7943                                 if (leave_copy) {
7944                                         ec.ig.Emit (OpCodes.Dup);
7945                                         temp = new LocalTemporary (ec, this.type);
7946                                         temp.Store (ec);
7947                                 }
7948                                 
7949                                 for (int i = 0; i < arg_count; i++){
7950                                         //args [i++] = a.Type;
7951                                         args [i] = TypeManager.int32_type;
7952                                 }
7953
7954                                 args [arg_count] = type;
7955                                 
7956                                 set = mb.GetArrayMethod (
7957                                         ea.Expr.Type, "Set",
7958                                         CallingConventions.HasThis |
7959                                         CallingConventions.Standard,
7960                                         TypeManager.void_type, args);
7961                                 
7962                                 ig.Emit (OpCodes.Call, set);
7963                         }
7964                         
7965                         if (temp != null)
7966                                 temp.Emit (ec);
7967                 }
7968
7969                 public void AddressOf (EmitContext ec, AddressOp mode)
7970                 {
7971                         int rank = ea.Expr.Type.GetArrayRank ();
7972                         ILGenerator ig = ec.ig;
7973
7974                         LoadArrayAndArguments (ec);
7975
7976                         if (rank == 1){
7977                                 ig.Emit (OpCodes.Ldelema, type);
7978                         } else {
7979                                 MethodInfo address = FetchAddressMethod ();
7980                                 ig.Emit (OpCodes.Call, address);
7981                         }
7982                 }
7983         }
7984
7985         
7986         class Indexers {
7987                 public ArrayList Properties;
7988                 static Hashtable map;
7989
7990                 public struct Indexer {
7991                         public readonly Type Type;
7992                         public readonly MethodInfo Getter, Setter;
7993
7994                         public Indexer (Type type, MethodInfo get, MethodInfo set)
7995                         {
7996                                 this.Type = type;
7997                                 this.Getter = get;
7998                                 this.Setter = set;
7999                         }
8000                 }
8001
8002                 static Indexers ()
8003                 {
8004                         map = new Hashtable ();
8005                 }
8006
8007                 Indexers ()
8008                 {
8009                         Properties = new ArrayList ();
8010                 }
8011                                 
8012                 void Append (MemberInfo [] mi)
8013                 {
8014                         foreach (PropertyInfo property in mi){
8015                                 MethodInfo get, set;
8016                                 
8017                                 get = property.GetGetMethod (true);
8018                                 set = property.GetSetMethod (true);
8019                                 Properties.Add (new Indexer (property.PropertyType, get, set));
8020                         }
8021                 }
8022
8023                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8024                 {
8025                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
8026
8027                         MemberInfo [] mi = TypeManager.MemberLookup (
8028                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
8029                                 BindingFlags.Public | BindingFlags.Instance |
8030                                 BindingFlags.DeclaredOnly, p_name, null);
8031
8032                         if (mi == null || mi.Length == 0)
8033                                 return null;
8034
8035                         return mi;
8036                 }
8037                 
8038                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc) 
8039                 {
8040                         Indexers ix = (Indexers) map [lookup_type];
8041
8042                         if (ix != null)
8043                                 return ix;
8044
8045                         Type copy = lookup_type;
8046                         while (copy != TypeManager.object_type && copy != null){
8047                                 MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, copy);
8048
8049                                 if (mi != null){
8050                                         if (ix == null)
8051                                                 ix = new Indexers ();
8052
8053                                         ix.Append (mi);
8054                                 }
8055                                         
8056                                 copy = copy.BaseType;
8057                         }
8058
8059                         if (!lookup_type.IsInterface)
8060                                 return ix;
8061
8062                         Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8063                         if (ifaces != null) {
8064                                 foreach (Type itype in ifaces) {
8065                                         MemberInfo [] mi = GetIndexersForTypeOrInterface (caller_type, itype);
8066                                         if (mi != null){
8067                                                 if (ix == null)
8068                                                         ix = new Indexers ();
8069                                         
8070                                                 ix.Append (mi);
8071                                         }
8072                                 }
8073                         }
8074
8075                         return ix;
8076                 }
8077         }
8078
8079         /// <summary>
8080         ///   Expressions that represent an indexer call.
8081         /// </summary>
8082         public class IndexerAccess : Expression, IAssignMethod {
8083                 //
8084                 // Points to our "data" repository
8085                 //
8086                 MethodInfo get, set;
8087                 ArrayList set_arguments;
8088                 bool is_base_indexer;
8089
8090                 protected Type indexer_type;
8091                 protected Type current_type;
8092                 protected Expression instance_expr;
8093                 protected ArrayList arguments;
8094                 
8095                 public IndexerAccess (ElementAccess ea, Location loc)
8096                         : this (ea.Expr, false, loc)
8097                 {
8098                         this.arguments = ea.Arguments;
8099                 }
8100
8101                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8102                                          Location loc)
8103                 {
8104                         this.instance_expr = instance_expr;
8105                         this.is_base_indexer = is_base_indexer;
8106                         this.eclass = ExprClass.Value;
8107                         this.loc = loc;
8108                 }
8109
8110                 protected virtual bool CommonResolve (EmitContext ec)
8111                 {
8112                         indexer_type = instance_expr.Type;
8113                         current_type = ec.ContainerType;
8114
8115                         return true;
8116                 }
8117
8118                 public override Expression DoResolve (EmitContext ec)
8119                 {
8120                         ArrayList AllGetters = new ArrayList();
8121                         if (!CommonResolve (ec))
8122                                 return null;
8123
8124                         //
8125                         // Step 1: Query for all `Item' *properties*.  Notice
8126                         // that the actual methods are pointed from here.
8127                         //
8128                         // This is a group of properties, piles of them.  
8129
8130                         bool found_any = false, found_any_getters = false;
8131                         Type lookup_type = indexer_type;
8132
8133                         Indexers ilist;
8134                         ilist = Indexers.GetIndexersForType (current_type, lookup_type, loc);
8135                         if (ilist != null) {
8136                                 found_any = true;
8137                                 if (ilist.Properties != null) {
8138                                         foreach (Indexers.Indexer ix in ilist.Properties) {
8139                                                 if (ix.Getter != null)
8140                                                         AllGetters.Add(ix.Getter);
8141                                         }
8142                                 }
8143                         }
8144
8145                         if (AllGetters.Count > 0) {
8146                                 found_any_getters = true;
8147                                 get = (MethodInfo) Invocation.OverloadResolve (
8148                                         ec, new MethodGroupExpr (AllGetters, loc),
8149                                         arguments, false, loc);
8150                         }
8151
8152                         if (!found_any) {
8153                                 Report.Error (21, loc,
8154                                               "Type `" + TypeManager.CSharpName (indexer_type) +
8155                                               "' does not have any indexers defined");
8156                                 return null;
8157                         }
8158
8159                         if (!found_any_getters) {
8160                                 Error (154, "indexer can not be used in this context, because " +
8161                                        "it lacks a `get' accessor");
8162                                 return null;
8163                         }
8164
8165                         if (get == null) {
8166                                 Error (1501, "No Overload for method `this' takes `" +
8167                                        arguments.Count + "' arguments");
8168                                 return null;
8169                         }
8170
8171                         //
8172                         // Only base will allow this invocation to happen.
8173                         //
8174                         if (get.IsAbstract && this is BaseIndexerAccess){
8175                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (get));
8176                                 return null;
8177                         }
8178
8179                         type = get.ReturnType;
8180                         if (type.IsPointer && !ec.InUnsafe){
8181                                 UnsafeError (loc);
8182                                 return null;
8183                         }
8184
8185                         instance_expr.CheckMarshallByRefAccess (ec.ContainerType);
8186                         
8187                         eclass = ExprClass.IndexerAccess;
8188                         return this;
8189                 }
8190
8191                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8192                 {
8193                         ArrayList AllSetters = new ArrayList();
8194                         if (!CommonResolve (ec))
8195                                 return null;
8196
8197                         bool found_any = false, found_any_setters = false;
8198
8199                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type, loc);
8200                         if (ilist != null) {
8201                                 found_any = true;
8202                                 if (ilist.Properties != null) {
8203                                         foreach (Indexers.Indexer ix in ilist.Properties) {
8204                                                 if (ix.Setter != null)
8205                                                         AllSetters.Add(ix.Setter);
8206                                         }
8207                                 }
8208                         }
8209                         if (AllSetters.Count > 0) {
8210                                 found_any_setters = true;
8211                                 set_arguments = (ArrayList) arguments.Clone ();
8212                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8213                                 set = (MethodInfo) Invocation.OverloadResolve (
8214                                         ec, new MethodGroupExpr (AllSetters, loc),
8215                                         set_arguments, false, loc);
8216                         }
8217
8218                         if (!found_any) {
8219                                 Report.Error (21, loc,
8220                                               "Type `" + TypeManager.CSharpName (indexer_type) +
8221                                               "' does not have any indexers defined");
8222                                 return null;
8223                         }
8224
8225                         if (!found_any_setters) {
8226                                 Error (154, "indexer can not be used in this context, because " +
8227                                        "it lacks a `set' accessor");
8228                                 return null;
8229                         }
8230
8231                         if (set == null) {
8232                                 Error (1501, "No Overload for method `this' takes `" +
8233                                        arguments.Count + "' arguments");
8234                                 return null;
8235                         }
8236
8237                         //
8238                         // Only base will allow this invocation to happen.
8239                         //
8240                         if (set.IsAbstract && this is BaseIndexerAccess){
8241                                 Report.Error (205, loc, "Cannot call an abstract base indexer: " + Invocation.FullMethodDesc (set));
8242                                 return null;
8243                         }
8244
8245                         //
8246                         // Now look for the actual match in the list of indexers to set our "return" type
8247                         //
8248                         type = TypeManager.void_type;   // default value
8249                         foreach (Indexers.Indexer ix in ilist.Properties){
8250                                 if (ix.Setter == set){
8251                                         type = ix.Type;
8252                                         break;
8253                                 }
8254                         }
8255                         
8256                         instance_expr.CheckMarshallByRefAccess (ec.ContainerType);
8257
8258                         eclass = ExprClass.IndexerAccess;
8259                         return this;
8260                 }
8261                 
8262                 bool prepared = false;
8263                 LocalTemporary temp;
8264                 
8265                 public void Emit (EmitContext ec, bool leave_copy)
8266                 {
8267                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
8268                         if (leave_copy) {
8269                                 ec.ig.Emit (OpCodes.Dup);
8270                                 temp = new LocalTemporary (ec, Type);
8271                                 temp.Store (ec);
8272                         }
8273                 }
8274                 
8275                 //
8276                 // source is ignored, because we already have a copy of it from the
8277                 // LValue resolution and we have already constructed a pre-cached
8278                 // version of the arguments (ea.set_arguments);
8279                 //
8280                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8281                 {
8282                         prepared = prepare_for_load;
8283                         Argument a = (Argument) set_arguments [set_arguments.Count - 1];
8284                         
8285                         if (prepared) {
8286                                 source.Emit (ec);
8287                                 if (leave_copy) {
8288                                         ec.ig.Emit (OpCodes.Dup);
8289                                         temp = new LocalTemporary (ec, Type);
8290                                         temp.Store (ec);
8291                                 }
8292                         } else if (leave_copy) {
8293                                 temp = new LocalTemporary (ec, Type);
8294                                 source.Emit (ec);
8295                                 temp.Store (ec);
8296                                 a.Expr = temp;
8297                         }
8298                         
8299                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
8300                         
8301                         if (temp != null)
8302                                 temp.Emit (ec);
8303                 }
8304                 
8305                 
8306                 public override void Emit (EmitContext ec)
8307                 {
8308                         Emit (ec, false);
8309                 }
8310         }
8311
8312         /// <summary>
8313         ///   The base operator for method names
8314         /// </summary>
8315         public class BaseAccess : Expression {
8316                 string member;
8317                 
8318                 public BaseAccess (string member, Location l)
8319                 {
8320                         this.member = member;
8321                         loc = l;
8322                 }
8323
8324                 public override Expression DoResolve (EmitContext ec)
8325                 {
8326                         Expression c = CommonResolve (ec);
8327
8328                         if (c == null)
8329                                 return null;
8330
8331                         //
8332                         // MethodGroups use this opportunity to flag an error on lacking ()
8333                         //
8334                         if (!(c is MethodGroupExpr))
8335                                 return c.Resolve (ec);
8336                         return c;
8337                 }
8338
8339                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8340                 {
8341                         Expression c = CommonResolve (ec);
8342
8343                         if (c == null)
8344                                 return null;
8345
8346                         //
8347                         // MethodGroups use this opportunity to flag an error on lacking ()
8348                         //
8349                         if (! (c is MethodGroupExpr))
8350                                 return c.DoResolveLValue (ec, right_side);
8351
8352                         return c;
8353                 }
8354
8355                 Expression CommonResolve (EmitContext ec)
8356                 {
8357                         Expression member_lookup;
8358                         Type current_type = ec.ContainerType;
8359                         Type base_type = current_type.BaseType;
8360                         Expression e;
8361
8362                         if (ec.IsStatic){
8363                                 Error (1511, "Keyword base is not allowed in static method");
8364                                 return null;
8365                         }
8366
8367                         if (ec.IsFieldInitializer){
8368                                 Error (1512, "Keyword base is not available in the current context");
8369                                 return null;
8370                         }
8371                         
8372                         member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type, member,
8373                                                       AllMemberTypes, AllBindingFlags, loc);
8374                         if (member_lookup == null) {
8375                                 MemberLookupFailed (ec, base_type, base_type, member, null, loc);
8376                                 return null;
8377                         }
8378
8379                         Expression left;
8380                         
8381                         if (ec.IsStatic)
8382                                 left = new TypeExpression (base_type, loc);
8383                         else
8384                                 left = ec.GetThis (loc);
8385                         
8386                         e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
8387
8388                         if (e is PropertyExpr){
8389                                 PropertyExpr pe = (PropertyExpr) e;
8390
8391                                 pe.IsBase = true;
8392                         }
8393                         
8394                         if (e is MethodGroupExpr)
8395                                 ((MethodGroupExpr) e).IsBase = true;
8396
8397                         return e;
8398                 }
8399
8400                 public override void Emit (EmitContext ec)
8401                 {
8402                         throw new Exception ("Should never be called"); 
8403                 }
8404         }
8405
8406         /// <summary>
8407         ///   The base indexer operator
8408         /// </summary>
8409         public class BaseIndexerAccess : IndexerAccess {
8410                 public BaseIndexerAccess (ArrayList args, Location loc)
8411                         : base (null, true, loc)
8412                 {
8413                         arguments = new ArrayList ();
8414                         foreach (Expression tmp in args)
8415                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8416                 }
8417
8418                 protected override bool CommonResolve (EmitContext ec)
8419                 {
8420                         instance_expr = ec.GetThis (loc);
8421
8422                         current_type = ec.ContainerType.BaseType;
8423                         indexer_type = current_type;
8424
8425                         foreach (Argument a in arguments){
8426                                 if (!a.Resolve (ec, loc))
8427                                         return false;
8428                         }
8429
8430                         return true;
8431                 }
8432         }
8433         
8434         /// <summary>
8435         ///   This class exists solely to pass the Type around and to be a dummy
8436         ///   that can be passed to the conversion functions (this is used by
8437         ///   foreach implementation to typecast the object return value from
8438         ///   get_Current into the proper type.  All code has been generated and
8439         ///   we only care about the side effect conversions to be performed
8440         ///
8441         ///   This is also now used as a placeholder where a no-action expression
8442         ///   is needed (the `New' class).
8443         /// </summary>
8444         public class EmptyExpression : Expression {
8445                 public static readonly EmptyExpression Null = new EmptyExpression ();
8446
8447                 // TODO: should be protected
8448                 public EmptyExpression ()
8449                 {
8450                         type = TypeManager.object_type;
8451                         eclass = ExprClass.Value;
8452                         loc = Location.Null;
8453                 }
8454
8455                 public EmptyExpression (Type t)
8456                 {
8457                         type = t;
8458                         eclass = ExprClass.Value;
8459                         loc = Location.Null;
8460                 }
8461                 
8462                 public override Expression DoResolve (EmitContext ec)
8463                 {
8464                         return this;
8465                 }
8466
8467                 public override void Emit (EmitContext ec)
8468                 {
8469                         // nothing, as we only exist to not do anything.
8470                 }
8471
8472                 //
8473                 // This is just because we might want to reuse this bad boy
8474                 // instead of creating gazillions of EmptyExpressions.
8475                 // (CanImplicitConversion uses it)
8476                 //
8477                 public void SetType (Type t)
8478                 {
8479                         type = t;
8480                 }
8481         }
8482
8483         public class UserCast : Expression {
8484                 MethodBase method;
8485                 Expression source;
8486                 
8487                 public UserCast (MethodInfo method, Expression source, Location l)
8488                 {
8489                         this.method = method;
8490                         this.source = source;
8491                         type = method.ReturnType;
8492                         eclass = ExprClass.Value;
8493                         loc = l;
8494                 }
8495
8496                 public Expression Source {
8497                         get {
8498                                 return source;
8499                         }
8500                 }
8501                         
8502                 public override Expression DoResolve (EmitContext ec)
8503                 {
8504                         //
8505                         // We are born fully resolved
8506                         //
8507                         return this;
8508                 }
8509
8510                 public override void Emit (EmitContext ec)
8511                 {
8512                         ILGenerator ig = ec.ig;
8513
8514                         source.Emit (ec);
8515                         
8516                         if (method is MethodInfo)
8517                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8518                         else
8519                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8520
8521                 }
8522         }
8523
8524         // <summary>
8525         //   This class is used to "construct" the type during a typecast
8526         //   operation.  Since the Type.GetType class in .NET can parse
8527         //   the type specification, we just use this to construct the type
8528         //   one bit at a time.
8529         // </summary>
8530         public class ComposedCast : TypeExpr {
8531                 Expression left;
8532                 string dim;
8533                 
8534                 public ComposedCast (Expression left, string dim, Location l)
8535                 {
8536                         this.left = left;
8537                         this.dim = dim;
8538                         loc = l;
8539                 }
8540
8541                 public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
8542                 {
8543                         TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8544                         if (lexpr == null)
8545                                 return null;
8546
8547                         Type ltype = lexpr.ResolveType (ec);
8548
8549                         if ((ltype == TypeManager.void_type) && (dim != "*")) {
8550                                 Report.Error (1547, Location,
8551                                               "Keyword 'void' cannot be used in this context");
8552                                 return null;
8553                         }
8554
8555                         //
8556                         // ltype.Fullname is already fully qualified, so we can skip
8557                         // a lot of probes, and go directly to TypeManager.LookupType
8558                         //
8559                         string cname = ltype.FullName + dim;
8560                         type = TypeManager.LookupTypeDirect (cname);
8561                         if (type == null){
8562                                 //
8563                                 // For arrays of enumerations we are having a problem
8564                                 // with the direct lookup.  Need to investigate.
8565                                 //
8566                                 // For now, fall back to the full lookup in that case.
8567                                 //
8568                                 type = RootContext.LookupType (
8569                                         ec.DeclSpace, cname, false, loc);
8570
8571                                 if (type == null)
8572                                         return null;
8573                         }
8574
8575                         if (!ec.InUnsafe && type.IsPointer){
8576                                 UnsafeError (loc);
8577                                 return null;
8578                         }
8579                         
8580                         eclass = ExprClass.Type;
8581                         return this;
8582                 }
8583
8584                 public override string Name {
8585                         get {
8586                                 return left + dim;
8587                         }
8588                 }
8589         }
8590
8591         //
8592         // This class is used to represent the address of an array, used
8593         // only by the Fixed statement, this is like the C "&a [0]" construct.
8594         //
8595         public class ArrayPtr : Expression {
8596                 Expression array;
8597                 
8598                 public ArrayPtr (Expression array, Location l)
8599                 {
8600                         Type array_type = TypeManager.GetElementType (array.Type);
8601
8602                         this.array = array;
8603
8604                         type = TypeManager.GetPointerType (array_type);
8605                         eclass = ExprClass.Value;
8606                         loc = l;
8607                 }
8608
8609                 public override void Emit (EmitContext ec)
8610                 {
8611                         ILGenerator ig = ec.ig;
8612                         
8613                         array.Emit (ec);
8614                         IntLiteral.EmitInt (ig, 0);
8615                         ig.Emit (OpCodes.Ldelema, TypeManager.GetElementType (array.Type));
8616                 }
8617
8618                 public override Expression DoResolve (EmitContext ec)
8619                 {
8620                         //
8621                         // We are born fully resolved
8622                         //
8623                         return this;
8624                 }
8625         }
8626
8627         //
8628         // Used by the fixed statement
8629         //
8630         public class StringPtr : Expression {
8631                 LocalBuilder b;
8632                 
8633                 public StringPtr (LocalBuilder b, Location l)
8634                 {
8635                         this.b = b;
8636                         eclass = ExprClass.Value;
8637                         type = TypeManager.char_ptr_type;
8638                         loc = l;
8639                 }
8640
8641                 public override Expression DoResolve (EmitContext ec)
8642                 {
8643                         // This should never be invoked, we are born in fully
8644                         // initialized state.
8645
8646                         return this;
8647                 }
8648
8649                 public override void Emit (EmitContext ec)
8650                 {
8651                         ILGenerator ig = ec.ig;
8652
8653                         ig.Emit (OpCodes.Ldloc, b);
8654                         ig.Emit (OpCodes.Conv_I);
8655                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8656                         ig.Emit (OpCodes.Add);
8657                 }
8658         }
8659         
8660         //
8661         // Implements the `stackalloc' keyword
8662         //
8663         public class StackAlloc : Expression {
8664                 Type otype;
8665                 Expression t;
8666                 Expression count;
8667                 
8668                 public StackAlloc (Expression type, Expression count, Location l)
8669                 {
8670                         t = type;
8671                         this.count = count;
8672                         loc = l;
8673                 }
8674
8675                 public override Expression DoResolve (EmitContext ec)
8676                 {
8677                         count = count.Resolve (ec);
8678                         if (count == null)
8679                                 return null;
8680                         
8681                         if (count.Type != TypeManager.int32_type){
8682                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8683                                 if (count == null)
8684                                         return null;
8685                         }
8686
8687                         Constant c = count as Constant;
8688                         if (c != null && c.IsNegative) {
8689                                 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8690                                 return null;
8691                         }
8692
8693                         if (ec.CurrentBranching.InCatch () ||
8694                             ec.CurrentBranching.InFinally (true)) {
8695                                 Error (255,
8696                                        "stackalloc can not be used in a catch or finally block");
8697                                 return null;
8698                         }
8699
8700                         TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8701                         if (texpr == null)
8702                                 return null;
8703
8704                         otype = texpr.ResolveType (ec);
8705
8706                         if (!TypeManager.VerifyUnManaged (otype, loc))
8707                                 return null;
8708
8709                         type = TypeManager.GetPointerType (otype);
8710                         eclass = ExprClass.Value;
8711
8712                         return this;
8713                 }
8714
8715                 public override void Emit (EmitContext ec)
8716                 {
8717                         int size = GetTypeSize (otype);
8718                         ILGenerator ig = ec.ig;
8719                                 
8720                         if (size == 0)
8721                                 ig.Emit (OpCodes.Sizeof, otype);
8722                         else
8723                                 IntConstant.EmitInt (ig, size);
8724                         count.Emit (ec);
8725                         ig.Emit (OpCodes.Mul);
8726                         ig.Emit (OpCodes.Localloc);
8727                 }
8728         }
8729 }