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