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