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