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