make line-endings uniform
[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                                 GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
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, "A 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 FloatConstant
2355                                 || c is DoubleConstant
2356                                 || c is DecimalConstant
2357                                 )
2358                                 return;
2359
2360                         long value = 0;
2361
2362                         if (c is ULongConstant) {
2363                                 ulong uvalue = ((ULongConstant) c).Value;
2364                                 if (uvalue > long.MaxValue) {
2365                                         if (type == TypeManager.byte_type ||
2366                                             type == TypeManager.sbyte_type ||
2367                                             type == TypeManager.short_type ||
2368                                             type == TypeManager.ushort_type ||
2369                                             type == TypeManager.int32_type ||
2370                                             type == TypeManager.uint32_type ||
2371                                             type == TypeManager.int64_type ||
2372                                                 type == TypeManager.char_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                         else if (c is CharConstant)
2393                                 value = ((CharConstant)c).Value;
2394
2395                         if (value == 0)
2396                                 return;
2397
2398                         if (IsValueOutOfRange (value, type))
2399                                 WarnUselessComparison (type);
2400                 }
2401
2402                 private bool IsValueOutOfRange (long value, Type type)
2403                 {
2404                         if (IsTypeUnsigned (type) && value < 0)
2405                                 return true;
2406                         return type == TypeManager.sbyte_type && (value >= 0x80 || value < -0x80) ||
2407                                 type == TypeManager.byte_type && value >= 0x100 ||
2408                                 type == TypeManager.short_type && (value >= 0x8000 || value < -0x8000) ||
2409                                 type == TypeManager.ushort_type && value >= 0x10000 ||
2410                                 type == TypeManager.int32_type && (value >= 0x80000000 || value < -0x80000000) ||
2411                                 type == TypeManager.uint32_type && value >= 0x100000000;
2412                 }
2413
2414                 private static bool IsTypeIntegral (Type type)
2415                 {
2416                         return type == TypeManager.uint64_type ||
2417                                 type == TypeManager.int64_type ||
2418                                 type == TypeManager.uint32_type ||
2419                                 type == TypeManager.int32_type ||
2420                                 type == TypeManager.ushort_type ||
2421                                 type == TypeManager.short_type ||
2422                                 type == TypeManager.sbyte_type ||
2423                                 type == TypeManager.byte_type ||
2424                                 type == TypeManager.char_type;
2425                 }
2426
2427                 private static bool IsTypeUnsigned (Type type)
2428                 {
2429                         return type == TypeManager.uint64_type ||
2430                                 type == TypeManager.uint32_type ||
2431                                 type == TypeManager.ushort_type ||
2432                                 type == TypeManager.byte_type ||
2433                                 type == TypeManager.char_type;
2434                 }
2435
2436                 private void WarnUselessComparison (Type type)
2437                 {
2438                         Report.Warning (652, 2, loc, "A comparison between a constant and a variable is useless. The constant is out of the range of the variable type `{0}'",
2439                                 TypeManager.CSharpName (type));
2440                 }
2441
2442                 /// <remarks>
2443                 ///   EmitBranchable is called from Statement.EmitBoolExpression in the
2444                 ///   context of a conditional bool expression.  This function will return
2445                 ///   false if it is was possible to use EmitBranchable, or true if it was.
2446                 ///
2447                 ///   The expression's code is generated, and we will generate a branch to `target'
2448                 ///   if the resulting expression value is equal to isTrue
2449                 /// </remarks>
2450                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
2451                 {
2452                         ILGenerator ig = ec.ig;
2453
2454                         //
2455                         // This is more complicated than it looks, but its just to avoid
2456                         // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2457                         // but on top of that we want for == and != to use a special path
2458                         // if we are comparing against null
2459                         //
2460                         if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
2461                                 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2462                                 
2463                                 //
2464                                 // put the constant on the rhs, for simplicity
2465                                 //
2466                                 if (left is Constant) {
2467                                         Expression swap = right;
2468                                         right = left;
2469                                         left = swap;
2470                                 }
2471                                 
2472                                 if (((Constant) right).IsZeroInteger) {
2473                                         left.Emit (ec);
2474                                         if (my_on_true)
2475                                                 ig.Emit (OpCodes.Brtrue, target);
2476                                         else
2477                                                 ig.Emit (OpCodes.Brfalse, target);
2478                                         
2479                                         return;
2480                                 } else if (right is BoolConstant) {
2481                                         left.Emit (ec);
2482                                         if (my_on_true != ((BoolConstant) right).Value)
2483                                                 ig.Emit (OpCodes.Brtrue, target);
2484                                         else
2485                                                 ig.Emit (OpCodes.Brfalse, target);
2486                                         
2487                                         return;
2488                                 }
2489
2490                         } else if (oper == Operator.LogicalAnd) {
2491
2492                                 if (onTrue) {
2493                                         Label tests_end = ig.DefineLabel ();
2494                                         
2495                                         left.EmitBranchable (ec, tests_end, false);
2496                                         right.EmitBranchable (ec, target, true);
2497                                         ig.MarkLabel (tests_end);                                       
2498                                 } else {
2499                                         //
2500                                         // This optimizes code like this 
2501                                         // if (true && i > 4)
2502                                         //
2503                                         if (!(left is Constant))
2504                                                 left.EmitBranchable (ec, target, false);
2505
2506                                         if (!(right is Constant)) 
2507                                                 right.EmitBranchable (ec, target, false);
2508                                 }
2509                                 
2510                                 return;
2511                                 
2512                         } else if (oper == Operator.LogicalOr){
2513                                 if (onTrue) {
2514                                         left.EmitBranchable (ec, target, true);
2515                                         right.EmitBranchable (ec, target, true);
2516                                         
2517                                 } else {
2518                                         Label tests_end = ig.DefineLabel ();
2519                                         left.EmitBranchable (ec, tests_end, true);
2520                                         right.EmitBranchable (ec, target, false);
2521                                         ig.MarkLabel (tests_end);
2522                                 }
2523                                 
2524                                 return;
2525                                 
2526                         } else if (!(oper == Operator.LessThan        || oper == Operator.GreaterThan ||
2527                                      oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
2528                                      oper == Operator.Equality        || oper == Operator.Inequality)) {
2529                                 base.EmitBranchable (ec, target, onTrue);
2530                                 return;
2531                         }
2532                         
2533                         left.Emit (ec);
2534                         right.Emit (ec);
2535
2536                         Type t = left.Type;
2537                         bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
2538                         
2539                         switch (oper){
2540                         case Operator.Equality:
2541                                 if (onTrue)
2542                                         ig.Emit (OpCodes.Beq, target);
2543                                 else
2544                                         ig.Emit (OpCodes.Bne_Un, target);
2545                                 break;
2546
2547                         case Operator.Inequality:
2548                                 if (onTrue)
2549                                         ig.Emit (OpCodes.Bne_Un, target);
2550                                 else
2551                                         ig.Emit (OpCodes.Beq, target);
2552                                 break;
2553
2554                         case Operator.LessThan:
2555                                 if (onTrue)
2556                                         if (isUnsigned)
2557                                                 ig.Emit (OpCodes.Blt_Un, target);
2558                                         else
2559                                                 ig.Emit (OpCodes.Blt, target);
2560                                 else
2561                                         if (isUnsigned)
2562                                                 ig.Emit (OpCodes.Bge_Un, target);
2563                                         else
2564                                                 ig.Emit (OpCodes.Bge, target);
2565                                 break;
2566
2567                         case Operator.GreaterThan:
2568                                 if (onTrue)
2569                                         if (isUnsigned)
2570                                                 ig.Emit (OpCodes.Bgt_Un, target);
2571                                         else
2572                                                 ig.Emit (OpCodes.Bgt, target);
2573                                 else
2574                                         if (isUnsigned)
2575                                                 ig.Emit (OpCodes.Ble_Un, target);
2576                                         else
2577                                                 ig.Emit (OpCodes.Ble, target);
2578                                 break;
2579
2580                         case Operator.LessThanOrEqual:
2581                                 if (onTrue)
2582                                         if (isUnsigned)
2583                                                 ig.Emit (OpCodes.Ble_Un, target);
2584                                         else
2585                                                 ig.Emit (OpCodes.Ble, target);
2586                                 else
2587                                         if (isUnsigned)
2588                                                 ig.Emit (OpCodes.Bgt_Un, target);
2589                                         else
2590                                                 ig.Emit (OpCodes.Bgt, target);
2591                                 break;
2592
2593
2594                         case Operator.GreaterThanOrEqual:
2595                                 if (onTrue)
2596                                         if (isUnsigned)
2597                                                 ig.Emit (OpCodes.Bge_Un, target);
2598                                         else
2599                                                 ig.Emit (OpCodes.Bge, target);
2600                                 else
2601                                         if (isUnsigned)
2602                                                 ig.Emit (OpCodes.Blt_Un, target);
2603                                         else
2604                                                 ig.Emit (OpCodes.Blt, target);
2605                                 break;
2606                         default:
2607                                 Console.WriteLine (oper);
2608                                 throw new Exception ("what is THAT");
2609                         }
2610                 }
2611                 
2612                 public override void Emit (EmitContext ec)
2613                 {
2614                         ILGenerator ig = ec.ig;
2615                         Type l = left.Type;
2616                         OpCode opcode;
2617
2618                         //
2619                         // Handle short-circuit operators differently
2620                         // than the rest
2621                         //
2622                         if (oper == Operator.LogicalAnd) {
2623                                 Label load_zero = ig.DefineLabel ();
2624                                 Label end = ig.DefineLabel ();
2625                                                                 
2626                                 left.EmitBranchable (ec, load_zero, false);
2627                                 right.Emit (ec);
2628                                 ig.Emit (OpCodes.Br, end);
2629                                 
2630                                 ig.MarkLabel (load_zero);
2631                                 ig.Emit (OpCodes.Ldc_I4_0);
2632                                 ig.MarkLabel (end);
2633                                 return;
2634                         } else if (oper == Operator.LogicalOr) {
2635                                 Label load_one = ig.DefineLabel ();
2636                                 Label end = ig.DefineLabel ();
2637
2638                                 left.EmitBranchable (ec, load_one, true);
2639                                 right.Emit (ec);
2640                                 ig.Emit (OpCodes.Br, end);
2641                                 
2642                                 ig.MarkLabel (load_one);
2643                                 ig.Emit (OpCodes.Ldc_I4_1);
2644                                 ig.MarkLabel (end);
2645                                 return;
2646                         }
2647
2648                         left.Emit (ec);
2649                         right.Emit (ec);
2650
2651                         bool isUnsigned = is_unsigned (left.Type);
2652                         
2653                         switch (oper){
2654                         case Operator.Multiply:
2655                                 if (ec.CheckState){
2656                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2657                                                 opcode = OpCodes.Mul_Ovf;
2658                                         else if (isUnsigned)
2659                                                 opcode = OpCodes.Mul_Ovf_Un;
2660                                         else
2661                                                 opcode = OpCodes.Mul;
2662                                 } else
2663                                         opcode = OpCodes.Mul;
2664
2665                                 break;
2666
2667                         case Operator.Division:
2668                                 if (isUnsigned)
2669                                         opcode = OpCodes.Div_Un;
2670                                 else
2671                                         opcode = OpCodes.Div;
2672                                 break;
2673
2674                         case Operator.Modulus:
2675                                 if (isUnsigned)
2676                                         opcode = OpCodes.Rem_Un;
2677                                 else
2678                                         opcode = OpCodes.Rem;
2679                                 break;
2680
2681                         case Operator.Addition:
2682                                 if (ec.CheckState){
2683                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2684                                                 opcode = OpCodes.Add_Ovf;
2685                                         else if (isUnsigned)
2686                                                 opcode = OpCodes.Add_Ovf_Un;
2687                                         else
2688                                                 opcode = OpCodes.Add;
2689                                 } else
2690                                         opcode = OpCodes.Add;
2691                                 break;
2692
2693                         case Operator.Subtraction:
2694                                 if (ec.CheckState){
2695                                         if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2696                                                 opcode = OpCodes.Sub_Ovf;
2697                                         else if (isUnsigned)
2698                                                 opcode = OpCodes.Sub_Ovf_Un;
2699                                         else
2700                                                 opcode = OpCodes.Sub;
2701                                 } else
2702                                         opcode = OpCodes.Sub;
2703                                 break;
2704
2705                         case Operator.RightShift:
2706                                 if (isUnsigned)
2707                                         opcode = OpCodes.Shr_Un;
2708                                 else
2709                                         opcode = OpCodes.Shr;
2710                                 break;
2711                                 
2712                         case Operator.LeftShift:
2713                                 opcode = OpCodes.Shl;
2714                                 break;
2715
2716                         case Operator.Equality:
2717                                 opcode = OpCodes.Ceq;
2718                                 break;
2719
2720                         case Operator.Inequality:
2721                                 ig.Emit (OpCodes.Ceq);
2722                                 ig.Emit (OpCodes.Ldc_I4_0);
2723                                 
2724                                 opcode = OpCodes.Ceq;
2725                                 break;
2726
2727                         case Operator.LessThan:
2728                                 if (isUnsigned)
2729                                         opcode = OpCodes.Clt_Un;
2730                                 else
2731                                         opcode = OpCodes.Clt;
2732                                 break;
2733
2734                         case Operator.GreaterThan:
2735                                 if (isUnsigned)
2736                                         opcode = OpCodes.Cgt_Un;
2737                                 else
2738                                         opcode = OpCodes.Cgt;
2739                                 break;
2740
2741                         case Operator.LessThanOrEqual:
2742                                 Type lt = left.Type;
2743                                 
2744                                 if (isUnsigned || (lt == TypeManager.double_type || lt == TypeManager.float_type))
2745                                         ig.Emit (OpCodes.Cgt_Un);
2746                                 else
2747                                         ig.Emit (OpCodes.Cgt);
2748                                 ig.Emit (OpCodes.Ldc_I4_0);
2749                                 
2750                                 opcode = OpCodes.Ceq;
2751                                 break;
2752
2753                         case Operator.GreaterThanOrEqual:
2754                                 Type le = left.Type;
2755                                 
2756                                 if (isUnsigned || (le == TypeManager.double_type || le == TypeManager.float_type))
2757                                         ig.Emit (OpCodes.Clt_Un);
2758                                 else
2759                                         ig.Emit (OpCodes.Clt);
2760                                 
2761                                 ig.Emit (OpCodes.Ldc_I4_0);
2762                                 
2763                                 opcode = OpCodes.Ceq;
2764                                 break;
2765
2766                         case Operator.BitwiseOr:
2767                                 opcode = OpCodes.Or;
2768                                 break;
2769
2770                         case Operator.BitwiseAnd:
2771                                 opcode = OpCodes.And;
2772                                 break;
2773
2774                         case Operator.ExclusiveOr:
2775                                 opcode = OpCodes.Xor;
2776                                 break;
2777
2778                         default:
2779                                 throw new Exception ("This should not happen: Operator = "
2780                                                      + oper.ToString ());
2781                         }
2782
2783                         ig.Emit (opcode);
2784                 }
2785         }
2786
2787         //
2788         // Object created by Binary when the binary operator uses an method instead of being
2789         // a binary operation that maps to a CIL binary operation.
2790         //
2791         public class BinaryMethod : Expression {
2792                 public MethodBase method;
2793                 public ArrayList  Arguments;
2794                 
2795                 public BinaryMethod (Type t, MethodBase m, ArrayList args)
2796                 {
2797                         method = m;
2798                         Arguments = args;
2799                         type = t;
2800                         eclass = ExprClass.Value;
2801                 }
2802
2803                 public override Expression DoResolve (EmitContext ec)
2804                 {
2805                         return this;
2806                 }
2807
2808                 public override void Emit (EmitContext ec)
2809                 {
2810                         ILGenerator ig = ec.ig;
2811                         
2812                         if (Arguments != null) 
2813                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
2814                         
2815                         if (method is MethodInfo)
2816                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
2817                         else
2818                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2819                 }
2820         }
2821         
2822         //
2823         // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
2824         // b, c, d... may be strings or objects.
2825         //
2826         public class StringConcat : Expression {
2827                 ArrayList operands;
2828                 bool invalid = false;
2829                 bool emit_conv_done = false;
2830                 //
2831                 // Are we also concating objects?
2832                 //
2833                 bool is_strings_only = true;
2834                 
2835                 public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
2836                 {
2837                         this.loc = loc;
2838                         type = TypeManager.string_type;
2839                         eclass = ExprClass.Value;
2840                 
2841                         operands = new ArrayList (2);
2842                         Append (ec, left);
2843                         Append (ec, right);
2844                 }
2845                 
2846                 public override Expression DoResolve (EmitContext ec)
2847                 {
2848                         if (invalid)
2849                                 return null;
2850                         
2851                         return this;
2852                 }
2853                 
2854                 public void Append (EmitContext ec, Expression operand)
2855                 {
2856                         //
2857                         // Constant folding
2858                         //
2859                         StringConstant sc = operand as StringConstant;
2860                         if (sc != null) {
2861 // TODO: it will be better to do this silently as an optimalization
2862 // int i = 0;
2863 // string s = "" + i;
2864 // because this code has poor performace
2865 //                              if (sc.Value.Length == 0)
2866 //                                      Report.Warning (-300, 3, Location, "Appending an empty string has no effect. Did you intend to append a space string?");
2867
2868                                 if (operands.Count != 0) {
2869                                         StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
2870                                         if (last_operand != null) {
2871                                                 operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value, last_operand.Location);
2872                                                 return;
2873                                         }
2874                                 }
2875                         }
2876                         
2877                         //
2878                         // Conversion to object
2879                         //
2880                         if (operand.Type != TypeManager.string_type) {
2881                                 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
2882                                 
2883                                 if (no == null) {
2884                                         Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
2885                                         invalid = true;
2886                                 }
2887                                 operand = no;
2888                         }
2889                         
2890                         operands.Add (operand);
2891                 }
2892
2893                 public override void Emit (EmitContext ec)
2894                 {
2895                         MethodInfo concat_method = null;
2896                         
2897                         //
2898                         // Do conversion to arguments; check for strings only
2899                         //
2900                         
2901                         // This can get called multiple times, so we have to deal with that.
2902                         if (!emit_conv_done) {
2903                                 emit_conv_done = true;
2904                                 for (int i = 0; i < operands.Count; i ++) {
2905                                         Expression e = (Expression) operands [i];
2906                                         is_strings_only &= e.Type == TypeManager.string_type;
2907                                 }
2908                                 
2909                                 for (int i = 0; i < operands.Count; i ++) {
2910                                         Expression e = (Expression) operands [i];
2911                                         
2912                                         if (! is_strings_only && e.Type == TypeManager.string_type) {
2913                                                 // need to make sure this is an object, because the EmitParams
2914                                                 // method might look at the type of this expression, see it is a
2915                                                 // string and emit a string [] when we want an object [];
2916                                                 
2917                                                 e = new EmptyCast (e, TypeManager.object_type);
2918                                         }
2919                                         operands [i] = new Argument (e, Argument.AType.Expression);
2920                                 }
2921                         }
2922                         
2923                         //
2924                         // Find the right method
2925                         //
2926                         switch (operands.Count) {
2927                         case 1:
2928                                 //
2929                                 // This should not be possible, because simple constant folding
2930                                 // is taken care of in the Binary code.
2931                                 //
2932                                 throw new Exception ("how did you get here?");
2933                         
2934                         case 2:
2935                                 concat_method = is_strings_only ? 
2936                                         TypeManager.string_concat_string_string :
2937                                         TypeManager.string_concat_object_object ;
2938                                 break;
2939                         case 3:
2940                                 concat_method = is_strings_only ? 
2941                                         TypeManager.string_concat_string_string_string :
2942                                         TypeManager.string_concat_object_object_object ;
2943                                 break;
2944                         case 4:
2945                                 //
2946                                 // There is not a 4 param overlaod for object (the one that there is
2947                                 // is actually a varargs methods, and is only in corlib because it was
2948                                 // introduced there before.).
2949                                 //
2950                                 if (!is_strings_only)
2951                                         goto default;
2952                                 
2953                                 concat_method = TypeManager.string_concat_string_string_string_string;
2954                                 break;
2955                         default:
2956                                 concat_method = is_strings_only ? 
2957                                         TypeManager.string_concat_string_dot_dot_dot :
2958                                         TypeManager.string_concat_object_dot_dot_dot ;
2959                                 break;
2960                         }
2961                         
2962                         Invocation.EmitArguments (ec, concat_method, operands, false, null);
2963                         ec.ig.Emit (OpCodes.Call, concat_method);
2964                 }
2965         }
2966
2967         //
2968         // Object created with +/= on delegates
2969         //
2970         public class BinaryDelegate : Expression {
2971                 MethodInfo method;
2972                 ArrayList  args;
2973
2974                 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
2975                 {
2976                         method = mi;
2977                         this.args = args;
2978                         type = t;
2979                         eclass = ExprClass.Value;
2980                 }
2981
2982                 public override Expression DoResolve (EmitContext ec)
2983                 {
2984                         return this;
2985                 }
2986
2987                 public override void Emit (EmitContext ec)
2988                 {
2989                         ILGenerator ig = ec.ig;
2990                         
2991                         Invocation.EmitArguments (ec, method, args, false, null);
2992                         
2993                         ig.Emit (OpCodes.Call, (MethodInfo) method);
2994                         ig.Emit (OpCodes.Castclass, type);
2995                 }
2996
2997                 public Expression Right {
2998                         get {
2999                                 Argument arg = (Argument) args [1];
3000                                 return arg.Expr;
3001                         }
3002                 }
3003
3004                 public bool IsAddition {
3005                         get {
3006                                 return method == TypeManager.delegate_combine_delegate_delegate;
3007                         }
3008                 }
3009         }
3010         
3011         //
3012         // User-defined conditional logical operator
3013         public class ConditionalLogicalOperator : Expression {
3014                 Expression left, right;
3015                 bool is_and;
3016
3017                 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3018                 {
3019                         type = t;
3020                         eclass = ExprClass.Value;
3021                         this.loc = loc;
3022                         this.left = left;
3023                         this.right = right;
3024                         this.is_and = is_and;
3025                 }
3026
3027                 protected void Error19 ()
3028                 {
3029                         Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3030                 }
3031
3032                 protected void Error218 ()
3033                 {
3034                         Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3035                                "declarations of operator true and operator false");
3036                 }
3037
3038                 Expression op_true, op_false, op;
3039                 LocalTemporary left_temp;
3040
3041                 public override Expression DoResolve (EmitContext ec)
3042                 {
3043                         MethodInfo method;
3044                         Expression operator_group;
3045
3046                         operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc);
3047                         if (operator_group == null) {
3048                                 Error19 ();
3049                                 return null;
3050                         }
3051
3052                         left_temp = new LocalTemporary (type);
3053
3054                         ArrayList arguments = new ArrayList (2);
3055                         arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3056                         arguments.Add (new Argument (right, Argument.AType.Expression));
3057                         method = Invocation.OverloadResolve (
3058                                 ec, (MethodGroupExpr) operator_group, arguments, false, loc)
3059                                 as MethodInfo;
3060                         if (method == null) {
3061                                 Error19 ();
3062                                 return null;
3063                         }
3064
3065                         if (method.ReturnType != type) {
3066                                 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3067                                                 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3068                                 return null;
3069                         }
3070
3071                         op = new StaticCallExpr (method, arguments, loc);
3072
3073                         op_true = GetOperatorTrue (ec, left_temp, loc);
3074                         op_false = GetOperatorFalse (ec, left_temp, loc);
3075                         if ((op_true == null) || (op_false == null)) {
3076                                 Error218 ();
3077                                 return null;
3078                         }
3079
3080                         return this;
3081                 }
3082
3083                 public override void Emit (EmitContext ec)
3084                 {
3085                         ILGenerator ig = ec.ig;
3086                         Label false_target = ig.DefineLabel ();
3087                         Label end_target = ig.DefineLabel ();
3088
3089                         left.Emit (ec);
3090                         left_temp.Store (ec);
3091
3092                         (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3093                         left_temp.Emit (ec);
3094                         ig.Emit (OpCodes.Br, end_target);
3095                         ig.MarkLabel (false_target);
3096                         op.Emit (ec);
3097                         ig.MarkLabel (end_target);
3098
3099                         // We release 'left_temp' here since 'op' may refer to it too
3100                         left_temp.Release (ec);
3101                 }
3102         }
3103
3104         public class PointerArithmetic : Expression {
3105                 Expression left, right;
3106                 bool is_add;
3107
3108                 //
3109                 // We assume that `l' is always a pointer
3110                 //
3111                 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3112                 {
3113                         type = t;
3114                         this.loc = loc;
3115                         left = l;
3116                         right = r;
3117                         is_add = is_addition;
3118                 }
3119
3120                 public override Expression DoResolve (EmitContext ec)
3121                 {
3122                         eclass = ExprClass.Variable;
3123                         
3124                         if (left.Type == TypeManager.void_ptr_type) {
3125                                 Error (242, "The operation in question is undefined on void pointers");
3126                                 return null;
3127                         }
3128                         
3129                         return this;
3130                 }
3131
3132                 public override void Emit (EmitContext ec)
3133                 {
3134                         Type op_type = left.Type;
3135                         ILGenerator ig = ec.ig;
3136                         
3137                         // It must be either array or fixed buffer
3138                         Type element = TypeManager.HasElementType (op_type) ?
3139                                 element = TypeManager.GetElementType (op_type) :
3140                                 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3141
3142                         int size = GetTypeSize (element);
3143                         Type rtype = right.Type;
3144                         
3145                         if (rtype.IsPointer){
3146                                 //
3147                                 // handle (pointer - pointer)
3148                                 //
3149                                 left.Emit (ec);
3150                                 right.Emit (ec);
3151                                 ig.Emit (OpCodes.Sub);
3152
3153                                 if (size != 1){
3154                                         if (size == 0)
3155                                                 ig.Emit (OpCodes.Sizeof, element);
3156                                         else 
3157                                                 IntLiteral.EmitInt (ig, size);
3158                                         ig.Emit (OpCodes.Div);
3159                                 }
3160                                 ig.Emit (OpCodes.Conv_I8);
3161                         } else {
3162                                 //
3163                                 // handle + and - on (pointer op int)
3164                                 //
3165                                 left.Emit (ec);
3166                                 ig.Emit (OpCodes.Conv_I);
3167
3168                                 Constant right_const = right as Constant;
3169                                 if (right_const != null && size != 0) {
3170                                         Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3171                                         if (ex == null)
3172                                                 return;
3173                                         ex.Emit (ec);
3174                                 } else {
3175                                         right.Emit (ec);
3176                                         if (size != 1){
3177                                                 if (size == 0)
3178                                                         ig.Emit (OpCodes.Sizeof, element);
3179                                                 else 
3180                                                         IntLiteral.EmitInt (ig, size);
3181                                                 if (rtype == TypeManager.int64_type)
3182                                                         ig.Emit (OpCodes.Conv_I8);
3183                                                 else if (rtype == TypeManager.uint64_type)
3184                                                         ig.Emit (OpCodes.Conv_U8);
3185                                                 ig.Emit (OpCodes.Mul);
3186                                         }
3187                                 }
3188                                 
3189                                 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3190                                         ig.Emit (OpCodes.Conv_I);
3191                                 
3192                                 if (is_add)
3193                                         ig.Emit (OpCodes.Add);
3194                                 else
3195                                         ig.Emit (OpCodes.Sub);
3196                         }
3197                 }
3198         }
3199         
3200         /// <summary>
3201         ///   Implements the ternary conditional operator (?:)
3202         /// </summary>
3203         public class Conditional : Expression {
3204                 Expression expr, trueExpr, falseExpr;
3205                 
3206                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
3207                 {
3208                         this.expr = expr;
3209                         this.trueExpr = trueExpr;
3210                         this.falseExpr = falseExpr;
3211                         this.loc = expr.Location;
3212                 }
3213
3214                 public Expression Expr {
3215                         get {
3216                                 return expr;
3217                         }
3218                 }
3219
3220                 public Expression TrueExpr {
3221                         get {
3222                                 return trueExpr;
3223                         }
3224                 }
3225
3226                 public Expression FalseExpr {
3227                         get {
3228                                 return falseExpr;
3229                         }
3230                 }
3231
3232                 public override Expression DoResolve (EmitContext ec)
3233                 {
3234                         expr = expr.Resolve (ec);
3235
3236                         if (expr == null)
3237                                 return null;
3238
3239 #if GMCS_SOURCE
3240                         if (TypeManager.IsNullableValueType (expr.Type))
3241                                 return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
3242 #endif
3243                         
3244                         if (expr.Type != TypeManager.bool_type){
3245                                 expr = Expression.ResolveBoolean (
3246                                         ec, expr, loc);
3247                                 
3248                                 if (expr == null)
3249                                         return null;
3250                         }
3251                         
3252                         Assign ass = expr as Assign;
3253                         if (ass != null && ass.Source is Constant) {
3254                                 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3255                         }
3256
3257                         trueExpr = trueExpr.Resolve (ec);
3258                         falseExpr = falseExpr.Resolve (ec);
3259
3260                         if (trueExpr == null || falseExpr == null)
3261                                 return null;
3262
3263                         eclass = ExprClass.Value;
3264                         if (trueExpr.Type == falseExpr.Type) {
3265                                 type = trueExpr.Type;
3266                                 if (type == TypeManager.null_type) {
3267                                         // TODO: probably will have to implement ConditionalConstant
3268                                         // to call method without return constant as well
3269                                         Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3270                                         return trueExpr;
3271                                 }
3272                         } else {
3273                                 Expression conv;
3274                                 Type true_type = trueExpr.Type;
3275                                 Type false_type = falseExpr.Type;
3276
3277                                 //
3278                                 // First, if an implicit conversion exists from trueExpr
3279                                 // to falseExpr, then the result type is of type falseExpr.Type
3280                                 //
3281                                 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3282                                 if (conv != null){
3283                                         //
3284                                         // Check if both can convert implicitl to each other's type
3285                                         //
3286                                         if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3287                                                 Error (172,
3288                                                        "Can not compute type of conditional expression " +
3289                                                        "as `" + TypeManager.CSharpName (trueExpr.Type) +
3290                                                        "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3291                                                        "' convert implicitly to each other");
3292                                                 return null;
3293                                         }
3294                                         type = false_type;
3295                                         trueExpr = conv;
3296                                 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3297                                         type = true_type;
3298                                         falseExpr = conv;
3299                                 } else {
3300                                         Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3301                                                 trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
3302                                         return null;
3303                                 }
3304                         }
3305
3306                         // Dead code optimalization
3307                         if (expr is BoolConstant){
3308                                 BoolConstant bc = (BoolConstant) expr;
3309
3310                                 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3311                                 return bc.Value ? trueExpr : falseExpr;
3312                         }
3313
3314                         return this;
3315                 }
3316
3317                 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3318                 {
3319                         return null;
3320                 }
3321
3322                 public override void Emit (EmitContext ec)
3323                 {
3324                         ILGenerator ig = ec.ig;
3325                         Label false_target = ig.DefineLabel ();
3326                         Label end_target = ig.DefineLabel ();
3327
3328                         expr.EmitBranchable (ec, false_target, false);
3329                         trueExpr.Emit (ec);
3330                         ig.Emit (OpCodes.Br, end_target);
3331                         ig.MarkLabel (false_target);
3332                         falseExpr.Emit (ec);
3333                         ig.MarkLabel (end_target);
3334                 }
3335
3336         }
3337
3338         public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3339                 bool prepared;
3340                 LocalTemporary temp;
3341
3342                 public abstract Variable Variable {
3343                         get;
3344                 }
3345
3346                 public abstract bool IsRef {
3347                         get;
3348                 }
3349
3350                 public override void Emit (EmitContext ec)
3351                 {
3352                         Emit (ec, false);
3353                 }
3354
3355                 //
3356                 // This method is used by parameters that are references, that are
3357                 // being passed as references:  we only want to pass the pointer (that
3358                 // is already stored in the parameter, not the address of the pointer,
3359                 // and not the value of the variable).
3360                 //
3361                 public void EmitLoad (EmitContext ec)
3362                 {
3363                         Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3364                         if (!prepared)
3365                                 Variable.EmitInstance (ec);
3366                         Variable.Emit (ec);
3367                 }
3368                 
3369                 public void Emit (EmitContext ec, bool leave_copy)
3370                 {
3371                         Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3372
3373                         EmitLoad (ec);
3374
3375                         if (IsRef) {
3376                                 if (prepared)
3377                                         ec.ig.Emit (OpCodes.Dup);
3378         
3379                                 //
3380                                 // If we are a reference, we loaded on the stack a pointer
3381                                 // Now lets load the real value
3382                                 //
3383                                 LoadFromPtr (ec.ig, type);
3384                         }
3385
3386                         if (leave_copy) {
3387                                 ec.ig.Emit (OpCodes.Dup);
3388
3389                                 if (IsRef || Variable.NeedsTemporary) {
3390                                         temp = new LocalTemporary (Type);
3391                                         temp.Store (ec);
3392                                 }
3393                         }
3394                 }
3395
3396                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3397                                         bool prepare_for_load)
3398                 {
3399                         Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3400                                       source, loc);
3401
3402                         ILGenerator ig = ec.ig;
3403                         prepared = prepare_for_load;
3404
3405                         Variable.EmitInstance (ec);
3406                         if (prepare_for_load && Variable.HasInstance)
3407                                 ig.Emit (OpCodes.Dup);
3408                         else if (IsRef && !prepared)
3409                                 Variable.Emit (ec);
3410
3411                         source.Emit (ec);
3412
3413                         if (leave_copy) {
3414                                 ig.Emit (OpCodes.Dup);
3415                                 if (IsRef || Variable.NeedsTemporary) {
3416                                         temp = new LocalTemporary (Type);
3417                                         temp.Store (ec);
3418                                 }
3419                         }
3420
3421                         if (IsRef)
3422                                 StoreFromPtr (ig, type);
3423                         else
3424                                 Variable.EmitAssign (ec);
3425
3426                         if (temp != null) {
3427                                 temp.Emit (ec);
3428                                 temp.Release (ec);
3429                         }
3430                 }
3431                 
3432                 public void AddressOf (EmitContext ec, AddressOp mode)
3433                 {
3434                         Variable.EmitInstance (ec);
3435                         Variable.EmitAddressOf (ec);
3436                 }
3437         }
3438
3439         /// <summary>
3440         ///   Local variables
3441         /// </summary>
3442         public class LocalVariableReference : VariableReference, IVariable {
3443                 public readonly string Name;
3444                 public readonly Block Block;
3445                 public LocalInfo local_info;
3446                 bool is_readonly;
3447                 Variable variable;
3448
3449                 public LocalVariableReference (Block block, string name, Location l)
3450                 {
3451                         Block = block;
3452                         Name = name;
3453                         loc = l;
3454                         eclass = ExprClass.Variable;
3455                 }
3456
3457                 //
3458                 // Setting `is_readonly' to false will allow you to create a writable
3459                 // reference to a read-only variable.  This is used by foreach and using.
3460                 //
3461                 public LocalVariableReference (Block block, string name, Location l,
3462                                                LocalInfo local_info, bool is_readonly)
3463                         : this (block, name, l)
3464                 {
3465                         this.local_info = local_info;
3466                         this.is_readonly = is_readonly;
3467                 }
3468
3469                 public VariableInfo VariableInfo {
3470                         get { return local_info.VariableInfo; }
3471                 }
3472
3473                 public override bool IsRef {
3474                         get { return false; }
3475                 }
3476
3477                 public bool IsReadOnly {
3478                         get { return is_readonly; }
3479                 }
3480
3481                 public bool VerifyAssigned (EmitContext ec)
3482                 {
3483                         VariableInfo variable_info = local_info.VariableInfo;
3484                         return variable_info == null || variable_info.IsAssigned (ec, loc);
3485                 }
3486
3487                 void ResolveLocalInfo ()
3488                 {
3489                         if (local_info == null) {
3490                                 local_info = Block.GetLocalInfo (Name);
3491                                 is_readonly = local_info.ReadOnly;
3492                         }
3493                 }
3494
3495                 protected Expression DoResolveBase (EmitContext ec)
3496                 {
3497                         type = local_info.VariableType;
3498
3499                         Expression e = Block.GetConstantExpression (Name);
3500                         if (e != null)
3501                                 return e.Resolve (ec);
3502
3503                         if (!VerifyAssigned (ec))
3504                                 return null;
3505
3506                         //
3507                         // If we are referencing a variable from the external block
3508                         // flag it for capturing
3509                         //
3510                         if (ec.MustCaptureVariable (local_info)) {
3511                                 if (local_info.AddressTaken){
3512                                         AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3513                                         return null;
3514                                 }
3515
3516                                 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3517                                 variable = scope.AddLocal (local_info);
3518                                 type = variable.Type;
3519                         }
3520
3521                         return this;
3522                 }
3523
3524                 public override Expression DoResolve (EmitContext ec)
3525                 {
3526                         ResolveLocalInfo ();
3527                         local_info.Used = true;
3528                         return DoResolveBase (ec);
3529                 }
3530
3531                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3532                 {
3533                         ResolveLocalInfo ();
3534
3535                         if (is_readonly) {
3536                                 int code;
3537                                 string msg;
3538                                 if (right_side == EmptyExpression.OutAccess) {
3539                                         code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3540                                 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3541                                         code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3542                                 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3543                                         code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3544                                 } else {
3545                                         code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3546                                 }
3547                                 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3548                                 return null;
3549                         }
3550
3551                         // is out param
3552                         if (right_side == EmptyExpression.OutAccess)
3553                                 local_info.Used = true;
3554
3555                         if (VariableInfo != null)
3556                                 VariableInfo.SetAssigned (ec);
3557
3558                         return DoResolveBase (ec);
3559                 }
3560
3561                 public bool VerifyFixed ()
3562                 {
3563                         // A local Variable is always fixed.
3564                         return true;
3565                 }
3566
3567                 public override int GetHashCode ()
3568                 {
3569                         return Name.GetHashCode ();
3570                 }
3571
3572                 public override bool Equals (object obj)
3573                 {
3574                         LocalVariableReference lvr = obj as LocalVariableReference;
3575                         if (lvr == null)
3576                                 return false;
3577
3578                         return Name == lvr.Name && Block == lvr.Block;
3579                 }
3580
3581                 public override Variable Variable {
3582                         get { return variable != null ? variable : local_info.Variable; }
3583                 }
3584
3585                 public override string ToString ()
3586                 {
3587                         return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3588                 }
3589         }
3590
3591         /// <summary>
3592         ///   This represents a reference to a parameter in the intermediate
3593         ///   representation.
3594         /// </summary>
3595         public class ParameterReference : VariableReference, IVariable {
3596                 Parameter par;
3597                 string name;
3598                 int idx;
3599                 Block block;
3600                 VariableInfo vi;
3601                 public bool is_ref, is_out;
3602
3603                 public bool IsOut {
3604                         get {
3605                                 return is_out;
3606                         }
3607                 }
3608
3609                 public override bool IsRef {
3610                         get {
3611                                 return is_ref;
3612                         }
3613                 }
3614
3615                 public string Name {
3616                         get {
3617                                 return name;
3618                         }
3619                 }
3620
3621                 public Parameter Parameter {
3622                         get {
3623                                 return par;
3624                         }
3625                 }
3626
3627                 Variable variable;
3628                 
3629                 public ParameterReference (Parameter par, Block block, int idx, Location loc)
3630                 {
3631                         this.par = par;
3632                         this.name = par.Name;
3633                         this.block = block;
3634                         this.idx  = idx;
3635                         this.loc = loc;
3636                         eclass = ExprClass.Variable;
3637                 }
3638
3639                 public VariableInfo VariableInfo {
3640                         get { return vi; }
3641                 }
3642
3643                 public override Variable Variable {
3644                         get { return variable != null ? variable : par.Variable; }
3645                 }
3646
3647                 public bool VerifyFixed ()
3648                 {
3649                         // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3650                         return par.ModFlags == Parameter.Modifier.NONE;
3651                 }
3652
3653                 public bool IsAssigned (EmitContext ec, Location loc)
3654                 {
3655                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (vi))
3656                                 return true;
3657
3658                         Report.Error (269, loc,
3659                                       "Use of unassigned out parameter `{0}'", par.Name);
3660                         return false;
3661                 }
3662
3663                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3664                 {
3665                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (vi, field_name))
3666                                 return true;
3667
3668                         Report.Error (170, loc,
3669                                       "Use of possibly unassigned field `" + field_name + "'");
3670                         return false;
3671                 }
3672
3673                 public void SetAssigned (EmitContext ec)
3674                 {
3675                         if (is_out && ec.DoFlowAnalysis)
3676                                 ec.CurrentBranching.SetAssigned (vi);
3677                 }
3678
3679                 public void SetFieldAssigned (EmitContext ec, string field_name)
3680                 {
3681                         if (is_out && ec.DoFlowAnalysis)
3682                                 ec.CurrentBranching.SetFieldAssigned (vi, field_name);
3683                 }
3684
3685                 protected bool DoResolveBase (EmitContext ec)
3686                 {
3687                         if (!par.Resolve (ec)) {
3688                                 //TODO:
3689                         }
3690
3691                         type = par.ParameterType;
3692                         Parameter.Modifier mod = par.ModFlags;
3693                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3694                         is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3695                         eclass = ExprClass.Variable;
3696
3697                         if (is_out)
3698                                 vi = block.ParameterMap [idx];
3699
3700                         AnonymousContainer am = ec.CurrentAnonymousMethod;
3701                         if (am == null)
3702                                 return true;
3703
3704                         if (is_ref && !block.Toplevel.IsLocalParameter (name)){
3705                                 Report.Error (1628, Location,
3706                                               "Cannot use ref or out parameter `{0}' inside an " +
3707                                               "anonymous method block", par.Name);
3708                                 return false;
3709                         }
3710
3711                         if (!am.IsIterator && block.Toplevel.IsLocalParameter (name))
3712                                 return true;
3713
3714                         RootScopeInfo host = null;
3715                         ToplevelBlock toplevel = block.Toplevel;
3716                         while (toplevel != null) {
3717                                 if (toplevel.IsLocalParameter (name))
3718                                         break;
3719
3720                                 toplevel = toplevel.Container;
3721                         }
3722
3723                         ScopeInfo scope = toplevel.CreateScopeInfo ();
3724                         variable = scope.AddParameter (par, idx);
3725                         type = variable.Type;
3726                         return true;
3727                 }
3728
3729                 public override int GetHashCode()
3730                 {
3731                         return name.GetHashCode ();
3732                 }
3733
3734                 public override bool Equals (object obj)
3735                 {
3736                         ParameterReference pr = obj as ParameterReference;
3737                         if (pr == null)
3738                                 return false;
3739
3740                         return name == pr.name && block == pr.block;
3741                 }
3742
3743                 //
3744                 // Notice that for ref/out parameters, the type exposed is not the
3745                 // same type exposed externally.
3746                 //
3747                 // for "ref int a":
3748                 //   externally we expose "int&"
3749                 //   here we expose       "int".
3750                 //
3751                 // We record this in "is_ref".  This means that the type system can treat
3752                 // the type as it is expected, but when we generate the code, we generate
3753                 // the alternate kind of code.
3754                 //
3755                 public override Expression DoResolve (EmitContext ec)
3756                 {
3757                         if (!DoResolveBase (ec))
3758                                 return null;
3759
3760                         if (is_out && ec.DoFlowAnalysis &&
3761                             (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3762                                 return null;
3763
3764                         return this;
3765                 }
3766
3767                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3768                 {
3769                         if (!DoResolveBase (ec))
3770                                 return null;
3771
3772                         SetAssigned (ec);
3773
3774                         return this;
3775                 }
3776
3777                 static public void EmitLdArg (ILGenerator ig, int x)
3778                 {
3779                         if (x <= 255){
3780                                 switch (x){
3781                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3782                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3783                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3784                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3785                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3786                                 }
3787                         } else
3788                                 ig.Emit (OpCodes.Ldarg, x);
3789                 }
3790                 
3791                 public override string ToString ()
3792                 {
3793                         return "ParameterReference[" + name + "]";
3794                 }
3795         }
3796         
3797         /// <summary>
3798         ///   Used for arguments to New(), Invocation()
3799         /// </summary>
3800         public class Argument {
3801                 public enum AType : byte {
3802                         Expression,
3803                         Ref,
3804                         Out,
3805                         ArgList
3806                 };
3807
3808                 public readonly AType ArgType;
3809                 public Expression Expr;
3810                 
3811                 public Argument (Expression expr, AType type)
3812                 {
3813                         this.Expr = expr;
3814                         this.ArgType = type;
3815                 }
3816
3817                 public Argument (Expression expr)
3818                 {
3819                         this.Expr = expr;
3820                         this.ArgType = AType.Expression;
3821                 }
3822
3823                 public Type Type {
3824                         get {
3825                                 if (ArgType == AType.Ref || ArgType == AType.Out)
3826                                         return TypeManager.GetReferenceType (Expr.Type);
3827                                 else
3828                                         return Expr.Type;
3829                         }
3830                 }
3831
3832                 public Parameter.Modifier Modifier
3833                 {
3834                         get {
3835                                 switch (ArgType) {
3836                                         case AType.Out:
3837                                                 return Parameter.Modifier.OUT;
3838
3839                                         case AType.Ref:
3840                                                 return Parameter.Modifier.REF;
3841
3842                                         default:
3843                                                 return Parameter.Modifier.NONE;
3844                                 }
3845                         }
3846                 }
3847
3848                 public static string FullDesc (Argument a)
3849                 {
3850                         if (a.ArgType == AType.ArgList)
3851                                 return "__arglist";
3852
3853                         return (a.ArgType == AType.Ref ? "ref " :
3854                                 (a.ArgType == AType.Out ? "out " : "")) +
3855                                 TypeManager.CSharpName (a.Expr.Type);
3856                 }
3857
3858                 public bool ResolveMethodGroup (EmitContext ec)
3859                 {
3860                         SimpleName sn = Expr as SimpleName;
3861                         if (sn != null)
3862                                 Expr = sn.GetMethodGroup ();
3863
3864                         // FIXME: csc doesn't report any error if you try to use `ref' or
3865                         //        `out' in a delegate creation expression.
3866                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3867                         if (Expr == null)
3868                                 return false;
3869
3870                         return true;
3871                 }
3872
3873                 public bool Resolve (EmitContext ec, Location loc)
3874                 {
3875                         using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
3876                                 // Verify that the argument is readable
3877                                 if (ArgType != AType.Out)
3878                                         Expr = Expr.Resolve (ec);
3879
3880                                 // Verify that the argument is writeable
3881                                 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
3882                                         Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
3883
3884                                 return Expr != null;
3885                         }
3886                 }
3887
3888                 public void Emit (EmitContext ec)
3889                 {
3890                         if (ArgType != AType.Ref && ArgType != AType.Out) {
3891                                 Expr.Emit (ec);
3892                                 return;
3893                         }
3894
3895                         AddressOp mode = AddressOp.Store;
3896                         if (ArgType == AType.Ref)
3897                                 mode |= AddressOp.Load;
3898                                 
3899                         IMemoryLocation ml = (IMemoryLocation) Expr;
3900                         ParameterReference pr = ml as ParameterReference;
3901
3902                         //
3903                         // ParameterReferences might already be references, so we want
3904                         // to pass just the value
3905                         //
3906                         if (pr != null && pr.IsRef)
3907                                 pr.EmitLoad (ec);
3908                         else
3909                                 ml.AddressOf (ec, mode);
3910                 }
3911         }
3912
3913         /// <summary>
3914         ///   Invocation of methods or delegates.
3915         /// </summary>
3916         public class Invocation : ExpressionStatement {
3917                 public readonly ArrayList Arguments;
3918
3919                 Expression expr;
3920                 MethodBase method = null;
3921                 
3922                 //
3923                 // arguments is an ArrayList, but we do not want to typecast,
3924                 // as it might be null.
3925                 //
3926                 // FIXME: only allow expr to be a method invocation or a
3927                 // delegate invocation (7.5.5)
3928                 //
3929                 public Invocation (Expression expr, ArrayList arguments)
3930                 {
3931                         this.expr = expr;
3932                         Arguments = arguments;
3933                         loc = expr.Location;
3934                 }
3935
3936                 public Expression Expr {
3937                         get {
3938                                 return expr;
3939                         }
3940                 }
3941
3942                 /// <summary>
3943                 ///   Determines "better conversion" as specified in 14.4.2.3
3944                 ///
3945                 ///    Returns : p    if a->p is better,
3946                 ///              q    if a->q is better,
3947                 ///              null if neither is better
3948                 /// </summary>
3949                 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3950                 {
3951                         Type argument_type = TypeManager.TypeToCoreType (a.Type);
3952                         Expression argument_expr = a.Expr;
3953
3954                         if (argument_type == null)
3955                                 throw new Exception ("Expression of type " + a.Expr +
3956                                                      " does not resolve its type");
3957
3958                         if (p == null || q == null)
3959                                 throw new InternalErrorException ("BetterConversion Got a null conversion");
3960
3961                         if (p == q)
3962                                 return null;
3963
3964                         if (argument_expr is NullLiteral) {
3965                                 //
3966                                 // If the argument is null and one of the types to compare is 'object' and
3967                                 // the other is a reference type, we prefer the other.
3968                                 //
3969                                 // This follows from the usual rules:
3970                                 //   * There is an implicit conversion from 'null' to type 'object'
3971                                 //   * There is an implicit conversion from 'null' to any reference type
3972                                 //   * There is an implicit conversion from any reference type to type 'object'
3973                                 //   * There is no implicit conversion from type 'object' to other reference types
3974                                 //  => Conversion of 'null' to a reference type is better than conversion to 'object'
3975                                 //
3976                                 //  FIXME: This probably isn't necessary, since the type of a NullLiteral is the 
3977                                 //         null type. I think it used to be 'object' and thus needed a special 
3978                                 //         case to avoid the immediately following two checks.
3979                                 //
3980                                 if (!p.IsValueType && q == TypeManager.object_type)
3981                                         return p;
3982                                 if (!q.IsValueType && p == TypeManager.object_type)
3983                                         return q;
3984                         }
3985                                 
3986                         if (argument_type == p)
3987                                 return p;
3988
3989                         if (argument_type == q)
3990                                 return q;
3991
3992                         Expression p_tmp = new EmptyExpression (p);
3993                         Expression q_tmp = new EmptyExpression (q);
3994
3995                         bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
3996                         bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
3997
3998                         if (p_to_q && !q_to_p)
3999                                 return p;
4000
4001                         if (q_to_p && !p_to_q)
4002                                 return q;
4003
4004                         if (p == TypeManager.sbyte_type)
4005                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4006                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4007                                         return p;
4008                         if (q == TypeManager.sbyte_type)
4009                                 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
4010                                     p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4011                                         return q;
4012
4013                         if (p == TypeManager.short_type)
4014                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4015                                     q == TypeManager.uint64_type)
4016                                         return p;
4017                         if (q == TypeManager.short_type)
4018                                 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
4019                                     p == TypeManager.uint64_type)
4020                                         return q;
4021
4022                         if (p == TypeManager.int32_type)
4023                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4024                                         return p;
4025                         if (q == TypeManager.int32_type)
4026                                 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4027                                         return q;
4028
4029                         if (p == TypeManager.int64_type)
4030                                 if (q == TypeManager.uint64_type)
4031                                         return p;
4032                         if (q == TypeManager.int64_type)
4033                                 if (p == TypeManager.uint64_type)
4034                                         return q;
4035
4036                         return null;
4037                 }
4038
4039                 static Type MoreSpecific (Type p, Type q)
4040                 {
4041                         if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4042                                 return q;
4043                         if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4044                                 return p;
4045
4046                         if (TypeManager.HasElementType (p)) {
4047                                 Type pe = TypeManager.GetElementType (p);
4048                                 Type qe = TypeManager.GetElementType (q);
4049                                 Type specific = MoreSpecific (pe, qe);
4050                                 if (specific == pe)
4051                                         return p;
4052                                 if (specific == qe)
4053                                         return q;
4054                         } else if (TypeManager.IsGenericType (p)) {
4055                                 Type[] pargs = TypeManager.GetTypeArguments (p);
4056                                 Type[] qargs = TypeManager.GetTypeArguments (q);
4057
4058                                 bool p_specific_at_least_once = false;
4059                                 bool q_specific_at_least_once = false;
4060
4061                                 for (int i = 0; i < pargs.Length; i++) {
4062                                         Type specific = MoreSpecific (pargs [i], qargs [i]);
4063                                         if (specific == pargs [i])
4064                                                 p_specific_at_least_once = true;
4065                                         if (specific == qargs [i])
4066                                                 q_specific_at_least_once = true;
4067                                 }
4068
4069                                 if (p_specific_at_least_once && !q_specific_at_least_once)
4070                                         return p;
4071                                 if (!p_specific_at_least_once && q_specific_at_least_once)
4072                                         return q;
4073                         }
4074
4075                         return null;
4076                 }
4077                 
4078                 /// <summary>
4079                 ///   Determines "Better function" between candidate
4080                 ///   and the current best match
4081                 /// </summary>
4082                 /// <remarks>
4083                 ///    Returns a boolean indicating :
4084                 ///     false if candidate ain't better
4085                 ///     true  if candidate is better than the current best match
4086                 /// </remarks>
4087                 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
4088                                             MethodBase candidate, bool candidate_params,
4089                                             MethodBase best, bool best_params)
4090                 {
4091                         ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
4092                         ParameterData best_pd = TypeManager.GetParameterData (best);
4093                 
4094                         bool better_at_least_one = false;
4095                         bool same = true;
4096                         for (int j = 0, c_idx = 0, b_idx = 0; j < argument_count; ++j, ++c_idx, ++b_idx) {
4097                                 Argument a = (Argument) args [j];
4098
4099                                 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (c_idx));
4100                                 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (b_idx));
4101
4102                                 if (candidate_params && candidate_pd.ParameterModifier (c_idx) == Parameter.Modifier.PARAMS) {
4103                                         ct = TypeManager.GetElementType (ct);
4104                                         --c_idx;
4105                                 }
4106
4107                                 if (best_params && best_pd.ParameterModifier (b_idx) == Parameter.Modifier.PARAMS) {
4108                                         bt = TypeManager.GetElementType (bt);
4109                                         --b_idx;
4110                                 }
4111
4112                                 if (ct.Equals (bt))
4113                                         continue;
4114
4115                                 same = false;
4116                                 Type better = BetterConversion (ec, a, ct, bt);
4117
4118                                 // for each argument, the conversion to 'ct' should be no worse than 
4119                                 // the conversion to 'bt'.
4120                                 if (better == bt)
4121                                         return false;
4122
4123                                 // for at least one argument, the conversion to 'ct' should be better than 
4124                                 // the conversion to 'bt'.
4125                                 if (better == ct)
4126                                         better_at_least_one = true;
4127                         }
4128
4129                         if (better_at_least_one)
4130                                 return true;
4131
4132                         //
4133                         // This handles the case
4134                         //
4135                         //   Add (float f1, float f2, float f3);
4136                         //   Add (params decimal [] foo);
4137                         //
4138                         // The call Add (3, 4, 5) should be ambiguous.  Without this check, the
4139                         // first candidate would've chosen as better.
4140                         //
4141                         if (!same)
4142                                 return false;
4143
4144                         //
4145                         // The two methods have equal parameter types.  Now apply tie-breaking rules
4146                         //
4147                         if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
4148                                 return true;
4149                         if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
4150                                 return false;
4151
4152                         //
4153                         // This handles the following cases:
4154                         //
4155                         //   Trim () is better than Trim (params char[] chars)
4156                         //   Concat (string s1, string s2, string s3) is better than
4157                         //     Concat (string s1, params string [] srest)
4158                         //   Foo (int, params int [] rest) is better than Foo (params int [] rest)
4159                         //
4160                         if (!candidate_params && best_params)
4161                                 return true;
4162                         if (candidate_params && !best_params)
4163                                 return false;
4164
4165                         int candidate_param_count = candidate_pd.Count;
4166                         int best_param_count = best_pd.Count;
4167
4168                         if (candidate_param_count != best_param_count)
4169                                 // can only happen if (candidate_params && best_params)
4170                                 return candidate_param_count > best_param_count;
4171
4172                         //
4173                         // now, both methods have the same number of parameters, and the parameters have the same types
4174                         // Pick the "more specific" signature
4175                         //
4176
4177                         MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
4178                         MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
4179
4180                         ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
4181                         ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
4182
4183                         bool specific_at_least_once = false;
4184                         for (int j = 0; j < candidate_param_count; ++j) {
4185                                 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
4186                                 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
4187                                 if (ct.Equals (bt))
4188                                         continue;
4189                                 Type specific = MoreSpecific (ct, bt);
4190                                 if (specific == bt)
4191                                         return false;
4192                                 if (specific == ct)
4193                                         specific_at_least_once = true;
4194                         }
4195
4196                         if (specific_at_least_once)
4197                                 return true;
4198
4199                         // FIXME: handle lifted operators
4200                         // ...
4201
4202                         return false;
4203                 }
4204
4205                 internal static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4206                 {
4207                         if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4208                                 return false;
4209
4210                         ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
4211                         ParameterData base_pd = TypeManager.GetParameterData (base_method);
4212                 
4213                         if (cand_pd.Count != base_pd.Count)
4214                                 return false;
4215
4216                         for (int j = 0; j < cand_pd.Count; ++j) {
4217                                 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
4218                                 Parameter.Modifier bm = base_pd.ParameterModifier (j);
4219                                 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
4220                                 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
4221
4222                                 if (cm != bm || ct != bt)
4223                                         return false;
4224                         }
4225
4226                         return true;
4227                 }
4228
4229                 public static string FullMethodDesc (MethodBase mb)
4230                 {
4231                         if (mb == null)
4232                                 return "";
4233
4234                         StringBuilder sb;
4235                         if (mb is MethodInfo) {
4236                                 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4237                                 sb.Append (" ");
4238                         }
4239                         else
4240                                 sb = new StringBuilder ();
4241
4242                         sb.Append (TypeManager.CSharpSignature (mb));
4243                         return sb.ToString ();
4244                 }
4245
4246                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4247                 {
4248                         MemberInfo [] miset;
4249                         MethodGroupExpr union;
4250
4251                         if (mg1 == null) {
4252                                 if (mg2 == null)
4253                                         return null;
4254                                 return (MethodGroupExpr) mg2;
4255                         } else {
4256                                 if (mg2 == null)
4257                                         return (MethodGroupExpr) mg1;
4258                         }
4259                         
4260                         MethodGroupExpr left_set = null, right_set = null;
4261                         int length1 = 0, length2 = 0;
4262                         
4263                         left_set = (MethodGroupExpr) mg1;
4264                         length1 = left_set.Methods.Length;
4265                         
4266                         right_set = (MethodGroupExpr) mg2;
4267                         length2 = right_set.Methods.Length;
4268                         
4269                         ArrayList common = new ArrayList ();
4270
4271                         foreach (MethodBase r in right_set.Methods){
4272                                 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4273                                         common.Add (r);
4274                         }
4275
4276                         miset = new MemberInfo [length1 + length2 - common.Count];
4277                         left_set.Methods.CopyTo (miset, 0);
4278                         
4279                         int k = length1;
4280
4281                         foreach (MethodBase r in right_set.Methods) {
4282                                 if (!common.Contains (r))
4283                                         miset [k++] = r;
4284                         }
4285
4286                         union = new MethodGroupExpr (miset, loc);
4287                         
4288                         return union;
4289                 }
4290
4291                 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4292                                                              ArrayList arguments, int arg_count,
4293                                                              ref MethodBase candidate)
4294                 {
4295                         return IsParamsMethodApplicable (
4296                                 ec, me, arguments, arg_count, false, ref candidate) ||
4297                                 IsParamsMethodApplicable (
4298                                         ec, me, arguments, arg_count, true, ref candidate);
4299
4300
4301                 }
4302
4303                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4304                                                       ArrayList arguments, int arg_count,
4305                                                       bool do_varargs, ref MethodBase candidate)
4306                 {
4307 #if GMCS_SOURCE
4308                         if (!me.HasTypeArguments &&
4309                             !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4310                                 return false;
4311
4312                         if (TypeManager.IsGenericMethodDefinition (candidate))
4313                                 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4314 #endif
4315
4316                         return IsParamsMethodApplicable (
4317                                 ec, arguments, arg_count, candidate, do_varargs);
4318                 }
4319
4320                 /// <summary>
4321                 ///   Determines if the candidate method, if a params method, is applicable
4322                 ///   in its expanded form to the given set of arguments
4323                 /// </summary>
4324                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4325                                                       int arg_count, MethodBase candidate,
4326                                                       bool do_varargs)
4327                 {
4328                         ParameterData pd = TypeManager.GetParameterData (candidate);
4329
4330                         int pd_count = pd.Count;
4331                         if (pd_count == 0)
4332                                 return false;
4333
4334                         int count = pd_count - 1;
4335                         if (do_varargs) {
4336                                 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4337                                         return false;
4338                                 if (pd_count != arg_count)
4339                                         return false;
4340
4341                                 if (!(((Argument) arguments [count]).Expr is Arglist))
4342                                         return false;
4343                                 --pd_count;
4344                         } else {
4345                                 if (!pd.HasParams)
4346                                         return false;
4347                         }
4348                         
4349                         if (count > arg_count)
4350                                 return false;
4351                         
4352                         if (pd_count == 1 && arg_count == 0)
4353                                 return true;
4354
4355                         //
4356                         // If we have come this far, the case which
4357                         // remains is when the number of parameters is
4358                         // less than or equal to the argument count.
4359                         //
4360                         int argument_index = 0;
4361                         Argument a;
4362                         for (int i = 0; i < pd_count; ++i) {
4363
4364                                 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
4365                                         Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4366                                         int params_args_count = arg_count - pd_count;
4367                                         if (params_args_count < 0)
4368                                                 continue;
4369
4370                                         do {
4371                                                 a = (Argument) arguments [argument_index++];
4372
4373                                                 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4374                                                         return false;
4375                                         } while (params_args_count-- > 0);
4376                                         continue;
4377                                 }
4378
4379                                 a = (Argument) arguments [argument_index++];
4380
4381                                 Parameter.Modifier a_mod = a.Modifier & 
4382                                         (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4383                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4384                                         (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4385
4386                                 if (a_mod == p_mod) {
4387
4388                                         if (a_mod == Parameter.Modifier.NONE)
4389                                                 if (!Convert.ImplicitConversionExists (ec,
4390                                                         a.Expr,
4391                                                         pd.ParameterType (i)))
4392                                                         return false;
4393
4394                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4395                                                 Type pt = pd.ParameterType (i);
4396
4397                                                 if (!pt.IsByRef)
4398                                                         pt = TypeManager.GetReferenceType (pt);
4399                                                 
4400                                                 if (pt != a.Type)
4401                                                         return false;
4402                                         }
4403                                 } else
4404                                         return false;
4405                                 
4406                         }
4407
4408                         return true;
4409                 }
4410
4411                 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4412                                                  ArrayList arguments, int arg_count,
4413                                                  ref MethodBase candidate)
4414                 {
4415 #if GMCS_SOURCE
4416                         if (!me.HasTypeArguments &&
4417                             !TypeManager.InferTypeArguments (arguments, ref candidate))
4418                                 return false;
4419
4420                         if (TypeManager.IsGenericMethodDefinition (candidate))
4421                                 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4422 #endif
4423
4424                         return IsApplicable (ec, arguments, arg_count, candidate);
4425                 }
4426
4427                 /// <summary>
4428                 ///   Determines if the candidate method is applicable (section 14.4.2.1)
4429                 ///   to the given set of arguments
4430                 /// </summary>
4431                 public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4432                         MethodBase candidate)
4433                 {
4434                         ParameterData pd = TypeManager.GetParameterData (candidate);
4435
4436                         if (arg_count != pd.Count)
4437                                 return false;
4438
4439                         for (int i = arg_count; i > 0; ) {
4440                                 i--;
4441
4442                                 Argument a = (Argument) arguments [i];
4443
4444                                 Parameter.Modifier a_mod = a.Modifier &
4445                                         ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4446
4447                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4448                                         ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
4449
4450                                 if (a_mod == p_mod) {
4451                                         Type pt = pd.ParameterType (i);
4452
4453                                         if (a_mod == Parameter.Modifier.NONE) {
4454                                                 if (!TypeManager.IsEqual (a.Type, pt) &&
4455                                                     !Convert.ImplicitConversionExists (ec, a.Expr, pt))
4456                                                         return false;
4457                                                 continue;
4458                                         }
4459                                         
4460                                         if (pt != a.Type)
4461                                                 return false;
4462                                 } else
4463                                         return false;
4464                         }
4465
4466                         return true;
4467                 }
4468
4469                 static internal bool IsAncestralType (Type first_type, Type second_type)
4470                 {
4471                         return first_type != second_type &&
4472                                 (TypeManager.IsSubclassOf (second_type, first_type) ||
4473                                  TypeManager.ImplementsInterface (second_type, first_type));
4474                 }
4475                 
4476                 /// <summary>
4477                 ///   Find the Applicable Function Members (7.4.2.1)
4478                 ///
4479                 ///   me: Method Group expression with the members to select.
4480                 ///       it might contain constructors or methods (or anything
4481                 ///       that maps to a method).
4482                 ///
4483                 ///   Arguments: ArrayList containing resolved Argument objects.
4484                 ///
4485                 ///   loc: The location if we want an error to be reported, or a Null
4486                 ///        location for "probing" purposes.
4487                 ///
4488                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4489                 ///            that is the best match of me on Arguments.
4490                 ///
4491                 /// </summary>
4492                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4493                                                           ArrayList Arguments, bool may_fail,
4494                                                           Location loc)
4495                 {
4496                         MethodBase method = null;
4497                         bool method_params = false;
4498                         Type applicable_type = null;
4499                         int arg_count = 0;
4500                         ArrayList candidates = new ArrayList (2);
4501                         ArrayList candidate_overrides = null;
4502
4503                         //
4504                         // Used to keep a map between the candidate
4505                         // and whether it is being considered in its
4506                         // normal or expanded form
4507                         //
4508                         // false is normal form, true is expanded form
4509                         //
4510                         Hashtable candidate_to_form = null;
4511
4512                         if (Arguments != null)
4513                                 arg_count = Arguments.Count;
4514
4515                         if ((me.Name == "Invoke") &&
4516                                 TypeManager.IsDelegateType (me.DeclaringType)) {
4517                                 Error_InvokeOnDelegate (loc);
4518                                 return null;
4519                         }
4520
4521                         MethodBase[] methods = me.Methods;
4522
4523                         int nmethods = methods.Length;
4524
4525                         if (!me.IsBase) {
4526                                 //
4527                                 // Methods marked 'override' don't take part in 'applicable_type'
4528                                 // computation, nor in the actual overload resolution.
4529                                 // However, they still need to be emitted instead of a base virtual method.
4530                                 // So, we salt them away into the 'candidate_overrides' array.
4531                                 //
4532                                 // In case of reflected methods, we replace each overriding method with
4533                                 // its corresponding base virtual method.  This is to improve compatibility
4534                                 // with non-C# libraries which change the visibility of overrides (#75636)
4535                                 //
4536                                 int j = 0;
4537                                 for (int i = 0; i < methods.Length; ++i) {
4538                                         MethodBase m = methods [i];
4539 #if GMCS_SOURCE
4540                                         Type [] gen_args = null;
4541                                         if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
4542                                                 gen_args = m.GetGenericArguments ();
4543 #endif
4544                                         if (TypeManager.IsOverride (m)) {
4545                                                 if (candidate_overrides == null)
4546                                                         candidate_overrides = new ArrayList ();
4547                                                 candidate_overrides.Add (m);
4548                                                 m = TypeManager.TryGetBaseDefinition (m);
4549 #if GMCS_SOURCE
4550                                                 if (m != null && gen_args != null) {
4551                                                         if (!m.IsGenericMethodDefinition)
4552                                                                 throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
4553                                                         m = ((MethodInfo) m).MakeGenericMethod (gen_args);
4554                                                 }
4555 #endif
4556                                         }
4557                                         if (m != null)
4558                                                 methods [j++] = m;
4559                                 }
4560                                 nmethods = j;
4561                         }
4562
4563                         int applicable_errors = Report.Errors;
4564                         
4565                         //
4566                         // First we construct the set of applicable methods
4567                         //
4568                         bool is_sorted = true;
4569                         for (int i = 0; i < nmethods; i++){
4570                                 Type decl_type = methods [i].DeclaringType;
4571
4572                                 //
4573                                 // If we have already found an applicable method
4574                                 // we eliminate all base types (Section 14.5.5.1)
4575                                 //
4576                                 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4577                                         continue;
4578
4579                                 //
4580                                 // Check if candidate is applicable (section 14.4.2.1)
4581                                 //   Is candidate applicable in normal form?
4582                                 //
4583                                 bool is_applicable = IsApplicable (ec, me, Arguments, arg_count, ref methods [i]);
4584
4585                                 if (!is_applicable && IsParamsMethodApplicable (ec, me, Arguments, arg_count, ref methods [i])) {
4586                                         MethodBase candidate = methods [i];
4587                                         if (candidate_to_form == null)
4588                                                 candidate_to_form = new PtrHashtable ();
4589                                         candidate_to_form [candidate] = candidate;
4590                                         // Candidate is applicable in expanded form
4591                                         is_applicable = true;
4592                                 }
4593
4594                                 if (!is_applicable)
4595                                         continue;
4596
4597                                 candidates.Add (methods [i]);
4598
4599                                 if (applicable_type == null)
4600                                         applicable_type = decl_type;
4601                                 else if (applicable_type != decl_type) {
4602                                         is_sorted = false;
4603                                         if (IsAncestralType (applicable_type, decl_type))
4604                                                 applicable_type = decl_type;
4605                                 }
4606                         }
4607
4608                         if (applicable_errors != Report.Errors)
4609                                 return null;
4610                         
4611                         int candidate_top = candidates.Count;
4612
4613                         if (applicable_type == null) {
4614                                 //
4615                                 // Okay so we have failed to find anything so we
4616                                 // return by providing info about the closest match
4617                                 //
4618                                 int errors = Report.Errors;
4619                                 for (int i = 0; i < nmethods; ++i) {
4620                                         MethodBase c = (MethodBase) methods [i];
4621                                         ParameterData pd = TypeManager.GetParameterData (c);
4622
4623                                         if (pd.Count != arg_count)
4624                                                 continue;
4625
4626 #if GMCS_SOURCE
4627                                         if (!TypeManager.InferTypeArguments (Arguments, ref c))
4628                                                 continue;
4629                                         if (TypeManager.IsGenericMethodDefinition (c))
4630                                                 continue;
4631 #endif
4632
4633                                         VerifyArgumentsCompat (ec, Arguments, arg_count,
4634                                                 c, false, null, may_fail, loc);
4635
4636                                         if (!may_fail && errors == Report.Errors)
4637                                                 throw new InternalErrorException (
4638                                                         "VerifyArgumentsCompat and IsApplicable do not agree; " +
4639                                                         "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
4640
4641                                         break;
4642                                 }
4643
4644                                 if (!may_fail && errors == Report.Errors) {
4645                                         string report_name = me.Name;
4646                                         if (report_name == ".ctor")
4647                                                 report_name = TypeManager.CSharpName (me.DeclaringType);
4648                                         
4649 #if GMCS_SOURCE
4650                                         //
4651                                         // Type inference
4652                                         //
4653                                         for (int i = 0; i < methods.Length; ++i) {
4654                                                 MethodBase c = methods [i];
4655                                                 ParameterData pd = TypeManager.GetParameterData (c);
4656
4657                                                 if (pd.Count != arg_count)
4658                                                         continue;
4659
4660                                                 if (TypeManager.InferTypeArguments (Arguments, ref c))
4661                                                         continue;
4662
4663                                                 Report.Error (
4664                                                         411, loc, "The type arguments for " +
4665                                                         "method `{0}' cannot be inferred from " +
4666                                                         "the usage. Try specifying the type " +
4667                                                         "arguments explicitly.", report_name);
4668                                                 return null;
4669                                         }
4670 #endif
4671
4672                                         Error_WrongNumArguments (loc, report_name, arg_count);
4673                                 }
4674                                 
4675                                 return null;
4676                         }
4677
4678                         if (!is_sorted) {
4679                                 //
4680                                 // At this point, applicable_type is _one_ of the most derived types
4681                                 // in the set of types containing the methods in this MethodGroup.
4682                                 // Filter the candidates so that they only contain methods from the
4683                                 // most derived types.
4684                                 //
4685
4686                                 int finalized = 0; // Number of finalized candidates
4687
4688                                 do {
4689                                         // Invariant: applicable_type is a most derived type
4690                                         
4691                                         // We'll try to complete Section 14.5.5.1 for 'applicable_type' by 
4692                                         // eliminating all it's base types.  At the same time, we'll also move
4693                                         // every unrelated type to the end of the array, and pick the next
4694                                         // 'applicable_type'.
4695
4696                                         Type next_applicable_type = null;
4697                                         int j = finalized; // where to put the next finalized candidate
4698                                         int k = finalized; // where to put the next undiscarded candidate
4699                                         for (int i = finalized; i < candidate_top; ++i) {
4700                                                 MethodBase candidate = (MethodBase) candidates [i];
4701                                                 Type decl_type = candidate.DeclaringType;
4702
4703                                                 if (decl_type == applicable_type) {
4704                                                         candidates [k++] = candidates [j];
4705                                                         candidates [j++] = candidates [i];
4706                                                         continue;
4707                                                 }
4708
4709                                                 if (IsAncestralType (decl_type, applicable_type))
4710                                                         continue;
4711
4712                                                 if (next_applicable_type != null &&
4713                                                     IsAncestralType (decl_type, next_applicable_type))
4714                                                         continue;
4715
4716                                                 candidates [k++] = candidates [i];
4717
4718                                                 if (next_applicable_type == null ||
4719                                                     IsAncestralType (next_applicable_type, decl_type))
4720                                                         next_applicable_type = decl_type;
4721                                         }
4722
4723                                         applicable_type = next_applicable_type;
4724                                         finalized = j;
4725                                         candidate_top = k;
4726                                 } while (applicable_type != null);
4727                         }
4728
4729                         //
4730                         // Now we actually find the best method
4731                         //
4732
4733                         method = (MethodBase) candidates [0];
4734                         method_params = candidate_to_form != null && candidate_to_form.Contains (method);
4735                         for (int ix = 1; ix < candidate_top; ix++){
4736                                 MethodBase candidate = (MethodBase) candidates [ix];
4737
4738                                 if (candidate == method)
4739                                         continue;
4740
4741                                 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4742
4743                                 if (BetterFunction (ec, Arguments, arg_count, 
4744                                                     candidate, cand_params,
4745                                                     method, method_params)) {
4746                                         method = candidate;
4747                                         method_params = cand_params;
4748                                 }
4749                         }
4750                         //
4751                         // Now check that there are no ambiguities i.e the selected method
4752                         // should be better than all the others
4753                         //
4754                         MethodBase ambiguous = null;
4755                         for (int ix = 0; ix < candidate_top; ix++){
4756                                 MethodBase candidate = (MethodBase) candidates [ix];
4757
4758                                 if (candidate == method)
4759                                         continue;
4760
4761                                 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4762                                 if (!BetterFunction (ec, Arguments, arg_count,
4763                                                      method, method_params,
4764                                                      candidate, cand_params)) {
4765                                         Report.SymbolRelatedToPreviousError (candidate);
4766                                         ambiguous = candidate;
4767                                 }
4768                         }
4769
4770                         if (ambiguous != null) {
4771                                 Report.SymbolRelatedToPreviousError (method);
4772                                 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4773                                         TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method));
4774                                 return null;
4775                         }
4776
4777                         //
4778                         // If the method is a virtual function, pick an override closer to the LHS type.
4779                         //
4780                         if (!me.IsBase && method.IsVirtual) {
4781                                 if (TypeManager.IsOverride (method))
4782                                         throw new InternalErrorException (
4783                                                 "Should not happen.  An 'override' method took part in overload resolution: " + method);
4784
4785                                 if (candidate_overrides != null)
4786                                         foreach (MethodBase candidate in candidate_overrides) {
4787                                                 if (IsOverride (candidate, method))
4788                                                         method = candidate;
4789                                         }
4790                         }
4791
4792                         //
4793                         // And now check if the arguments are all
4794                         // compatible, perform conversions if
4795                         // necessary etc. and return if everything is
4796                         // all right
4797                         //
4798                         if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method,
4799                                                     method_params, null, may_fail, loc))
4800                                 return null;
4801
4802                         if (method == null)
4803                                 return null;
4804
4805                         MethodBase the_method = TypeManager.DropGenericMethodArguments (method);
4806 #if GMCS_SOURCE
4807                         if (the_method.IsGenericMethodDefinition &&
4808                             !ConstraintChecker.CheckConstraints (ec, the_method, method, loc))
4809                                 return null;
4810 #endif
4811
4812                         IMethodData data = TypeManager.GetMethod (the_method);
4813                         if (data != null)
4814                                 data.SetMemberIsUsed ();
4815
4816                         return method;
4817                 }
4818
4819                 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4820                 {
4821                         Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4822                                 name, arg_count.ToString ());
4823                 }
4824
4825                 static void Error_InvokeOnDelegate (Location loc)
4826                 {
4827                         Report.Error (1533, loc,
4828                                       "Invoke cannot be called directly on a delegate");
4829                 }
4830                         
4831                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4832                                                     Type delegate_type, Argument a, ParameterData expected_par)
4833                 {
4834                         if (delegate_type == null) 
4835                                 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4836                                               TypeManager.CSharpSignature (method));
4837                         else
4838                                 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4839                                         TypeManager.CSharpName (delegate_type));
4840
4841                         Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4842
4843                         string index = (idx + 1).ToString ();
4844                         if (mod != Parameter.Modifier.ARGLIST && mod != a.Modifier) {
4845                                 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4846                                         Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4847                                                 index, Parameter.GetModifierSignature (a.Modifier));
4848                                 else
4849                                         Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4850                                                 index, Parameter.GetModifierSignature (mod));
4851                         } else {
4852                                 string p1 = Argument.FullDesc (a);
4853                                 string p2 = expected_par.ParameterDesc (idx);
4854
4855                                 if (p1 == p2) {
4856                                         Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4857                                         Report.SymbolRelatedToPreviousError (a.Expr.Type);
4858                                         Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4859                                 }
4860                                 Report.Error (1503, loc, "Argument {0}: Cannot convert from `{1}' to `{2}'", index, p1, p2);
4861                         }
4862                 }
4863                 
4864                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4865                                                           int arg_count, MethodBase method, 
4866                                                           bool chose_params_expanded,
4867                                                           Type delegate_type, bool may_fail,
4868                                                           Location loc)
4869                 {
4870                         ParameterData pd = TypeManager.GetParameterData (method);
4871                         int j;
4872                         int a_idx = 0;
4873                         Argument a = null;
4874                         for (j = 0; j < pd.Count; j++) {
4875                                 Type parameter_type = pd.ParameterType (j);
4876                                 Parameter.Modifier pm = pd.ParameterModifier (j);
4877
4878                                 if (pm == Parameter.Modifier.ARGLIST) {
4879                                         a = (Argument) Arguments [a_idx];
4880                                         if (!(a.Expr is Arglist))
4881                                                 break;
4882                                         ++a_idx;
4883                                         continue;
4884                                 }
4885
4886                                 int params_arg_count = 1;
4887                                 if (pm == Parameter.Modifier.PARAMS) {
4888                                         pm = Parameter.Modifier.NONE;
4889                                         params_arg_count = arg_count - pd.Count + 1;
4890                                         if (chose_params_expanded)
4891                                                 parameter_type = TypeManager.GetElementType (parameter_type);
4892                                 }
4893
4894                                 while (params_arg_count > 0) {
4895                                         a = (Argument) Arguments [a_idx];
4896                                         if (pm != a.Modifier)
4897                                                 break;
4898
4899                                         if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4900                                                 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4901                                                         break;
4902
4903                                                 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4904                                                 if (conv == null)
4905                                                         break;
4906
4907                                                 // Update the argument with the implicit conversion
4908                                                 if (a.Expr != conv)
4909                                                         a.Expr = conv;
4910                                         }
4911
4912                                         --params_arg_count;
4913                                         ++a_idx;
4914                                 }
4915                                 if (params_arg_count > 0)
4916                                         break;
4917
4918                                 if (parameter_type.IsPointer && !ec.InUnsafe) {
4919                                         UnsafeError (loc);
4920                                         return false;
4921                                 }
4922                         }
4923
4924                         if (a_idx == arg_count)
4925                                 return true;
4926
4927                         if (!may_fail)
4928                                 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4929                         return false;
4930                 }
4931
4932                 private bool resolved = false;
4933                 public override Expression DoResolve (EmitContext ec)
4934                 {
4935                         if (resolved)
4936                                 return this.method == null ? null : this;
4937
4938                         resolved = true;
4939                         //
4940                         // First, resolve the expression that is used to
4941                         // trigger the invocation
4942                         //
4943                         SimpleName sn = expr as SimpleName;
4944                         if (sn != null)
4945                                 expr = sn.GetMethodGroup ();
4946
4947                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4948                         if (expr == null)
4949                                 return null;
4950
4951                         if (!(expr is MethodGroupExpr)) {
4952                                 Type expr_type = expr.Type;
4953
4954                                 if (expr_type != null){
4955                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
4956                                         if (IsDelegate)
4957                                                 return (new DelegateInvocation (
4958                                                         this.expr, Arguments, loc)).Resolve (ec);
4959                                 }
4960                         }
4961
4962                         if (!(expr is MethodGroupExpr)){
4963                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4964                                 return null;
4965                         }
4966
4967                         //
4968                         // Next, evaluate all the expressions in the argument list
4969                         //
4970                         if (Arguments != null){
4971                                 foreach (Argument a in Arguments){
4972                                         if (!a.Resolve (ec, loc))
4973                                                 return null;
4974                                 }
4975                         }
4976
4977                         MethodGroupExpr mg = (MethodGroupExpr) expr;
4978                         MethodBase method = OverloadResolve (ec, mg, Arguments, false, loc);
4979
4980                         if (method == null)
4981                                 return null;
4982
4983                         MethodInfo mi = method as MethodInfo;
4984                         if (mi != null) {
4985                                 type = TypeManager.TypeToCoreType (mi.ReturnType);
4986                                 Expression iexpr = mg.InstanceExpression;
4987                                 if (mi.IsStatic) {
4988                                         if (iexpr == null || 
4989                                             iexpr is This || iexpr is EmptyExpression ||
4990                                             mg.IdenticalTypeName) {
4991                                                 mg.InstanceExpression = null;
4992                                         } else {
4993                                                 MemberExpr.error176 (loc, TypeManager.CSharpSignature (mi));
4994                                                 return null;
4995                                         }
4996                                 } else {
4997                                         if (iexpr == null || iexpr is EmptyExpression) {
4998                                                 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (mi));
4999                                                 return null;
5000                                         }
5001                                 }
5002                         }
5003
5004                         if (type.IsPointer){
5005                                 if (!ec.InUnsafe){
5006                                         UnsafeError (loc);
5007                                         return null;
5008                                 }
5009                         }
5010                         
5011                         //
5012                         // Only base will allow this invocation to happen.
5013                         //
5014                         if (mg.IsBase && method.IsAbstract){
5015                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
5016                                 return null;
5017                         }
5018
5019                         if (Arguments == null && method.Name == "Finalize") {
5020                                 if (mg.IsBase)
5021                                         Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5022                                 else
5023                                         Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5024                                 return null;
5025                         }
5026
5027                         if (IsSpecialMethodInvocation (method)) {
5028                                 return null;
5029                         }
5030                         
5031                         if (mg.InstanceExpression != null){
5032                                 mg.InstanceExpression.CheckMarshalByRefAccess ();
5033
5034                                 //
5035                                 // This is used to check that no methods are called in struct
5036                                 // constructors before all the fields on the struct have been
5037                                 // initialized.
5038                                 //
5039                                 if (!method.IsStatic){
5040                                         This mgthis = mg.InstanceExpression as This;
5041                                         if (mgthis != null){
5042                                                 if (!mgthis.CheckThisUsage (ec))
5043                                                         return  null;
5044                                         }
5045                                 }
5046                         }
5047
5048                         eclass = ExprClass.Value;
5049                         this.method = method;
5050                         return this;
5051                 }
5052
5053                 bool IsSpecialMethodInvocation (MethodBase method)
5054                 {
5055                         if (!TypeManager.IsSpecialMethod (method))
5056                                 return false;
5057
5058                         Report.SymbolRelatedToPreviousError (method);
5059                         Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5060                                 TypeManager.CSharpSignature (method, true));
5061         
5062                         return true;
5063                 }
5064
5065                 // <summary>
5066                 //   Emits the list of arguments as an array
5067                 // </summary>
5068                 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
5069                 {
5070                         ILGenerator ig = ec.ig;
5071                         Type t = null;
5072                         for (int j = 0; j < count; j++){
5073                                 Argument a = (Argument) arguments [j + idx];
5074                                 if (j == 0) {
5075                                         t = a.Expr.Type;
5076                                         IntConstant.EmitInt (ig, count);
5077                                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5078                                 }
5079                                 
5080                                 ig.Emit (OpCodes.Dup);
5081                                 IntConstant.EmitInt (ig, j);
5082
5083                                 bool is_stobj, has_type_arg;
5084                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
5085                                 if (is_stobj)
5086                                         ig.Emit (OpCodes.Ldelema, t);
5087
5088                                 a.Emit (ec);
5089
5090                                 if (has_type_arg)
5091                                         ig.Emit (op, t);
5092                                 else
5093                                         ig.Emit (op);
5094                         }
5095                 }
5096                 
5097                 /// <summary>
5098                 ///   Emits a list of resolved Arguments that are in the arguments
5099                 ///   ArrayList.
5100                 /// 
5101                 ///   The MethodBase argument might be null if the
5102                 ///   emission of the arguments is known not to contain
5103                 ///   a `params' field (for example in constructors or other routines
5104                 ///   that keep their arguments in this structure)
5105                 ///   
5106                 ///   if `dup_args' is true, a copy of the arguments will be left
5107                 ///   on the stack. If `dup_args' is true, you can specify `this_arg'
5108                 ///   which will be duplicated before any other args. Only EmitCall
5109                 ///   should be using this interface.
5110                 /// </summary>
5111                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
5112                 {
5113                         ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
5114                         int top = pd.Count;
5115                         LocalTemporary [] temps = null;
5116                         
5117                         if (dup_args && top != 0)
5118                                 temps = new LocalTemporary [top];
5119
5120                         int argument_index = 0;
5121                         Argument a;
5122                         for (int i = 0; i < top; i++){
5123                                 if (pd != null){
5124                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5125                                                 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
5126                                                 int params_args_count = arguments == null ?
5127                                                         0 : arguments.Count - top + 1;
5128
5129                                                 // Fill not provided argument
5130                                                 if (params_args_count <= 0) {
5131                                                         ILGenerator ig = ec.ig;
5132                                                         IntConstant.EmitInt (ig, 0);
5133                                                         ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
5134                                                         continue;
5135                                                 }
5136
5137                                                 //
5138                                                 // Special case if we are passing the same data as the
5139                                                 // params argument, we do not need to recreate an array.
5140                                                 //
5141                                                 a = (Argument) arguments [argument_index];
5142                                                 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
5143                                                         ++argument_index;
5144                                                         a.Emit (ec);
5145                                                         continue;
5146                                                 }
5147
5148                                                 EmitParams (ec, arguments, i, params_args_count);
5149                                                 argument_index += params_args_count;
5150                                                 continue;
5151                                         }
5152                                 }
5153
5154                                 a = (Argument) arguments [argument_index++];
5155                                 a.Emit (ec);
5156                                 if (dup_args) {
5157                                         ec.ig.Emit (OpCodes.Dup);
5158                                         (temps [i] = new LocalTemporary (a.Type)).Store (ec);
5159                                 }
5160                         }
5161                         
5162                         if (dup_args) {
5163                                 if (this_arg != null)
5164                                         this_arg.Emit (ec);
5165                                 
5166                                 for (int i = 0; i < top; i ++) {
5167                                         temps [i].Emit (ec);
5168                                         temps [i].Release (ec);
5169                                 }
5170                         }
5171                 }
5172
5173                 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
5174                 {
5175                         ParameterData pd = TypeManager.GetParameterData (mb);
5176
5177                         if (arguments == null)
5178                                 return new Type [0];
5179
5180                         Argument a = (Argument) arguments [pd.Count - 1];
5181                         Arglist list = (Arglist) a.Expr;
5182
5183                         return list.ArgumentTypes;
5184                 }
5185
5186                 /// <summary>
5187                 /// This checks the ConditionalAttribute on the method 
5188                 /// </summary>
5189                 static bool IsMethodExcluded (MethodBase method)
5190                 {
5191                         if (method.IsConstructor)
5192                                 return false;
5193
5194                         IMethodData md = TypeManager.GetMethod (method);
5195                         if (md != null)
5196                                 return md.IsExcluded ();
5197
5198                         // For some methods (generated by delegate class) GetMethod returns null
5199                         // because they are not included in builder_to_method table
5200                         if (method.DeclaringType is TypeBuilder)
5201                                 return false;
5202
5203                         return AttributeTester.IsConditionalMethodExcluded (method);
5204                 }
5205
5206                 /// <remarks>
5207                 ///   is_base tells whether we want to force the use of the `call'
5208                 ///   opcode instead of using callvirt.  Call is required to call
5209                 ///   a specific method, while callvirt will always use the most
5210                 ///   recent method in the vtable.
5211                 ///
5212                 ///   is_static tells whether this is an invocation on a static method
5213                 ///
5214                 ///   instance_expr is an expression that represents the instance
5215                 ///   it must be non-null if is_static is false.
5216                 ///
5217                 ///   method is the method to invoke.
5218                 ///
5219                 ///   Arguments is the list of arguments to pass to the method or constructor.
5220                 /// </remarks>
5221                 public static void EmitCall (EmitContext ec, bool is_base,
5222                                              bool is_static, Expression instance_expr,
5223                                              MethodBase method, ArrayList Arguments, Location loc)
5224                 {
5225                         EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
5226                 }
5227                 
5228                 // `dup_args' leaves an extra copy of the arguments on the stack
5229                 // `omit_args' does not leave any arguments at all.
5230                 // So, basically, you could make one call with `dup_args' set to true,
5231                 // and then another with `omit_args' set to true, and the two calls
5232                 // would have the same set of arguments. However, each argument would
5233                 // only have been evaluated once.
5234                 public static void EmitCall (EmitContext ec, bool is_base,
5235                                              bool is_static, Expression instance_expr,
5236                                              MethodBase method, ArrayList Arguments, Location loc,
5237                                              bool dup_args, bool omit_args)
5238                 {
5239                         ILGenerator ig = ec.ig;
5240                         bool struct_call = false;
5241                         bool this_call = false;
5242                         LocalTemporary this_arg = null;
5243
5244                         Type decl_type = method.DeclaringType;
5245
5246                         if (!RootContext.StdLib) {
5247                                 // Replace any calls to the system's System.Array type with calls to
5248                                 // the newly created one.
5249                                 if (method == TypeManager.system_int_array_get_length)
5250                                         method = TypeManager.int_array_get_length;
5251                                 else if (method == TypeManager.system_int_array_get_rank)
5252                                         method = TypeManager.int_array_get_rank;
5253                                 else if (method == TypeManager.system_object_array_clone)
5254                                         method = TypeManager.object_array_clone;
5255                                 else if (method == TypeManager.system_int_array_get_length_int)
5256                                         method = TypeManager.int_array_get_length_int;
5257                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5258                                         method = TypeManager.int_array_get_lower_bound_int;
5259                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5260                                         method = TypeManager.int_array_get_upper_bound_int;
5261                                 else if (method == TypeManager.system_void_array_copyto_array_int)
5262                                         method = TypeManager.void_array_copyto_array_int;
5263                         }
5264
5265                         if (!ec.IsInObsoleteScope) {
5266                                 //
5267                                 // This checks ObsoleteAttribute on the method and on the declaring type
5268                                 //
5269                                 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
5270                                 if (oa != null)
5271                                         AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
5272
5273                                 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5274                                 if (oa != null) {
5275                                         AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5276                                 }
5277                         }
5278
5279                         if (IsMethodExcluded (method))
5280                                 return;
5281                         
5282                         if (!is_static){
5283                                 if (instance_expr == EmptyExpression.Null) {
5284                                         SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
5285                                         return;
5286                                 }
5287
5288                                 this_call = instance_expr is This;
5289                                 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5290                                         struct_call = true;
5291
5292                                 //
5293                                 // If this is ourselves, push "this"
5294                                 //
5295                                 if (!omit_args) {
5296                                         Type t = null;
5297                                         Type iexpr_type = instance_expr.Type;
5298
5299                                         //
5300                                         // Push the instance expression
5301                                         //
5302                                         if (TypeManager.IsValueType (iexpr_type)) {
5303                                                 //
5304                                                 // Special case: calls to a function declared in a 
5305                                                 // reference-type with a value-type argument need
5306                                                 // to have their value boxed.
5307                                                 if (decl_type.IsValueType ||
5308                                                     TypeManager.IsGenericParameter (iexpr_type)) {
5309                                                         //
5310                                                         // If the expression implements IMemoryLocation, then
5311                                                         // we can optimize and use AddressOf on the
5312                                                         // return.
5313                                                         //
5314                                                         // If not we have to use some temporary storage for
5315                                                         // it.
5316                                                         if (instance_expr is IMemoryLocation) {
5317                                                                 ((IMemoryLocation)instance_expr).
5318                                                                         AddressOf (ec, AddressOp.LoadStore);
5319                                                         } else {
5320                                                                 LocalTemporary temp = new LocalTemporary (iexpr_type);
5321                                                                 instance_expr.Emit (ec);
5322                                                                 temp.Store (ec);
5323                                                                 temp.AddressOf (ec, AddressOp.Load);
5324                                                         }
5325
5326                                                         // avoid the overhead of doing this all the time.
5327                                                         if (dup_args)
5328                                                                 t = TypeManager.GetReferenceType (iexpr_type);
5329                                                 } else {
5330                                                         instance_expr.Emit (ec);
5331                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
5332                                                         t = TypeManager.object_type;
5333                                                 }
5334                                         } else {
5335                                                 instance_expr.Emit (ec);
5336                                                 t = instance_expr.Type;
5337                                         }
5338
5339                                         if (dup_args) {
5340                                                 ig.Emit (OpCodes.Dup);
5341                                                 if (Arguments != null && Arguments.Count != 0) {
5342                                                         this_arg = new LocalTemporary (t);
5343                                                         this_arg.Store (ec);
5344                                                 }
5345                                         }
5346                                 }
5347                         }
5348
5349                         if (!omit_args)
5350                                 EmitArguments (ec, method, Arguments, dup_args, this_arg);
5351
5352 #if GMCS_SOURCE
5353                         if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5354                                 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5355 #endif
5356
5357                         OpCode call_op;
5358                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5359                                 call_op = OpCodes.Call;
5360                         else
5361                                 call_op = OpCodes.Callvirt;
5362
5363                         if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5364                                 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5365                                 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5366                                 return;
5367                         }
5368
5369                         //
5370                         // If you have:
5371                         // this.DoFoo ();
5372                         // and DoFoo is not virtual, you can omit the callvirt,
5373                         // because you don't need the null checking behavior.
5374                         //
5375                         if (method is MethodInfo)
5376                                 ig.Emit (call_op, (MethodInfo) method);
5377                         else
5378                                 ig.Emit (call_op, (ConstructorInfo) method);
5379                 }
5380                 
5381                 public override void Emit (EmitContext ec)
5382                 {
5383                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5384
5385                         EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5386                 }
5387                 
5388                 public override void EmitStatement (EmitContext ec)
5389                 {
5390                         Emit (ec);
5391
5392                         // 
5393                         // Pop the return value if there is one
5394                         //
5395                         if (method is MethodInfo){
5396                                 Type ret = ((MethodInfo)method).ReturnType;
5397                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5398                                         ec.ig.Emit (OpCodes.Pop);
5399                         }
5400                 }
5401         }
5402
5403         public class InvocationOrCast : ExpressionStatement
5404         {
5405                 Expression expr;
5406                 Expression argument;
5407
5408                 public InvocationOrCast (Expression expr, Expression argument)
5409                 {
5410                         this.expr = expr;
5411                         this.argument = argument;
5412                         this.loc = expr.Location;
5413                 }
5414
5415                 public override Expression DoResolve (EmitContext ec)
5416                 {
5417                         //
5418                         // First try to resolve it as a cast.
5419                         //
5420                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5421                         if ((te != null) && (te.eclass == ExprClass.Type)) {
5422                                 Cast cast = new Cast (te, argument, loc);
5423                                 return cast.Resolve (ec);
5424                         }
5425
5426                         //
5427                         // This can either be a type or a delegate invocation.
5428                         // Let's just resolve it and see what we'll get.
5429                         //
5430                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5431                         if (expr == null)
5432                                 return null;
5433
5434                         //
5435                         // Ok, so it's a Cast.
5436                         //
5437                         if (expr.eclass == ExprClass.Type) {
5438                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5439                                 return cast.Resolve (ec);
5440                         }
5441
5442                         //
5443                         // It's a delegate invocation.
5444                         //
5445                         if (!TypeManager.IsDelegateType (expr.Type)) {
5446                                 Error (149, "Method name expected");
5447                                 return null;
5448                         }
5449
5450                         ArrayList args = new ArrayList ();
5451                         args.Add (new Argument (argument, Argument.AType.Expression));
5452                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5453                         return invocation.Resolve (ec);
5454                 }
5455
5456                 void error201 ()
5457                 {
5458                         Error (201, "Only assignment, call, increment, decrement and new object " +
5459                                "expressions can be used as a statement");
5460                 }
5461
5462                 public override ExpressionStatement ResolveStatement (EmitContext ec)
5463                 {
5464                         //
5465                         // First try to resolve it as a cast.
5466                         //
5467                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5468                         if ((te != null) && (te.eclass == ExprClass.Type)) {
5469                                 error201 ();
5470                                 return null;
5471                         }
5472
5473                         //
5474                         // This can either be a type or a delegate invocation.
5475                         // Let's just resolve it and see what we'll get.
5476                         //
5477                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5478                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5479                                 error201 ();
5480                                 return null;
5481                         }
5482
5483                         //
5484                         // It's a delegate invocation.
5485                         //
5486                         if (!TypeManager.IsDelegateType (expr.Type)) {
5487                                 Error (149, "Method name expected");
5488                                 return null;
5489                         }
5490
5491                         ArrayList args = new ArrayList ();
5492                         args.Add (new Argument (argument, Argument.AType.Expression));
5493                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5494                         return invocation.ResolveStatement (ec);
5495                 }
5496
5497                 public override void Emit (EmitContext ec)
5498                 {
5499                         throw new Exception ("Cannot happen");
5500                 }
5501
5502                 public override void EmitStatement (EmitContext ec)
5503                 {
5504                         throw new Exception ("Cannot happen");
5505                 }
5506         }
5507
5508         //
5509         // This class is used to "disable" the code generation for the
5510         // temporary variable when initializing value types.
5511         //
5512         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5513                 public void AddressOf (EmitContext ec, AddressOp Mode)
5514                 {
5515                         // nothing
5516                 }
5517         }
5518         
5519         /// <summary>
5520         ///    Implements the new expression 
5521         /// </summary>
5522         public class New : ExpressionStatement, IMemoryLocation {
5523                 public readonly ArrayList Arguments;
5524
5525                 //
5526                 // During bootstrap, it contains the RequestedType,
5527                 // but if `type' is not null, it *might* contain a NewDelegate
5528                 // (because of field multi-initialization)
5529                 //
5530                 public Expression RequestedType;
5531
5532                 MethodBase method = null;
5533
5534                 //
5535                 // If set, the new expression is for a value_target, and
5536                 // we will not leave anything on the stack.
5537                 //
5538                 Expression value_target;
5539                 bool value_target_set = false;
5540                 bool is_type_parameter = false;
5541                 
5542                 public New (Expression requested_type, ArrayList arguments, Location l)
5543                 {
5544                         RequestedType = requested_type;
5545                         Arguments = arguments;
5546                         loc = l;
5547                 }
5548
5549                 public bool SetValueTypeVariable (Expression value)
5550                 {
5551                         value_target = value;
5552                         value_target_set = true;
5553                         if (!(value_target is IMemoryLocation)){
5554                                 Error_UnexpectedKind (null, "variable", loc);
5555                                 return false;
5556                         }
5557                         return true;
5558                 }
5559
5560                 //
5561                 // This function is used to disable the following code sequence for
5562                 // value type initialization:
5563                 //
5564                 // AddressOf (temporary)
5565                 // Construct/Init
5566                 // LoadTemporary
5567                 //
5568                 // Instead the provide will have provided us with the address on the
5569                 // stack to store the results.
5570                 //
5571                 static Expression MyEmptyExpression;
5572                 
5573                 public void DisableTemporaryValueType ()
5574                 {
5575                         if (MyEmptyExpression == null)
5576                                 MyEmptyExpression = new EmptyAddressOf ();
5577
5578                         //
5579                         // To enable this, look into:
5580                         // test-34 and test-89 and self bootstrapping.
5581                         //
5582                         // For instance, we can avoid a copy by using `newobj'
5583                         // instead of Call + Push-temp on value types.
5584 //                      value_target = MyEmptyExpression;
5585                 }
5586
5587
5588                 /// <summary>
5589                 /// Converts complex core type syntax like 'new int ()' to simple constant
5590                 /// </summary>
5591                 public static Constant Constantify (Type t)
5592                 {
5593                         if (t == TypeManager.int32_type)
5594                                 return new IntConstant (0, Location.Null);
5595                         if (t == TypeManager.uint32_type)
5596                                 return new UIntConstant (0, Location.Null);
5597                         if (t == TypeManager.int64_type)
5598                                 return new LongConstant (0, Location.Null);
5599                         if (t == TypeManager.uint64_type)
5600                                 return new ULongConstant (0, Location.Null);
5601                         if (t == TypeManager.float_type)
5602                                 return new FloatConstant (0, Location.Null);
5603                         if (t == TypeManager.double_type)
5604                                 return new DoubleConstant (0, Location.Null);
5605                         if (t == TypeManager.short_type)
5606                                 return new ShortConstant (0, Location.Null);
5607                         if (t == TypeManager.ushort_type)
5608                                 return new UShortConstant (0, Location.Null);
5609                         if (t == TypeManager.sbyte_type)
5610                                 return new SByteConstant (0, Location.Null);
5611                         if (t == TypeManager.byte_type)
5612                                 return new ByteConstant (0, Location.Null);
5613                         if (t == TypeManager.char_type)
5614                                 return new CharConstant ('\0', Location.Null);
5615                         if (t == TypeManager.bool_type)
5616                                 return new BoolConstant (false, Location.Null);
5617                         if (t == TypeManager.decimal_type)
5618                                 return new DecimalConstant (0, Location.Null);
5619                         if (TypeManager.IsEnumType (t))
5620                                 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5621
5622                         return null;
5623                 }
5624
5625                 //
5626                 // Checks whether the type is an interface that has the
5627                 // [ComImport, CoClass] attributes and must be treated
5628                 // specially
5629                 //
5630                 public Expression CheckComImport (EmitContext ec)
5631                 {
5632                         if (!type.IsInterface)
5633                                 return null;
5634
5635                         //
5636                         // Turn the call into:
5637                         // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5638                         //
5639                         Type real_class = AttributeTester.GetCoClassAttribute (type);
5640                         if (real_class == null)
5641                                 return null;
5642
5643                         New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5644                         Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5645                         return cast.Resolve (ec);
5646                 }
5647                 
5648                 public override Expression DoResolve (EmitContext ec)
5649                 {
5650                         //
5651                         // The New DoResolve might be called twice when initializing field
5652                         // expressions (see EmitFieldInitializers, the call to
5653                         // GetInitializerExpression will perform a resolve on the expression,
5654                         // and later the assign will trigger another resolution
5655                         //
5656                         // This leads to bugs (#37014)
5657                         //
5658                         if (type != null){
5659                                 if (RequestedType is NewDelegate)
5660                                         return RequestedType;
5661                                 return this;
5662                         }
5663
5664                         TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5665                         if (texpr == null)
5666                                 return null;
5667
5668                         type = texpr.Type;
5669
5670                         if (type == TypeManager.void_type) {
5671                                 Error_VoidInvalidInTheContext (loc);
5672                                 return null;
5673                         }
5674
5675                         if (Arguments == null) {
5676                                 Expression c = Constantify (type);
5677                                 if (c != null)
5678                                         return c;
5679                         }
5680
5681                         if (TypeManager.IsDelegateType (type)) {
5682                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5683                                 if (RequestedType != null)
5684                                         if (!(RequestedType is DelegateCreation))
5685                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5686                                 return RequestedType;
5687                         }
5688
5689 #if GMCS_SOURCE
5690                         if (type.IsGenericParameter) {
5691                                 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5692
5693                                 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5694                                         Error (304, String.Format (
5695                                                        "Cannot create an instance of the " +
5696                                                        "variable type '{0}' because it " +
5697                                                        "doesn't have the new() constraint",
5698                                                        type));
5699                                         return null;
5700                                 }
5701
5702                                 if ((Arguments != null) && (Arguments.Count != 0)) {
5703                                         Error (417, String.Format (
5704                                                        "`{0}': cannot provide arguments " +
5705                                                        "when creating an instance of a " +
5706                                                        "variable type.", type));
5707                                         return null;
5708                                 }
5709
5710                                 is_type_parameter = true;
5711                                 eclass = ExprClass.Value;
5712                                 return this;
5713                         }
5714 #endif
5715
5716                         if (type.IsAbstract && type.IsSealed) {
5717                                 Report.SymbolRelatedToPreviousError (type);
5718                                 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5719                                 return null;
5720                         }
5721
5722                         if (type.IsInterface || type.IsAbstract){
5723                                 RequestedType = CheckComImport (ec);
5724                                 if (RequestedType != null)
5725                                         return RequestedType;
5726                                 
5727                                 Report.SymbolRelatedToPreviousError (type);
5728                                 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5729                                 return null;
5730                         }
5731
5732                         bool is_struct = type.IsValueType;
5733                         eclass = ExprClass.Value;
5734
5735                         //
5736                         // SRE returns a match for .ctor () on structs (the object constructor), 
5737                         // so we have to manually ignore it.
5738                         //
5739                         if (is_struct && Arguments == null)
5740                                 return this;
5741
5742                         // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5743                         Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5744                                 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5745
5746                         if (ml == null)
5747                                 return null;
5748
5749                         MethodGroupExpr mg = ml as MethodGroupExpr;
5750
5751                         if (mg == null) {
5752                                 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5753                                 return null;
5754                         }
5755
5756                         if (Arguments != null){
5757                                 foreach (Argument a in Arguments){
5758                                         if (!a.Resolve (ec, loc))
5759                                                 return null;
5760                                 }
5761                         }
5762
5763                         method = Invocation.OverloadResolve (ec, mg, Arguments, false, loc);
5764                         if (method == null) {
5765                                 if (almostMatchedMembers.Count != 0)
5766                                         MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
5767                                 return null;
5768                         }
5769
5770                         return this;
5771                 }
5772
5773                 bool DoEmitTypeParameter (EmitContext ec)
5774                 {
5775 #if GMCS_SOURCE
5776                         ILGenerator ig = ec.ig;
5777
5778                         ig.Emit (OpCodes.Ldtoken, type);
5779                         ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
5780                         ig.Emit (OpCodes.Call, TypeManager.activator_create_instance);
5781                         ig.Emit (OpCodes.Unbox_Any, type);
5782                         return true;
5783 #else
5784                         throw new InternalErrorException ();
5785 #endif
5786                 }
5787
5788                 //
5789                 // This DoEmit can be invoked in two contexts:
5790                 //    * As a mechanism that will leave a value on the stack (new object)
5791                 //    * As one that wont (init struct)
5792                 //
5793                 // You can control whether a value is required on the stack by passing
5794                 // need_value_on_stack.  The code *might* leave a value on the stack
5795                 // so it must be popped manually
5796                 //
5797                 // If we are dealing with a ValueType, we have a few
5798                 // situations to deal with:
5799                 //
5800                 //    * The target is a ValueType, and we have been provided
5801                 //      the instance (this is easy, we are being assigned).
5802                 //
5803                 //    * The target of New is being passed as an argument,
5804                 //      to a boxing operation or a function that takes a
5805                 //      ValueType.
5806                 //
5807                 //      In this case, we need to create a temporary variable
5808                 //      that is the argument of New.
5809                 //
5810                 // Returns whether a value is left on the stack
5811                 //
5812                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5813                 {
5814                         bool is_value_type = TypeManager.IsValueType (type);
5815                         ILGenerator ig = ec.ig;
5816
5817                         if (is_value_type){
5818                                 IMemoryLocation ml;
5819
5820                                 // Allow DoEmit() to be called multiple times.
5821                                 // We need to create a new LocalTemporary each time since
5822                                 // you can't share LocalBuilders among ILGeneators.
5823                                 if (!value_target_set)
5824                                         value_target = new LocalTemporary (type);
5825
5826                                 ml = (IMemoryLocation) value_target;
5827                                 ml.AddressOf (ec, AddressOp.Store);
5828                         }
5829
5830                         if (method != null)
5831                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
5832
5833                         if (is_value_type){
5834                                 if (method == null)
5835                                         ig.Emit (OpCodes.Initobj, type);
5836                                 else 
5837                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5838                                 if (need_value_on_stack){
5839                                         value_target.Emit (ec);
5840                                         return true;
5841                                 }
5842                                 return false;
5843                         } else {
5844                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5845                                 return true;
5846                         }
5847                 }
5848
5849                 public override void Emit (EmitContext ec)
5850                 {
5851                         if (is_type_parameter)
5852                                 DoEmitTypeParameter (ec);
5853                         else
5854                                 DoEmit (ec, true);
5855                 }
5856                 
5857                 public override void EmitStatement (EmitContext ec)
5858                 {
5859                         if (is_type_parameter)
5860                                 throw new InvalidOperationException ();
5861
5862                         if (DoEmit (ec, false))
5863                                 ec.ig.Emit (OpCodes.Pop);
5864                 }
5865
5866                 public void AddressOf (EmitContext ec, AddressOp Mode)
5867                 {
5868                         if (is_type_parameter)
5869                                 throw new InvalidOperationException ();
5870
5871                         if (!type.IsValueType){
5872                                 //
5873                                 // We throw an exception.  So far, I believe we only need to support
5874                                 // value types:
5875                                 // foreach (int j in new StructType ())
5876                                 // see bug 42390
5877                                 //
5878                                 throw new Exception ("AddressOf should not be used for classes");
5879                         }
5880
5881                         if (!value_target_set)
5882                                 value_target = new LocalTemporary (type);
5883                                         
5884                         IMemoryLocation ml = (IMemoryLocation) value_target;
5885                         ml.AddressOf (ec, AddressOp.Store);
5886                         if (method != null)
5887                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
5888
5889                         if (method == null)
5890                                 ec.ig.Emit (OpCodes.Initobj, type);
5891                         else 
5892                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5893                         
5894                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5895                 }
5896         }
5897
5898         /// <summary>
5899         ///   14.5.10.2: Represents an array creation expression.
5900         /// </summary>
5901         ///
5902         /// <remarks>
5903         ///   There are two possible scenarios here: one is an array creation
5904         ///   expression that specifies the dimensions and optionally the
5905         ///   initialization data and the other which does not need dimensions
5906         ///   specified but where initialization data is mandatory.
5907         /// </remarks>
5908         public class ArrayCreation : Expression {
5909                 Expression requested_base_type;
5910                 ArrayList initializers;
5911
5912                 //
5913                 // The list of Argument types.
5914                 // This is used to construct the `newarray' or constructor signature
5915                 //
5916                 ArrayList arguments;
5917
5918                 //
5919                 // Method used to create the array object.
5920                 //
5921                 MethodBase new_method = null;
5922                 
5923                 Type array_element_type;
5924                 Type underlying_type;
5925                 bool is_one_dimensional = false;
5926                 bool is_builtin_type = false;
5927                 bool expect_initializers = false;
5928                 int num_arguments = 0;
5929                 int dimensions = 0;
5930                 string rank;
5931
5932                 ArrayList array_data;
5933
5934                 IDictionary bounds;
5935
5936                 // The number of constants in array initializers
5937                 int const_initializers_count;
5938                 bool only_constant_initializers;
5939                 
5940                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5941                 {
5942                         this.requested_base_type = requested_base_type;
5943                         this.initializers = initializers;
5944                         this.rank = rank;
5945                         loc = l;
5946
5947                         arguments = new ArrayList ();
5948
5949                         foreach (Expression e in exprs) {
5950                                 arguments.Add (new Argument (e, Argument.AType.Expression));
5951                                 num_arguments++;
5952                         }
5953                 }
5954
5955                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5956                 {
5957                         this.requested_base_type = requested_base_type;
5958                         this.initializers = initializers;
5959                         this.rank = rank;
5960                         loc = l;
5961
5962                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5963                         //
5964                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
5965                         //
5966                         //dimensions = tmp.Length - 1;
5967                         expect_initializers = true;
5968                 }
5969
5970                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5971                 {
5972                         StringBuilder sb = new StringBuilder (rank);
5973                         
5974                         sb.Append ("[");
5975                         for (int i = 1; i < idx_count; i++)
5976                                 sb.Append (",");
5977                         
5978                         sb.Append ("]");
5979
5980                         return new ComposedCast (base_type, sb.ToString (), loc);
5981                 }
5982
5983                 void Error_IncorrectArrayInitializer ()
5984                 {
5985                         Error (178, "Invalid rank specifier: expected `,' or `]'");
5986                 }
5987                 
5988                 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5989                 {
5990                         if (specified_dims) { 
5991                                 Argument a = (Argument) arguments [idx];
5992
5993                                 if (!a.Resolve (ec, loc))
5994                                         return false;
5995
5996                                 Constant c = a.Expr as Constant;
5997                                 if (c != null) {
5998                                         c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5999                                 }
6000
6001                                 if (c == null) {
6002                                         Report.Error (150, a.Expr.Location, "A constant value is expected");
6003                                         return false;
6004                                 }
6005
6006                                 int value = (int) c.GetValue ();
6007                                 
6008                                 if (value != probe.Count) {
6009                                         Error_IncorrectArrayInitializer ();
6010                                         return false;
6011                                 }
6012                                 
6013                                 bounds [idx] = value;
6014                         }
6015
6016                         int child_bounds = -1;
6017                         only_constant_initializers = true;
6018                         for (int i = 0; i < probe.Count; ++i) {
6019                                 object o = probe [i];
6020                                 if (o is ArrayList) {
6021                                         ArrayList sub_probe = o as ArrayList;
6022                                         int current_bounds = sub_probe.Count;
6023                                         
6024                                         if (child_bounds == -1) 
6025                                                 child_bounds = current_bounds;
6026
6027                                         else if (child_bounds != current_bounds){
6028                                                 Error_IncorrectArrayInitializer ();
6029                                                 return false;
6030                                         }
6031                                         if (idx + 1 >= dimensions){
6032                                                 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6033                                                 return false;
6034                                         }
6035                                         
6036                                         bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
6037                                         if (!ret)
6038                                                 return false;
6039                                 } else {
6040                                         if (child_bounds != -1){
6041                                                 Error_IncorrectArrayInitializer ();
6042                                                 return false;
6043                                         }
6044                                         
6045                                         Expression tmp = (Expression) o;
6046                                         tmp = tmp.Resolve (ec);
6047                                         if (tmp == null)
6048                                                 return false;
6049
6050                                         Expression conv = Convert.ImplicitConversionRequired (
6051                                                 ec, tmp, underlying_type, loc);
6052                                         
6053                                         if (conv == null) 
6054                                                 return false;
6055
6056                                         // Initializers with the default values can be ignored
6057                                         Constant c = conv as Constant;
6058                                         if (c != null) {
6059                                                 if (c.IsDefaultInitializer (array_element_type)) {
6060                                                         conv = null;
6061                                                 }
6062                                                 else {
6063                                                         ++const_initializers_count;
6064                                                 }
6065                                         } else {
6066                                                 only_constant_initializers = false;
6067                                         }
6068                                         
6069                                         array_data.Add (conv);
6070                                 }
6071                         }
6072
6073                         return true;
6074                 }
6075                 
6076                 public void UpdateIndices ()
6077                 {
6078                         int i = 0;
6079                         for (ArrayList probe = initializers; probe != null;) {
6080                                 if (probe.Count > 0 && probe [0] is ArrayList) {
6081                                         Expression e = new IntConstant (probe.Count, Location.Null);
6082                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6083
6084                                         bounds [i++] =  probe.Count;
6085                                         
6086                                         probe = (ArrayList) probe [0];
6087                                         
6088                                 } else {
6089                                         Expression e = new IntConstant (probe.Count, Location.Null);
6090                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6091
6092                                         bounds [i++] = probe.Count;
6093                                         return;
6094                                 }
6095                         }
6096
6097                 }
6098                 
6099                 bool ResolveInitializers (EmitContext ec)
6100                 {
6101                         if (initializers == null) {
6102                                 return !expect_initializers;
6103                         }
6104                         
6105                         if (underlying_type == null)
6106                                 return false;
6107                         
6108                         //
6109                         // We use this to store all the date values in the order in which we
6110                         // will need to store them in the byte blob later
6111                         //
6112                         array_data = new ArrayList ();
6113                         bounds = new System.Collections.Specialized.HybridDictionary ();
6114                         
6115                         if (arguments != null)
6116                                 return CheckIndices (ec, initializers, 0, true);
6117
6118                         arguments = new ArrayList ();
6119
6120                         if (!CheckIndices (ec, initializers, 0, false))
6121                                 return false;
6122                                 
6123                         UpdateIndices ();
6124                                 
6125                         if (arguments.Count != dimensions) {
6126                                 Error_IncorrectArrayInitializer ();
6127                                 return false;
6128                         }
6129
6130                         return true;
6131                 }
6132
6133                 //
6134                 // Creates the type of the array
6135                 //
6136                 bool LookupType (EmitContext ec)
6137                 {
6138                         StringBuilder array_qualifier = new StringBuilder (rank);
6139
6140                         //
6141                         // `In the first form allocates an array instace of the type that results
6142                         // from deleting each of the individual expression from the expression list'
6143                         //
6144                         if (num_arguments > 0) {
6145                                 array_qualifier.Append ("[");
6146                                 for (int i = num_arguments-1; i > 0; i--)
6147                                         array_qualifier.Append (",");
6148                                 array_qualifier.Append ("]");                           
6149                         }
6150
6151                         //
6152                         // Lookup the type
6153                         //
6154                         TypeExpr array_type_expr;
6155                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6156                         array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6157                         if (array_type_expr == null)
6158                                 return false;
6159
6160                         type = array_type_expr.Type;
6161                         underlying_type = TypeManager.GetElementType (type);
6162                         dimensions = type.GetArrayRank ();
6163
6164                         return true;
6165                 }
6166                 
6167                 public override Expression DoResolve (EmitContext ec)
6168                 {
6169                         if (type != null)
6170                                 return this;
6171
6172                         if (!LookupType (ec))
6173                                 return null;
6174                         
6175                         array_element_type = TypeManager.GetElementType (type);
6176                         if (array_element_type.IsAbstract && array_element_type.IsSealed) {
6177                                 Report.Error (719, loc, "`{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
6178                                 return null;
6179                         }
6180
6181                         //
6182                         // First step is to validate the initializers and fill
6183                         // in any missing bits
6184                         //
6185                         if (!ResolveInitializers (ec))
6186                                 return null;
6187
6188                         int arg_count;
6189                         if (arguments == null)
6190                                 arg_count = 0;
6191                         else {
6192                                 arg_count = arguments.Count;
6193                                 foreach (Argument a in arguments){
6194                                         if (!a.Resolve (ec, loc))
6195                                                 return null;
6196
6197                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6198                                         if (real_arg == null)
6199                                                 return null;
6200
6201                                         a.Expr = real_arg;
6202                                 }
6203                         }
6204                         
6205                         if (arg_count == 1) {
6206                                 is_one_dimensional = true;
6207                                 eclass = ExprClass.Value;
6208                                 return this;
6209                         }
6210
6211                         is_builtin_type = TypeManager.IsBuiltinType (type);
6212
6213                         if (is_builtin_type) {
6214                                 Expression ml;
6215                                 
6216                                 ml = MemberLookup (ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
6217                                                    AllBindingFlags, loc);
6218                                 
6219                                 if (!(ml is MethodGroupExpr)) {
6220                                         ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
6221                                         return null;
6222                                 }
6223                                 
6224                                 if (ml == null) {
6225                                         Error (-6, "New invocation: Can not find a constructor for " +
6226                                                       "this argument list");
6227                                         return null;
6228                                 }
6229                                 
6230                                 new_method = Invocation.OverloadResolve (
6231                                         ec, (MethodGroupExpr) ml, arguments, false, loc);
6232
6233                                 if (new_method == null) {
6234                                         Error (-6, "New invocation: Can not find a constructor for " +
6235                                                       "this argument list");
6236                                         return null;
6237                                 }
6238                                 
6239                                 eclass = ExprClass.Value;
6240                                 return this;
6241                         } else {
6242                                 ModuleBuilder mb = CodeGen.Module.Builder;
6243                                 ArrayList args = new ArrayList ();
6244                                 
6245                                 if (arguments != null) {
6246                                         for (int i = 0; i < arg_count; i++)
6247                                                 args.Add (TypeManager.int32_type);
6248                                 }
6249                                 
6250                                 Type [] arg_types = null;
6251
6252                                 if (args.Count > 0)
6253                                         arg_types = new Type [args.Count];
6254                                 
6255                                 args.CopyTo (arg_types, 0);
6256                                 
6257                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6258                                                             arg_types);
6259
6260                                 if (new_method == null) {
6261                                         Error (-6, "New invocation: Can not find a constructor for " +
6262                                                       "this argument list");
6263                                         return null;
6264                                 }
6265                                 
6266                                 eclass = ExprClass.Value;
6267                                 return this;
6268                         }
6269                 }
6270
6271                 byte [] MakeByteBlob ()
6272                 {
6273                         int factor;
6274                         byte [] data;
6275                         byte [] element;
6276                         int count = array_data.Count;
6277
6278                         if (underlying_type.IsEnum)
6279                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6280                         
6281                         factor = GetTypeSize (underlying_type);
6282                         if (factor == 0)
6283                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6284
6285                         data = new byte [(count * factor + 4) & ~3];
6286                         int idx = 0;
6287
6288                         for (int i = 0; i < count; ++i) {
6289                                 object v = array_data [i];
6290
6291                                 if (v is EnumConstant)
6292                                         v = ((EnumConstant) v).Child;
6293                                 
6294                                 if (v is Constant && !(v is StringConstant))
6295                                         v = ((Constant) v).GetValue ();
6296                                 else {
6297                                         idx += factor;
6298                                         continue;
6299                                 }
6300                                 
6301                                 if (underlying_type == TypeManager.int64_type){
6302                                         if (!(v is Expression)){
6303                                                 long val = (long) v;
6304                                                 
6305                                                 for (int j = 0; j < factor; ++j) {
6306                                                         data [idx + j] = (byte) (val & 0xFF);
6307                                                         val = (val >> 8);
6308                                                 }
6309                                         }
6310                                 } else if (underlying_type == TypeManager.uint64_type){
6311                                         if (!(v is Expression)){
6312                                                 ulong val = (ulong) v;
6313
6314                                                 for (int j = 0; j < factor; ++j) {
6315                                                         data [idx + j] = (byte) (val & 0xFF);
6316                                                         val = (val >> 8);
6317                                                 }
6318                                         }
6319                                 } else if (underlying_type == TypeManager.float_type) {
6320                                         if (!(v is Expression)){
6321                                                 element = BitConverter.GetBytes ((float) v);
6322                                                         
6323                                                 for (int j = 0; j < factor; ++j)
6324                                                         data [idx + j] = element [j];
6325                                         }
6326                                 } else if (underlying_type == TypeManager.double_type) {
6327                                         if (!(v is Expression)){
6328                                                 element = BitConverter.GetBytes ((double) v);
6329
6330                                                 for (int j = 0; j < factor; ++j)
6331                                                         data [idx + j] = element [j];
6332                                         }
6333                                 } else if (underlying_type == TypeManager.char_type){
6334                                         if (!(v is Expression)){
6335                                                 int val = (int) ((char) v);
6336                                                 
6337                                                 data [idx] = (byte) (val & 0xff);
6338                                                 data [idx+1] = (byte) (val >> 8);
6339                                         }
6340                                 } else if (underlying_type == TypeManager.short_type){
6341                                         if (!(v is Expression)){
6342                                                 int val = (int) ((short) v);
6343                                         
6344                                                 data [idx] = (byte) (val & 0xff);
6345                                                 data [idx+1] = (byte) (val >> 8);
6346                                         }
6347                                 } else if (underlying_type == TypeManager.ushort_type){
6348                                         if (!(v is Expression)){
6349                                                 int val = (int) ((ushort) v);
6350                                         
6351                                                 data [idx] = (byte) (val & 0xff);
6352                                                 data [idx+1] = (byte) (val >> 8);
6353                                         }
6354                                 } else if (underlying_type == TypeManager.int32_type) {
6355                                         if (!(v is Expression)){
6356                                                 int val = (int) v;
6357                                         
6358                                                 data [idx]   = (byte) (val & 0xff);
6359                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6360                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6361                                                 data [idx+3] = (byte) (val >> 24);
6362                                         }
6363                                 } else if (underlying_type == TypeManager.uint32_type) {
6364                                         if (!(v is Expression)){
6365                                                 uint val = (uint) v;
6366                                         
6367                                                 data [idx]   = (byte) (val & 0xff);
6368                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6369                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6370                                                 data [idx+3] = (byte) (val >> 24);
6371                                         }
6372                                 } else if (underlying_type == TypeManager.sbyte_type) {
6373                                         if (!(v is Expression)){
6374                                                 sbyte val = (sbyte) v;
6375                                                 data [idx] = (byte) val;
6376                                         }
6377                                 } else if (underlying_type == TypeManager.byte_type) {
6378                                         if (!(v is Expression)){
6379                                                 byte val = (byte) v;
6380                                                 data [idx] = (byte) val;
6381                                         }
6382                                 } else if (underlying_type == TypeManager.bool_type) {
6383                                         if (!(v is Expression)){
6384                                                 bool val = (bool) v;
6385                                                 data [idx] = (byte) (val ? 1 : 0);
6386                                         }
6387                                 } else if (underlying_type == TypeManager.decimal_type){
6388                                         if (!(v is Expression)){
6389                                                 int [] bits = Decimal.GetBits ((decimal) v);
6390                                                 int p = idx;
6391
6392                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
6393                                                 int [] nbits = new int [4];
6394                                                 nbits [0] = bits [3];
6395                                                 nbits [1] = bits [2];
6396                                                 nbits [2] = bits [0];
6397                                                 nbits [3] = bits [1];
6398                                                 
6399                                                 for (int j = 0; j < 4; j++){
6400                                                         data [p++] = (byte) (nbits [j] & 0xff);
6401                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6402                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6403                                                         data [p++] = (byte) (nbits [j] >> 24);
6404                                                 }
6405                                         }
6406                                 } else
6407                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6408
6409                                 idx += factor;
6410                         }
6411
6412                         return data;
6413                 }
6414
6415                 //
6416                 // Emits the initializers for the array
6417                 //
6418                 void EmitStaticInitializers (EmitContext ec)
6419                 {
6420                         //
6421                         // First, the static data
6422                         //
6423                         FieldBuilder fb;
6424                         ILGenerator ig = ec.ig;
6425                         
6426                         byte [] data = MakeByteBlob ();
6427
6428                         fb = RootContext.MakeStaticData (data);
6429
6430                         ig.Emit (OpCodes.Dup);
6431                         ig.Emit (OpCodes.Ldtoken, fb);
6432                         ig.Emit (OpCodes.Call,
6433                                  TypeManager.void_initializearray_array_fieldhandle);
6434                 }
6435
6436                 //
6437                 // Emits pieces of the array that can not be computed at compile
6438                 // time (variables and string locations).
6439                 //
6440                 // This always expect the top value on the stack to be the array
6441                 //
6442                 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
6443                 {
6444                         ILGenerator ig = ec.ig;
6445                         int dims = bounds.Count;
6446                         int [] current_pos = new int [dims];
6447
6448                         MethodInfo set = null;
6449
6450                         if (dims != 1){
6451                                 Type [] args = new Type [dims + 1];
6452
6453                                 for (int j = 0; j < dims; j++)
6454                                         args [j] = TypeManager.int32_type;
6455                                 args [dims] = array_element_type;
6456                                 
6457                                 set = CodeGen.Module.Builder.GetArrayMethod (
6458                                         type, "Set",
6459                                         CallingConventions.HasThis | CallingConventions.Standard,
6460                                         TypeManager.void_type, args);
6461                         }
6462
6463                         for (int i = 0; i < array_data.Count; i++){
6464
6465                                 Expression e = (Expression)array_data [i];
6466
6467                                 // Constant can be initialized via StaticInitializer
6468                                 if (e != null && !(!emitConstants && e is Constant)) {
6469                                         Type etype = e.Type;
6470
6471                                         ig.Emit (OpCodes.Dup);
6472
6473                                         for (int idx = 0; idx < dims; idx++) 
6474                                                 IntConstant.EmitInt (ig, current_pos [idx]);
6475
6476                                         //
6477                                         // If we are dealing with a struct, get the
6478                                         // address of it, so we can store it.
6479                                         //
6480                                         if ((dims == 1) && etype.IsValueType &&
6481                                             (!TypeManager.IsBuiltinOrEnum (etype) ||
6482                                              etype == TypeManager.decimal_type)) {
6483                                                 if (e is New){
6484                                                         New n = (New) e;
6485
6486                                                         //
6487                                                         // Let new know that we are providing
6488                                                         // the address where to store the results
6489                                                         //
6490                                                         n.DisableTemporaryValueType ();
6491                                                 }
6492
6493                                                 ig.Emit (OpCodes.Ldelema, etype);
6494                                         }
6495
6496                                         e.Emit (ec);
6497
6498                                         if (dims == 1) {
6499                                                 bool is_stobj, has_type_arg;
6500                                                 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6501                                                 if (is_stobj)
6502                                                         ig.Emit (OpCodes.Stobj, etype);
6503                                                 else if (has_type_arg)
6504                                                         ig.Emit (op, etype);
6505                                                 else
6506                                                         ig.Emit (op);
6507                                         } else 
6508                                                 ig.Emit (OpCodes.Call, set);
6509
6510                                 }
6511                                 
6512                                 //
6513                                 // Advance counter
6514                                 //
6515                                 for (int j = dims - 1; j >= 0; j--){
6516                                         current_pos [j]++;
6517                                         if (current_pos [j] < (int) bounds [j])
6518                                                 break;
6519                                         current_pos [j] = 0;
6520                                 }
6521                         }
6522                 }
6523
6524                 void EmitArrayArguments (EmitContext ec)
6525                 {
6526                         ILGenerator ig = ec.ig;
6527                         
6528                         foreach (Argument a in arguments) {
6529                                 Type atype = a.Type;
6530                                 a.Emit (ec);
6531
6532                                 if (atype == TypeManager.uint64_type)
6533                                         ig.Emit (OpCodes.Conv_Ovf_U4);
6534                                 else if (atype == TypeManager.int64_type)
6535                                         ig.Emit (OpCodes.Conv_Ovf_I4);
6536                         }
6537                 }
6538                 
6539                 public override void Emit (EmitContext ec)
6540                 {
6541                         ILGenerator ig = ec.ig;
6542                         
6543                         EmitArrayArguments (ec);
6544                         if (is_one_dimensional)
6545                                 ig.Emit (OpCodes.Newarr, array_element_type);
6546                         else {
6547                                 if (is_builtin_type) 
6548                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6549                                 else 
6550                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6551                         }
6552                         
6553                         if (initializers == null)
6554                                 return;
6555
6556                         // Emit static initializer for arrays which have contain more than 4 items and
6557                         // the static initializer will initialize at least 25% of array values.
6558                         // NOTE: const_initializers_count does not contain default constant values.
6559                         if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6560                                 TypeManager.IsPrimitiveType (array_element_type)) {
6561                                 EmitStaticInitializers (ec);
6562
6563                                 if (!only_constant_initializers)
6564                                         EmitDynamicInitializers (ec, false);
6565                         } else {
6566                                 EmitDynamicInitializers (ec, true);
6567                         }                               
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                 //
6712                 // Called from Invocation to check if the invocation is correct
6713                 //
6714                 public bool CheckThisUsage (EmitContext ec)
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 false;
6722                         }
6723
6724                         return true;
6725                 }
6726                 
6727                 public override Expression DoResolve (EmitContext ec)
6728                 {
6729                         if (!ResolveBase (ec))
6730                                 return null;
6731
6732
6733                         if (ec.IsFieldInitializer) {
6734                                 Error (27, "Keyword `this' is not available in the current context");
6735                                 return null;
6736                         }
6737
6738                         return this;
6739                 }
6740
6741                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6742                 {
6743                         if (!ResolveBase (ec))
6744                                 return null;
6745
6746                         if (variable_info != null)
6747                                 variable_info.SetAssigned (ec);
6748                         
6749                         if (ec.TypeContainer is Class){
6750                                 Error (1604, "Cannot assign to 'this' because it is read-only");
6751                                 return null;
6752                         }
6753
6754                         return this;
6755                 }
6756                 public override int GetHashCode()
6757                 {
6758                         return block.GetHashCode ();
6759                 }
6760
6761                 public override bool Equals (object obj)
6762                 {
6763                         This t = obj as This;
6764                         if (t == null)
6765                                 return false;
6766
6767                         return block == t.block;
6768                 }
6769
6770                 protected class SimpleThis : Variable
6771                 {
6772                         Type type;
6773
6774                         public SimpleThis (Type type)
6775                         {
6776                                 this.type = type;
6777                         }
6778
6779                         public override Type Type {
6780                                 get { return type; }
6781                         }
6782
6783                         public override bool HasInstance {
6784                                 get { return false; }
6785                         }
6786
6787                         public override bool NeedsTemporary {
6788                                 get { return false; }
6789                         }
6790
6791                         public override void EmitInstance (EmitContext ec)
6792                         {
6793                                 // Do nothing.
6794                         }
6795
6796                         public override void Emit (EmitContext ec)
6797                         {
6798                                 ec.ig.Emit (OpCodes.Ldarg_0);
6799                         }
6800
6801                         public override void EmitAssign (EmitContext ec)
6802                         {
6803                                 throw new InvalidOperationException ();
6804                         }
6805
6806                         public override void EmitAddressOf (EmitContext ec)
6807                         {
6808                                 ec.ig.Emit (OpCodes.Ldarg_0);
6809                         }
6810                 }
6811         }
6812
6813         /// <summary>
6814         ///   Represents the `__arglist' construct
6815         /// </summary>
6816         public class ArglistAccess : Expression
6817         {
6818                 public ArglistAccess (Location loc)
6819                 {
6820                         this.loc = loc;
6821                 }
6822
6823                 public override Expression DoResolve (EmitContext ec)
6824                 {
6825                         eclass = ExprClass.Variable;
6826                         type = TypeManager.runtime_argument_handle_type;
6827
6828                         if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs) 
6829                         {
6830                                 Error (190, "The __arglist construct is valid only within " +
6831                                        "a variable argument method");
6832                                 return null;
6833                         }
6834
6835                         return this;
6836                 }
6837
6838                 public override void Emit (EmitContext ec)
6839                 {
6840                         ec.ig.Emit (OpCodes.Arglist);
6841                 }
6842         }
6843
6844         /// <summary>
6845         ///   Represents the `__arglist (....)' construct
6846         /// </summary>
6847         public class Arglist : Expression
6848         {
6849                 public readonly Argument[] Arguments;
6850
6851                 public Arglist (Argument[] args, Location l)
6852                 {
6853                         Arguments = args;
6854                         loc = l;
6855                 }
6856
6857                 public Type[] ArgumentTypes {
6858                         get {
6859                                 Type[] retval = new Type [Arguments.Length];
6860                                 for (int i = 0; i < Arguments.Length; i++)
6861                                         retval [i] = Arguments [i].Type;
6862                                 return retval;
6863                         }
6864                 }
6865
6866                 public override Expression DoResolve (EmitContext ec)
6867                 {
6868                         eclass = ExprClass.Variable;
6869                         type = TypeManager.runtime_argument_handle_type;
6870
6871                         foreach (Argument arg in Arguments) {
6872                                 if (!arg.Resolve (ec, loc))
6873                                         return null;
6874                         }
6875
6876                         return this;
6877                 }
6878
6879                 public override void Emit (EmitContext ec)
6880                 {
6881                         foreach (Argument arg in Arguments)
6882                                 arg.Emit (ec);
6883                 }
6884         }
6885
6886         //
6887         // This produces the value that renders an instance, used by the iterators code
6888         //
6889         public class ProxyInstance : Expression, IMemoryLocation  {
6890                 public override Expression DoResolve (EmitContext ec)
6891                 {
6892                         eclass = ExprClass.Variable;
6893                         type = ec.ContainerType;
6894                         return this;
6895                 }
6896                 
6897                 public override void Emit (EmitContext ec)
6898                 {
6899                         ec.ig.Emit (OpCodes.Ldarg_0);
6900
6901                 }
6902                 
6903                 public void AddressOf (EmitContext ec, AddressOp mode)
6904                 {
6905                         ec.ig.Emit (OpCodes.Ldarg_0);
6906                 }
6907         }
6908
6909         /// <summary>
6910         ///   Implements the typeof operator
6911         /// </summary>
6912         public class TypeOf : Expression {
6913                 readonly Expression QueriedType;
6914                 protected Type typearg;
6915                 
6916                 public TypeOf (Expression queried_type, Location l)
6917                 {
6918                         QueriedType = queried_type;
6919                         loc = l;
6920                 }
6921
6922                 public override Expression DoResolve (EmitContext ec)
6923                 {
6924                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6925                         if (texpr == null)
6926                                 return null;
6927
6928                         typearg = texpr.Type;
6929
6930                         if (typearg == TypeManager.void_type) {
6931                                 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6932                                 return null;
6933                         }
6934
6935                         if (typearg.IsPointer && !ec.InUnsafe){
6936                                 UnsafeError (loc);
6937                                 return null;
6938                         }
6939
6940                         type = TypeManager.type_type;
6941                         // Even though what is returned is a type object, it's treated as a value by the compiler.
6942                         // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6943                         eclass = ExprClass.Value;
6944                         return this;
6945                 }
6946
6947                 public override void Emit (EmitContext ec)
6948                 {
6949                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
6950                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6951                 }
6952
6953                 public override bool GetAttributableValue (Type valueType, out object value)
6954                 {
6955                         if (TypeManager.ContainsGenericParameters (typearg)) {
6956                                 Report.SymbolRelatedToPreviousError(typearg);
6957                                 Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters",
6958                                              TypeManager.CSharpName(typearg));
6959                                 value = null;
6960                                 return false;
6961                         }
6962
6963                         if (valueType == TypeManager.object_type) {
6964                                 value = (object)typearg;
6965                                 return true;
6966                         }
6967                         value = typearg;
6968                         return true;
6969                 }
6970
6971                 public Type TypeArgument
6972                 {
6973                         get
6974                         {
6975                                 return typearg;
6976                         }
6977                 }
6978         }
6979
6980         /// <summary>
6981         ///   Implements the `typeof (void)' operator
6982         /// </summary>
6983         public class TypeOfVoid : TypeOf {
6984                 public TypeOfVoid (Location l) : base (null, l)
6985                 {
6986                         loc = l;
6987                 }
6988
6989                 public override Expression DoResolve (EmitContext ec)
6990                 {
6991                         type = TypeManager.type_type;
6992                         typearg = TypeManager.void_type;
6993                         // See description in TypeOf.
6994                         eclass = ExprClass.Value;
6995                         return this;
6996                 }
6997         }
6998
6999         /// <summary>
7000         ///   Implements the sizeof expression
7001         /// </summary>
7002         public class SizeOf : Expression {
7003                 public Expression QueriedType;
7004                 Type type_queried;
7005                 
7006                 public SizeOf (Expression queried_type, Location l)
7007                 {
7008                         this.QueriedType = queried_type;
7009                         loc = l;
7010                 }
7011
7012                 public override Expression DoResolve (EmitContext ec)
7013                 {
7014                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
7015                         if (texpr == null)
7016                                 return null;
7017
7018 #if GMCS_SOURCE
7019                         if (texpr is TypeParameterExpr){
7020                                 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
7021                                 return null;
7022                         }
7023 #endif
7024
7025                         type_queried = texpr.Type;
7026                         if (type_queried.IsEnum)
7027                                 type_queried = TypeManager.EnumToUnderlying (type_queried);
7028
7029                         if (type_queried == TypeManager.void_type) {
7030                                 Expression.Error_VoidInvalidInTheContext (loc);
7031                                 return null;
7032                         }
7033
7034                         int size_of = GetTypeSize (type_queried);
7035                         if (size_of > 0) {
7036                                 return new IntConstant (size_of, loc);
7037                         }
7038
7039                         if (!ec.InUnsafe) {
7040                                 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)",
7041                                          TypeManager.CSharpName (type_queried));
7042                                 return null;
7043                         }
7044
7045                         if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7046                                 return null;
7047                         }
7048                         
7049                         type = TypeManager.int32_type;
7050                         eclass = ExprClass.Value;
7051                         return this;
7052                 }
7053
7054                 public override void Emit (EmitContext ec)
7055                 {
7056                         int size = GetTypeSize (type_queried);
7057
7058                         if (size == 0)
7059                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7060                         else
7061                                 IntConstant.EmitInt (ec.ig, size);
7062                 }
7063         }
7064
7065         /// <summary>
7066         ///   Implements the qualified-alias-member (::) expression.
7067         /// </summary>
7068         public class QualifiedAliasMember : Expression
7069         {
7070                 string alias, identifier;
7071
7072                 public QualifiedAliasMember (string alias, string identifier, Location l)
7073                 {
7074                         this.alias = alias;
7075                         this.identifier = identifier;
7076                         loc = l;
7077                 }
7078
7079                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7080                 {
7081                         if (alias == "global")
7082                                 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
7083
7084                         int errors = Report.Errors;
7085                         FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7086                         if (fne == null) {
7087                                 if (errors == Report.Errors)
7088                                         Report.Error (432, loc, "Alias `{0}' not found", alias);
7089                                 return null;
7090                         }
7091                         if (fne.eclass != ExprClass.Namespace) {
7092                                 if (!silent)
7093                                         Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
7094                                 return null;
7095                         }
7096                         return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
7097                 }
7098
7099                 public override Expression DoResolve (EmitContext ec)
7100                 {
7101                         FullNamedExpression fne;
7102                         if (alias == "global") {
7103                                 fne = RootNamespace.Global;
7104                         } else {
7105                                 int errors = Report.Errors;
7106                                 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7107                                 if (fne == null) {
7108                                         if (errors == Report.Errors)
7109                                                 Report.Error (432, loc, "Alias `{0}' not found", alias);
7110                                         return null;
7111                                 }
7112                         }
7113
7114                         Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
7115                         if (retval == null)
7116                                 return null;
7117
7118                         if (!(retval is FullNamedExpression)) {
7119                                 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
7120                                 return null;
7121                         }
7122
7123                         // We defer this check till the end to match the behaviour of CSC
7124                         if (fne.eclass != ExprClass.Namespace) {
7125                                 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
7126                                 return null;
7127                         }
7128                         return retval;
7129                 }
7130
7131                 public override void Emit (EmitContext ec)
7132                 {
7133                         throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
7134                 }
7135
7136
7137                 public override string ToString ()
7138                 {
7139                         return alias + "::" + identifier;
7140                 }
7141
7142                 public override string GetSignatureForError ()
7143                 {
7144                         return ToString ();
7145                 }
7146         }
7147
7148         /// <summary>
7149         ///   Implements the member access expression
7150         /// </summary>
7151         public class MemberAccess : Expression {
7152                 public readonly string Identifier;
7153                 Expression expr;
7154
7155                 public MemberAccess (Expression expr, string id)
7156                         : this (expr, id, expr.Location)
7157                 {
7158                 }
7159
7160                 public MemberAccess (Expression expr, string identifier, Location loc)
7161                 {
7162                         this.expr = expr;
7163                         Identifier = identifier;
7164                         this.loc = loc;
7165                 }
7166
7167                 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7168                         : this (expr, identifier, loc)
7169                 {
7170                         this.args = args;
7171                 }
7172
7173                 TypeArguments args;
7174
7175                 public Expression Expr {
7176                         get { return expr; }
7177                 }
7178
7179                 protected string LookupIdentifier {
7180                         get { return MemberName.MakeName (Identifier, args); }
7181                 }
7182
7183                 // TODO: this method has very poor performace for Enum fields and
7184                 // probably for other constants as well
7185                 Expression DoResolve (EmitContext ec, Expression right_side)
7186                 {
7187                         if (type != null)
7188                                 throw new Exception ();
7189
7190                         //
7191                         // Resolve the expression with flow analysis turned off, we'll do the definite
7192                         // assignment checks later.  This is because we don't know yet what the expression
7193                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7194                         // definite assignment check on the actual field and not on the whole struct.
7195                         //
7196
7197                         SimpleName original = expr as SimpleName;
7198                         Expression new_expr = expr.Resolve (ec,
7199                                 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7200                                 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7201
7202                         if (new_expr == null)
7203                                 return null;
7204
7205                         if (new_expr is Namespace) {
7206                                 Namespace ns = (Namespace) new_expr;
7207                                 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7208 #if GMCS_SOURCE
7209                                 if ((retval != null) && (args != null))
7210                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
7211 #endif
7212
7213                                 if (retval == null)
7214                                         ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
7215                                 return retval;
7216                         }
7217
7218                         Type expr_type = new_expr.Type;
7219                         if (expr_type.IsPointer || expr_type == TypeManager.void_type || new_expr is NullLiteral){
7220                                 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7221                                 return null;
7222                         }
7223                         if (expr_type == TypeManager.anonymous_method_type){
7224                                 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
7225                                 return null;
7226                         }
7227
7228                         Constant c = new_expr as Constant;
7229                         if (c != null && c.GetValue () == null) {
7230                                 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7231                                         "System.NullReferenceException");
7232                         }
7233
7234                         Expression member_lookup;
7235                         member_lookup = MemberLookup (
7236                                 ec.ContainerType, expr_type, expr_type, Identifier, loc);
7237 #if GMCS_SOURCE
7238                         if ((member_lookup == null) && (args != null)) {
7239                                 member_lookup = MemberLookup (
7240                                         ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7241                         }
7242 #endif
7243                         if (member_lookup == null) {
7244                                 MemberLookupFailed (
7245                                         ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
7246                                 return null;
7247                         }
7248
7249                         TypeExpr texpr = member_lookup as TypeExpr;
7250                         if (texpr != null) {
7251                                 if (!(new_expr is TypeExpr) && 
7252                                     (original == null || !original.IdenticalNameAndTypeName (ec, new_expr, loc))) {
7253                                         Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7254                                                 Identifier, member_lookup.GetSignatureForError ());
7255                                         return null;
7256                                 }
7257
7258                                 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7259                                         Report.SymbolRelatedToPreviousError (member_lookup.Type);
7260                                         ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7261                                         return null;
7262                                 }
7263
7264 #if GMCS_SOURCE
7265                                 ConstructedType ct = new_expr as ConstructedType;
7266                                 if (ct != null) {
7267                                         //
7268                                         // When looking up a nested type in a generic instance
7269                                         // via reflection, we always get a generic type definition
7270                                         // and not a generic instance - so we have to do this here.
7271                                         //
7272                                         // See gtest-172-lib.cs and gtest-172.cs for an example.
7273                                         //
7274                                         ct = new ConstructedType (
7275                                                 member_lookup.Type, ct.TypeArguments, loc);
7276
7277                                         return ct.ResolveAsTypeStep (ec, false);
7278                                 }
7279 #endif
7280                                 return member_lookup;
7281                         }
7282
7283                         MemberExpr me = (MemberExpr) member_lookup;
7284                         member_lookup = me.ResolveMemberAccess (ec, new_expr, loc, original);
7285                         if (member_lookup == null)
7286                                 return null;
7287
7288                         if (args != null) {
7289                                 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
7290                                 if (mg == null)
7291                                         throw new InternalErrorException ();
7292
7293                                 return mg.ResolveGeneric (ec, args);
7294                         }
7295
7296                         if (original != null && !TypeManager.IsValueType (expr_type)) {
7297                                 me = member_lookup as MemberExpr;
7298                                 if (me != null && me.IsInstance) {
7299                                         LocalVariableReference var = new_expr as LocalVariableReference;
7300                                         if (var != null && !var.VerifyAssigned (ec))
7301                                                 return null;
7302                                 }
7303                         }
7304
7305                         // The following DoResolve/DoResolveLValue will do the definite assignment
7306                         // check.
7307
7308                         if (right_side != null)
7309                                 return member_lookup.DoResolveLValue (ec, right_side);
7310                         else
7311                                 return member_lookup.DoResolve (ec);
7312                 }
7313
7314                 public override Expression DoResolve (EmitContext ec)
7315                 {
7316                         return DoResolve (ec, null);
7317                 }
7318
7319                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7320                 {
7321                         return DoResolve (ec, right_side);
7322                 }
7323
7324                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7325                 {
7326                         return ResolveNamespaceOrType (ec, silent);
7327                 }
7328
7329                 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7330                 {
7331                         FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7332
7333                         if (new_expr == null)
7334                                 return null;
7335
7336                         if (new_expr is Namespace) {
7337                                 Namespace ns = (Namespace) new_expr;
7338                                 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7339 #if GMCS_SOURCE
7340                                 if ((retval != null) && (args != null))
7341                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
7342 #endif
7343                                 if (!silent && retval == null)
7344                                         ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7345                                 return retval;
7346                         }
7347
7348                         TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7349                         if (tnew_expr == null)
7350                                 return null;
7351
7352                         Type expr_type = tnew_expr.Type;
7353
7354                         if (expr_type.IsPointer){
7355                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7356                                        TypeManager.CSharpName (expr_type) + ")");
7357                                 return null;
7358                         }
7359
7360                         Expression member_lookup = MemberLookup (
7361                                 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7362                                 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7363                         if (member_lookup == null) {
7364                                 if (silent)
7365                                         return null;
7366
7367                                 member_lookup = MemberLookup(
7368                                     rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7369                                         MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7370
7371                                 if (member_lookup == null) {
7372                                         Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7373                                                       Identifier, new_expr.GetSignatureForError ());
7374                                 } else {
7375                                 // TODO: Report.SymbolRelatedToPreviousError
7376                                     member_lookup.Error_UnexpectedKind (null, "type", loc);
7377                                 }
7378                                 return null;
7379                         }
7380
7381                         TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7382                         if (texpr == null)
7383                                 return null;
7384
7385 #if GMCS_SOURCE
7386                         TypeArguments the_args = args;
7387                         if (TypeManager.HasGenericArguments (expr_type)) {
7388                                 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
7389
7390                                 TypeArguments new_args = new TypeArguments (loc);
7391                                 foreach (Type decl in decl_args)
7392                                         new_args.Add (new TypeExpression (decl, loc));
7393
7394                                 if (args != null)
7395                                         new_args.Add (args);
7396
7397                                 the_args = new_args;
7398                         }
7399
7400                         if (the_args != null) {
7401                                 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7402                                 return ctype.ResolveAsTypeStep (rc, false);
7403                         }
7404 #endif
7405
7406                         return texpr;
7407                 }
7408
7409                 public override void Emit (EmitContext ec)
7410                 {
7411                         throw new Exception ("Should not happen");
7412                 }
7413
7414                 public override string ToString ()
7415                 {
7416                         return expr + "." + MemberName.MakeName (Identifier, args);
7417                 }
7418
7419                 public override string GetSignatureForError ()
7420                 {
7421                         return expr.GetSignatureForError () + "." + Identifier;
7422                 }
7423         }
7424
7425         /// <summary>
7426         ///   Implements checked expressions
7427         /// </summary>
7428         public class CheckedExpr : Expression {
7429
7430                 public Expression Expr;
7431
7432                 public CheckedExpr (Expression e, Location l)
7433                 {
7434                         Expr = e;
7435                         loc = l;
7436                 }
7437
7438                 public override Expression DoResolve (EmitContext ec)
7439                 {
7440                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7441                                 Expr = Expr.Resolve (ec);
7442                         
7443                         if (Expr == null)
7444                                 return null;
7445
7446                         if (Expr is Constant)
7447                                 return Expr;
7448                         
7449                         eclass = Expr.eclass;
7450                         type = Expr.Type;
7451                         return this;
7452                 }
7453
7454                 public override void Emit (EmitContext ec)
7455                 {
7456                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7457                                 Expr.Emit (ec);
7458                 }
7459
7460                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7461                 {
7462                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7463                                 Expr.EmitBranchable (ec, target, onTrue);
7464                 }
7465         }
7466
7467         /// <summary>
7468         ///   Implements the unchecked expression
7469         /// </summary>
7470         public class UnCheckedExpr : Expression {
7471
7472                 public Expression Expr;
7473
7474                 public UnCheckedExpr (Expression e, Location l)
7475                 {
7476                         Expr = e;
7477                         loc = l;
7478                 }
7479
7480                 public override Expression DoResolve (EmitContext ec)
7481                 {
7482                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7483                                 Expr = Expr.Resolve (ec);
7484
7485                         if (Expr == null)
7486                                 return null;
7487
7488                         if (Expr is Constant)
7489                                 return Expr;
7490                         
7491                         eclass = Expr.eclass;
7492                         type = Expr.Type;
7493                         return this;
7494                 }
7495
7496                 public override void Emit (EmitContext ec)
7497                 {
7498                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7499                                 Expr.Emit (ec);
7500                 }
7501                 
7502                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7503                 {
7504                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7505                                 Expr.EmitBranchable (ec, target, onTrue);
7506                 }
7507         }
7508
7509         /// <summary>
7510         ///   An Element Access expression.
7511         ///
7512         ///   During semantic analysis these are transformed into 
7513         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7514         /// </summary>
7515         public class ElementAccess : Expression {
7516                 public ArrayList  Arguments;
7517                 public Expression Expr;
7518                 
7519                 public ElementAccess (Expression e, ArrayList e_list)
7520                 {
7521                         Expr = e;
7522
7523                         loc  = e.Location;
7524                         
7525                         if (e_list == null)
7526                                 return;
7527                         
7528                         Arguments = new ArrayList ();
7529                         foreach (Expression tmp in e_list)
7530                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7531                         
7532                 }
7533
7534                 bool CommonResolve (EmitContext ec)
7535                 {
7536                         Expr = Expr.Resolve (ec);
7537
7538                         if (Expr == null) 
7539                                 return false;
7540
7541                         if (Arguments == null)
7542                                 return false;
7543
7544                         foreach (Argument a in Arguments){
7545                                 if (!a.Resolve (ec, loc))
7546                                         return false;
7547                         }
7548
7549                         return true;
7550                 }
7551
7552                 Expression MakePointerAccess (EmitContext ec, Type t)
7553                 {
7554                         if (t == TypeManager.void_ptr_type){
7555                                 Error (242, "The array index operation is not valid on void pointers");
7556                                 return null;
7557                         }
7558                         if (Arguments.Count != 1){
7559                                 Error (196, "A pointer must be indexed by only one value");
7560                                 return null;
7561                         }
7562                         Expression p;
7563
7564                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7565                         if (p == null)
7566                                 return null;
7567                         return new Indirection (p, loc).Resolve (ec);
7568                 }
7569                 
7570                 public override Expression DoResolve (EmitContext ec)
7571                 {
7572                         if (!CommonResolve (ec))
7573                                 return null;
7574
7575                         //
7576                         // We perform some simple tests, and then to "split" the emit and store
7577                         // code we create an instance of a different class, and return that.
7578                         //
7579                         // I am experimenting with this pattern.
7580                         //
7581                         Type t = Expr.Type;
7582
7583                         if (t == TypeManager.array_type){
7584                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7585                                 return null;
7586                         }
7587                         
7588                         if (t.IsArray)
7589                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7590                         if (t.IsPointer)
7591                                 return MakePointerAccess (ec, Expr.Type);
7592
7593                         FieldExpr fe = Expr as FieldExpr;
7594                         if (fe != null) {
7595                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7596                                 if (ff != null) {
7597                                         return MakePointerAccess (ec, ff.ElementType);
7598                                 }
7599                         }
7600                         return (new IndexerAccess (this, loc)).Resolve (ec);
7601                 }
7602
7603                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7604                 {
7605                         if (!CommonResolve (ec))
7606                                 return null;
7607
7608                         Type t = Expr.Type;
7609                         if (t.IsArray)
7610                                 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7611
7612                         if (t.IsPointer)
7613                                 return MakePointerAccess (ec, Expr.Type);
7614
7615                         FieldExpr fe = Expr as FieldExpr;
7616                         if (fe != null) {
7617                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7618                                 if (ff != null) {
7619                                         if (!(fe.InstanceExpression is LocalVariableReference) && 
7620                                                 !(fe.InstanceExpression is This)) {
7621                                                 Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields");
7622                                                 return null;
7623                                         }
7624                                         if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
7625                                                 Error (1666, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
7626                                                 return null;
7627                                         }
7628                                         return MakePointerAccess (ec, ff.ElementType);
7629                                 }
7630                         }
7631                         return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7632                 }
7633                 
7634                 public override void Emit (EmitContext ec)
7635                 {
7636                         throw new Exception ("Should never be reached");
7637                 }
7638         }
7639
7640         /// <summary>
7641         ///   Implements array access 
7642         /// </summary>
7643         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7644                 //
7645                 // Points to our "data" repository
7646                 //
7647                 ElementAccess ea;
7648
7649                 LocalTemporary temp;
7650                 bool prepared;
7651                 
7652                 public ArrayAccess (ElementAccess ea_data, Location l)
7653                 {
7654                         ea = ea_data;
7655                         eclass = ExprClass.Variable;
7656                         loc = l;
7657                 }
7658
7659                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7660                 {
7661                         return DoResolve (ec);
7662                 }
7663
7664                 public override Expression DoResolve (EmitContext ec)
7665                 {
7666 #if false
7667                         ExprClass eclass = ea.Expr.eclass;
7668
7669                         // As long as the type is valid
7670                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7671                               eclass == ExprClass.Value)) {
7672                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7673                                 return null;
7674                         }
7675 #endif
7676
7677                         Type t = ea.Expr.Type;
7678                         if (t.GetArrayRank () != ea.Arguments.Count){
7679                                 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7680                                           ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7681                                 return null;
7682                         }
7683
7684                         type = TypeManager.GetElementType (t);
7685                         if (type.IsPointer && !ec.InUnsafe){
7686                                 UnsafeError (ea.Location);
7687                                 return null;
7688                         }
7689
7690                         foreach (Argument a in ea.Arguments){
7691                                 Type argtype = a.Type;
7692
7693                                 if (argtype == TypeManager.int32_type ||
7694                                     argtype == TypeManager.uint32_type ||
7695                                     argtype == TypeManager.int64_type ||
7696                                     argtype == TypeManager.uint64_type) {
7697                                         Constant c = a.Expr as Constant;
7698                                         if (c != null && c.IsNegative) {
7699                                                 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7700                                         }
7701                                         continue;
7702                                 }
7703
7704                                 //
7705                                 // Mhm.  This is strage, because the Argument.Type is not the same as
7706                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7707                                 //
7708                                 // Wonder if I will run into trouble for this.
7709                                 //
7710                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7711                                 if (a.Expr == null)
7712                                         return null;
7713                         }
7714                         
7715                         eclass = ExprClass.Variable;
7716
7717                         return this;
7718                 }
7719
7720                 /// <summary>
7721                 ///    Emits the right opcode to load an object of Type `t'
7722                 ///    from an array of T
7723                 /// </summary>
7724                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7725                 {
7726                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7727                                 ig.Emit (OpCodes.Ldelem_U1);
7728                         else if (type == TypeManager.sbyte_type)
7729                                 ig.Emit (OpCodes.Ldelem_I1);
7730                         else if (type == TypeManager.short_type)
7731                                 ig.Emit (OpCodes.Ldelem_I2);
7732                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7733                                 ig.Emit (OpCodes.Ldelem_U2);
7734                         else if (type == TypeManager.int32_type)
7735                                 ig.Emit (OpCodes.Ldelem_I4);
7736                         else if (type == TypeManager.uint32_type)
7737                                 ig.Emit (OpCodes.Ldelem_U4);
7738                         else if (type == TypeManager.uint64_type)
7739                                 ig.Emit (OpCodes.Ldelem_I8);
7740                         else if (type == TypeManager.int64_type)
7741                                 ig.Emit (OpCodes.Ldelem_I8);
7742                         else if (type == TypeManager.float_type)
7743                                 ig.Emit (OpCodes.Ldelem_R4);
7744                         else if (type == TypeManager.double_type)
7745                                 ig.Emit (OpCodes.Ldelem_R8);
7746                         else if (type == TypeManager.intptr_type)
7747                                 ig.Emit (OpCodes.Ldelem_I);
7748                         else if (TypeManager.IsEnumType (type)){
7749                                 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7750                         } else if (type.IsValueType){
7751                                 ig.Emit (OpCodes.Ldelema, type);
7752                                 ig.Emit (OpCodes.Ldobj, type);
7753 #if GMCS_SOURCE
7754                         } else if (type.IsGenericParameter) {
7755 #if MS_COMPATIBLE
7756                                 ig.Emit (OpCodes.Ldelem, type);
7757 #else
7758                                 ig.Emit (OpCodes.Ldelem_Any, type);
7759 #endif
7760 #endif
7761                         } else if (type.IsPointer)
7762                                 ig.Emit (OpCodes.Ldelem_I);
7763                         else
7764                                 ig.Emit (OpCodes.Ldelem_Ref);
7765                 }
7766
7767                 /// <summary>
7768                 ///    Returns the right opcode to store an object of Type `t'
7769                 ///    from an array of T.  
7770                 /// </summary>
7771                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7772                 {
7773                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
7774                         has_type_arg = false; is_stobj = false;
7775                         t = TypeManager.TypeToCoreType (t);
7776                         if (TypeManager.IsEnumType (t))
7777                                 t = TypeManager.EnumToUnderlying (t);
7778                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7779                             t == TypeManager.bool_type)
7780                                 return OpCodes.Stelem_I1;
7781                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7782                                  t == TypeManager.char_type)
7783                                 return OpCodes.Stelem_I2;
7784                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7785                                 return OpCodes.Stelem_I4;
7786                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7787                                 return OpCodes.Stelem_I8;
7788                         else if (t == TypeManager.float_type)
7789                                 return OpCodes.Stelem_R4;
7790                         else if (t == TypeManager.double_type)
7791                                 return OpCodes.Stelem_R8;
7792                         else if (t == TypeManager.intptr_type) {
7793                                 has_type_arg = true;
7794                                 is_stobj = true;
7795                                 return OpCodes.Stobj;
7796                         } else if (t.IsValueType) {
7797                                 has_type_arg = true;
7798                                 is_stobj = true;
7799                                 return OpCodes.Stobj;
7800 #if GMCS_SOURCE
7801                         } else if (t.IsGenericParameter) {
7802                                 has_type_arg = true;
7803 #if MS_COMPATIBLE
7804                                 return OpCodes.Stelem;
7805 #else
7806                                 return OpCodes.Stelem_Any;
7807 #endif
7808 #endif
7809
7810                         } else if (t.IsPointer)
7811                                 return OpCodes.Stelem_I;
7812                         else
7813                                 return OpCodes.Stelem_Ref;
7814                 }
7815
7816                 MethodInfo FetchGetMethod ()
7817                 {
7818                         ModuleBuilder mb = CodeGen.Module.Builder;
7819                         int arg_count = ea.Arguments.Count;
7820                         Type [] args = new Type [arg_count];
7821                         MethodInfo get;
7822                         
7823                         for (int i = 0; i < arg_count; i++){
7824                                 //args [i++] = a.Type;
7825                                 args [i] = TypeManager.int32_type;
7826                         }
7827                         
7828                         get = mb.GetArrayMethod (
7829                                 ea.Expr.Type, "Get",
7830                                 CallingConventions.HasThis |
7831                                 CallingConventions.Standard,
7832                                 type, args);
7833                         return get;
7834                 }
7835                                 
7836
7837                 MethodInfo FetchAddressMethod ()
7838                 {
7839                         ModuleBuilder mb = CodeGen.Module.Builder;
7840                         int arg_count = ea.Arguments.Count;
7841                         Type [] args = new Type [arg_count];
7842                         MethodInfo address;
7843                         Type ret_type;
7844                         
7845                         ret_type = TypeManager.GetReferenceType (type);
7846                         
7847                         for (int i = 0; i < arg_count; i++){
7848                                 //args [i++] = a.Type;
7849                                 args [i] = TypeManager.int32_type;
7850                         }
7851                         
7852                         address = mb.GetArrayMethod (
7853                                 ea.Expr.Type, "Address",
7854                                 CallingConventions.HasThis |
7855                                 CallingConventions.Standard,
7856                                 ret_type, args);
7857
7858                         return address;
7859                 }
7860
7861                 //
7862                 // Load the array arguments into the stack.
7863                 //
7864                 // If we have been requested to cache the values (cached_locations array
7865                 // initialized), then load the arguments the first time and store them
7866                 // in locals.  otherwise load from local variables.
7867                 //
7868                 void LoadArrayAndArguments (EmitContext ec)
7869                 {
7870                         ILGenerator ig = ec.ig;
7871                         
7872                         ea.Expr.Emit (ec);
7873                         foreach (Argument a in ea.Arguments){
7874                                 Type argtype = a.Expr.Type;
7875                                 
7876                                 a.Expr.Emit (ec);
7877                                 
7878                                 if (argtype == TypeManager.int64_type)
7879                                         ig.Emit (OpCodes.Conv_Ovf_I);
7880                                 else if (argtype == TypeManager.uint64_type)
7881                                         ig.Emit (OpCodes.Conv_Ovf_I_Un);
7882                         }
7883                 }
7884
7885                 public void Emit (EmitContext ec, bool leave_copy)
7886                 {
7887                         int rank = ea.Expr.Type.GetArrayRank ();
7888                         ILGenerator ig = ec.ig;
7889
7890                         if (!prepared) {
7891                                 LoadArrayAndArguments (ec);
7892                                 
7893                                 if (rank == 1)
7894                                         EmitLoadOpcode (ig, type);
7895                                 else {
7896                                         MethodInfo method;
7897                                         
7898                                         method = FetchGetMethod ();
7899                                         ig.Emit (OpCodes.Call, method);
7900                                 }
7901                         } else
7902                                 LoadFromPtr (ec.ig, this.type);
7903                         
7904                         if (leave_copy) {
7905                                 ec.ig.Emit (OpCodes.Dup);
7906                                 temp = new LocalTemporary (this.type);
7907                                 temp.Store (ec);
7908                         }
7909                 }
7910                 
7911                 public override void Emit (EmitContext ec)
7912                 {
7913                         Emit (ec, false);
7914                 }
7915
7916                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7917                 {
7918                         int rank = ea.Expr.Type.GetArrayRank ();
7919                         ILGenerator ig = ec.ig;
7920                         Type t = source.Type;
7921                         prepared = prepare_for_load;
7922
7923                         if (prepare_for_load) {
7924                                 AddressOf (ec, AddressOp.LoadStore);
7925                                 ec.ig.Emit (OpCodes.Dup);
7926                                 source.Emit (ec);
7927                                 if (leave_copy) {
7928                                         ec.ig.Emit (OpCodes.Dup);
7929                                         temp = new LocalTemporary (this.type);
7930                                         temp.Store (ec);
7931                                 }
7932                                 StoreFromPtr (ec.ig, t);
7933                                 
7934                                 if (temp != null) {
7935                                         temp.Emit (ec);
7936                                         temp.Release (ec);
7937                                 }
7938                                 
7939                                 return;
7940                         }
7941                         
7942                         LoadArrayAndArguments (ec);
7943
7944                         if (rank == 1) {
7945                                 bool is_stobj, has_type_arg;
7946                                 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7947                                 //
7948                                 // The stobj opcode used by value types will need
7949                                 // an address on the stack, not really an array/array
7950                                 // pair
7951                                 //
7952                                 if (is_stobj)
7953                                         ig.Emit (OpCodes.Ldelema, t);
7954                                 
7955                                 source.Emit (ec);
7956                                 if (leave_copy) {
7957                                         ec.ig.Emit (OpCodes.Dup);
7958                                         temp = new LocalTemporary (this.type);
7959                                         temp.Store (ec);
7960                                 }
7961                                 
7962                                 if (is_stobj)
7963                                         ig.Emit (OpCodes.Stobj, t);
7964                                 else if (has_type_arg)
7965                                         ig.Emit (op, t);
7966                                 else
7967                                         ig.Emit (op);
7968                         } else {
7969                                 ModuleBuilder mb = CodeGen.Module.Builder;
7970                                 int arg_count = ea.Arguments.Count;
7971                                 Type [] args = new Type [arg_count + 1];
7972                                 MethodInfo set;
7973                                 
7974                                 source.Emit (ec);
7975                                 if (leave_copy) {
7976                                         ec.ig.Emit (OpCodes.Dup);
7977                                         temp = new LocalTemporary (this.type);
7978                                         temp.Store (ec);
7979                                 }
7980                                 
7981                                 for (int i = 0; i < arg_count; i++){
7982                                         //args [i++] = a.Type;
7983                                         args [i] = TypeManager.int32_type;
7984                                 }
7985
7986                                 args [arg_count] = type;
7987                                 
7988                                 set = mb.GetArrayMethod (
7989                                         ea.Expr.Type, "Set",
7990                                         CallingConventions.HasThis |
7991                                         CallingConventions.Standard,
7992                                         TypeManager.void_type, args);
7993                                 
7994                                 ig.Emit (OpCodes.Call, set);
7995                         }
7996                         
7997                         if (temp != null) {
7998                                 temp.Emit (ec);
7999                                 temp.Release (ec);
8000                         }
8001                 }
8002
8003                 public void AddressOf (EmitContext ec, AddressOp mode)
8004                 {
8005                         int rank = ea.Expr.Type.GetArrayRank ();
8006                         ILGenerator ig = ec.ig;
8007
8008                         LoadArrayAndArguments (ec);
8009
8010                         if (rank == 1){
8011                                 ig.Emit (OpCodes.Ldelema, type);
8012                         } else {
8013                                 MethodInfo address = FetchAddressMethod ();
8014                                 ig.Emit (OpCodes.Call, address);
8015                         }
8016                 }
8017
8018                 public void EmitGetLength (EmitContext ec, int dim)
8019                 {
8020                         int rank = ea.Expr.Type.GetArrayRank ();
8021                         ILGenerator ig = ec.ig;
8022
8023                         ea.Expr.Emit (ec);
8024                         if (rank == 1) {
8025                                 ig.Emit (OpCodes.Ldlen);
8026                                 ig.Emit (OpCodes.Conv_I4);
8027                         } else {
8028                                 IntLiteral.EmitInt (ig, dim);
8029                                 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
8030                         }
8031                 }
8032         }
8033         
8034         class Indexers {
8035                 // note that the ArrayList itself in mutable.  We just can't assign to 'Properties' again.
8036                 public readonly ArrayList Properties;
8037                 static Indexers empty;
8038
8039                 public struct Indexer {
8040                         public readonly PropertyInfo PropertyInfo;
8041                         public readonly MethodInfo Getter, Setter;
8042
8043                         public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
8044                         {
8045                                 this.PropertyInfo = property_info;
8046                                 this.Getter = get;
8047                                 this.Setter = set;
8048                         }
8049                 }
8050
8051                 static Indexers ()
8052                 {
8053                         empty = new Indexers (null);
8054                 }
8055
8056                 Indexers (ArrayList array)
8057                 {
8058                         Properties = array;
8059                 }
8060
8061                 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
8062                 {
8063                         bool dummy;
8064                         if (mi == null)
8065                                 return;
8066                         foreach (PropertyInfo property in mi){
8067                                 MethodInfo get, set;
8068                                 
8069                                 get = property.GetGetMethod (true);
8070                                 set = property.GetSetMethod (true);
8071                                 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
8072                                         get = null;
8073                                 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
8074                                         set = null;
8075                                 if (get != null || set != null) {
8076                                         if (ix == empty)
8077                                                 ix = new Indexers (new ArrayList ());
8078                                         ix.Properties.Add (new Indexer (property, get, set));
8079                                 }
8080                         }
8081                 }
8082
8083                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8084                 {
8085                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
8086
8087                         return TypeManager.MemberLookup (
8088                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
8089                                 BindingFlags.Public | BindingFlags.Instance |
8090                                 BindingFlags.DeclaredOnly, p_name, null);
8091                 }
8092                 
8093                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type) 
8094                 {
8095                         Indexers ix = empty;
8096
8097 #if GMCS_SOURCE
8098                         if (lookup_type.IsGenericParameter) {
8099                                 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8100                                 if (gc == null)
8101                                         return empty;
8102
8103                                 if (gc.HasClassConstraint)
8104                                         Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8105
8106                                 Type[] ifaces = gc.InterfaceConstraints;
8107                                 foreach (Type itype in ifaces)
8108                                         Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8109
8110                                 return ix;
8111                         }
8112 #endif
8113
8114                         Type copy = lookup_type;
8115                         while (copy != TypeManager.object_type && copy != null){
8116                                 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8117                                 copy = copy.BaseType;
8118                         }
8119
8120                         if (lookup_type.IsInterface) {
8121                                 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8122                                 if (ifaces != null) {
8123                                         foreach (Type itype in ifaces)
8124                                                 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8125                                 }
8126                         }
8127
8128                         return ix;
8129                 }
8130         }
8131
8132         /// <summary>
8133         ///   Expressions that represent an indexer call.
8134         /// </summary>
8135         public class IndexerAccess : Expression, IAssignMethod {
8136                 //
8137                 // Points to our "data" repository
8138                 //
8139                 MethodInfo get, set;
8140                 ArrayList set_arguments;
8141                 bool is_base_indexer;
8142
8143                 protected Type indexer_type;
8144                 protected Type current_type;
8145                 protected Expression instance_expr;
8146                 protected ArrayList arguments;
8147                 
8148                 public IndexerAccess (ElementAccess ea, Location loc)
8149                         : this (ea.Expr, false, loc)
8150                 {
8151                         this.arguments = ea.Arguments;
8152                 }
8153
8154                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8155                                          Location loc)
8156                 {
8157                         this.instance_expr = instance_expr;
8158                         this.is_base_indexer = is_base_indexer;
8159                         this.eclass = ExprClass.Value;
8160                         this.loc = loc;
8161                 }
8162
8163                 protected virtual bool CommonResolve (EmitContext ec)
8164                 {
8165                         indexer_type = instance_expr.Type;
8166                         current_type = ec.ContainerType;
8167
8168                         return true;
8169                 }
8170
8171                 public override Expression DoResolve (EmitContext ec)
8172                 {
8173                         if (!CommonResolve (ec))
8174                                 return null;
8175
8176                         //
8177                         // Step 1: Query for all `Item' *properties*.  Notice
8178                         // that the actual methods are pointed from here.
8179                         //
8180                         // This is a group of properties, piles of them.  
8181
8182                         ArrayList AllGetters = null;
8183
8184                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8185                         if (ilist.Properties != null) {
8186                                 AllGetters = new ArrayList(ilist.Properties.Count);
8187                                 foreach (Indexers.Indexer ix in ilist.Properties) {
8188                                         if (ix.Getter != null)
8189                                                 AllGetters.Add (ix.Getter);
8190                                 }
8191                         }
8192
8193                         if (AllGetters == null) {
8194                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8195                                         TypeManager.CSharpName (indexer_type));
8196                                 return null;
8197                         }
8198
8199                         if (AllGetters.Count == 0) {
8200                                 // FIXME: we cannot simply select first one as the error message is missleading when
8201                                 // multiple indexers exist
8202                                 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
8203                                 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
8204                                         TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
8205                                 return null;
8206                         }
8207
8208                         get = (MethodInfo)Invocation.OverloadResolve (ec, new MethodGroupExpr (AllGetters, loc),
8209                                         arguments, false, loc);
8210
8211                         if (get == null) {
8212                                 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
8213                                 return null;
8214                         }
8215
8216                         //
8217                         // Only base will allow this invocation to happen.
8218                         //
8219                         if (get.IsAbstract && this is BaseIndexerAccess){
8220                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
8221                                 return null;
8222                         }
8223
8224                         type = get.ReturnType;
8225                         if (type.IsPointer && !ec.InUnsafe){
8226                                 UnsafeError (loc);
8227                                 return null;
8228                         }
8229
8230                         instance_expr.CheckMarshalByRefAccess ();
8231                         
8232                         eclass = ExprClass.IndexerAccess;
8233                         return this;
8234                 }
8235
8236                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8237                 {
8238                         if (right_side == EmptyExpression.OutAccess) {
8239                                 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8240                                               GetSignatureForError ());
8241                                 return null;
8242                         }
8243
8244                         // if the indexer returns a value type, and we try to set a field in it
8245                         if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8246                                 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
8247                                               GetSignatureForError ());
8248                                 return null;
8249                         }
8250
8251                         ArrayList AllSetters = new ArrayList();
8252                         if (!CommonResolve (ec))
8253                                 return null;
8254
8255                         bool found_any = false, found_any_setters = false;
8256
8257                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8258                         if (ilist.Properties != null) {
8259                                 found_any = true;
8260                                 foreach (Indexers.Indexer ix in ilist.Properties) {
8261                                         if (ix.Setter != null)
8262                                                 AllSetters.Add (ix.Setter);
8263                                 }
8264                         }
8265                         if (AllSetters.Count > 0) {
8266                                 found_any_setters = true;
8267                                 set_arguments = (ArrayList) arguments.Clone ();
8268                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8269                                 set = (MethodInfo) Invocation.OverloadResolve (
8270                                         ec, new MethodGroupExpr (AllSetters, loc),
8271                                         set_arguments, false, loc);
8272                         }
8273
8274                         if (!found_any) {
8275                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8276                                               TypeManager.CSharpName (indexer_type));
8277                                 return null;
8278                         }
8279
8280                         if (!found_any_setters) {
8281                                 Error (154, "indexer can not be used in this context, because " +
8282                                        "it lacks a `set' accessor");
8283                                 return null;
8284                         }
8285
8286                         if (set == null) {
8287                                 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
8288                                 return null;
8289                         }
8290
8291                         //
8292                         // Only base will allow this invocation to happen.
8293                         //
8294                         if (set.IsAbstract && this is BaseIndexerAccess){
8295                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
8296                                 return null;
8297                         }
8298
8299                         //
8300                         // Now look for the actual match in the list of indexers to set our "return" type
8301                         //
8302                         type = TypeManager.void_type;   // default value
8303                         foreach (Indexers.Indexer ix in ilist.Properties){
8304                                 if (ix.Setter == set){
8305                                         type = ix.PropertyInfo.PropertyType;
8306                                         break;
8307                                 }
8308                         }
8309
8310                         instance_expr.CheckMarshalByRefAccess ();
8311
8312                         eclass = ExprClass.IndexerAccess;
8313                         return this;
8314                 }
8315                 
8316                 bool prepared = false;
8317                 LocalTemporary temp;
8318                 
8319                 public void Emit (EmitContext ec, bool leave_copy)
8320                 {
8321                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
8322                         if (leave_copy) {
8323                                 ec.ig.Emit (OpCodes.Dup);
8324                                 temp = new LocalTemporary (Type);
8325                                 temp.Store (ec);
8326                         }
8327                 }
8328                 
8329                 //
8330                 // source is ignored, because we already have a copy of it from the
8331                 // LValue resolution and we have already constructed a pre-cached
8332                 // version of the arguments (ea.set_arguments);
8333                 //
8334                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8335                 {
8336                         prepared = prepare_for_load;
8337                         Argument a = (Argument) set_arguments [set_arguments.Count - 1];
8338                         
8339                         if (prepared) {
8340                                 source.Emit (ec);
8341                                 if (leave_copy) {
8342                                         ec.ig.Emit (OpCodes.Dup);
8343                                         temp = new LocalTemporary (Type);
8344                                         temp.Store (ec);
8345                                 }
8346                         } else if (leave_copy) {
8347                                 temp = new LocalTemporary (Type);
8348                                 source.Emit (ec);
8349                                 temp.Store (ec);
8350                                 a.Expr = temp;
8351                         }
8352                         
8353                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
8354                         
8355                         if (temp != null) {
8356                                 temp.Emit (ec);
8357                                 temp.Release (ec);
8358                         }
8359                 }
8360                 
8361                 
8362                 public override void Emit (EmitContext ec)
8363                 {
8364                         Emit (ec, false);
8365                 }
8366
8367                 public override string GetSignatureForError ()
8368                 {
8369                         // FIXME: print the argument list of the indexer
8370                         return instance_expr.GetSignatureForError () + ".this[...]";
8371                 }
8372         }
8373
8374         /// <summary>
8375         ///   The base operator for method names
8376         /// </summary>
8377         public class BaseAccess : Expression {
8378                 public readonly string Identifier;
8379
8380                 public BaseAccess (string member, Location l)
8381                 {
8382                         this.Identifier = member;
8383                         loc = l;
8384                 }
8385
8386                 public BaseAccess (string member, TypeArguments args, Location l)
8387                         : this (member, l)
8388                 {
8389                         this.args = args;
8390                 }
8391
8392                 TypeArguments args;
8393
8394                 public override Expression DoResolve (EmitContext ec)
8395                 {
8396                         Expression c = CommonResolve (ec);
8397
8398                         if (c == null)
8399                                 return null;
8400
8401                         //
8402                         // MethodGroups use this opportunity to flag an error on lacking ()
8403                         //
8404                         if (!(c is MethodGroupExpr))
8405                                 return c.Resolve (ec);
8406                         return c;
8407                 }
8408
8409                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8410                 {
8411                         Expression c = CommonResolve (ec);
8412
8413                         if (c == null)
8414                                 return null;
8415
8416                         //
8417                         // MethodGroups use this opportunity to flag an error on lacking ()
8418                         //
8419                         if (! (c is MethodGroupExpr))
8420                                 return c.DoResolveLValue (ec, right_side);
8421
8422                         return c;
8423                 }
8424
8425                 Expression CommonResolve (EmitContext ec)
8426                 {
8427                         Expression member_lookup;
8428                         Type current_type = ec.ContainerType;
8429                         Type base_type = current_type.BaseType;
8430
8431                         if (ec.IsStatic){
8432                                 Error (1511, "Keyword `base' is not available in a static method");
8433                                 return null;
8434                         }
8435
8436                         if (ec.IsFieldInitializer){
8437                                 Error (1512, "Keyword `base' is not available in the current context");
8438                                 return null;
8439                         }
8440                         
8441                         member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8442                                                       AllMemberTypes, AllBindingFlags, loc);
8443                         if (member_lookup == null) {
8444                                 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8445                                 return null;
8446                         }
8447
8448                         Expression left;
8449                         
8450                         if (ec.IsStatic)
8451                                 left = new TypeExpression (base_type, loc);
8452                         else
8453                                 left = ec.GetThis (loc);
8454
8455                         MemberExpr me = (MemberExpr) member_lookup;
8456                         
8457                         Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8458
8459                         if (e is PropertyExpr) {
8460                                 PropertyExpr pe = (PropertyExpr) e;
8461
8462                                 pe.IsBase = true;
8463                         }
8464
8465                         MethodGroupExpr mg = e as MethodGroupExpr;
8466                         if (mg != null)
8467                                 mg.IsBase = true;
8468
8469                         if (args != null) {
8470                                 if (mg != null)
8471                                         return mg.ResolveGeneric (ec, args);
8472
8473                                 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8474                                               Identifier);
8475                                 return null;
8476                         }
8477
8478                         return e;
8479                 }
8480
8481                 public override void Emit (EmitContext ec)
8482                 {
8483                         throw new Exception ("Should never be called"); 
8484                 }
8485         }
8486
8487         /// <summary>
8488         ///   The base indexer operator
8489         /// </summary>
8490         public class BaseIndexerAccess : IndexerAccess {
8491                 public BaseIndexerAccess (ArrayList args, Location loc)
8492                         : base (null, true, loc)
8493                 {
8494                         arguments = new ArrayList ();
8495                         foreach (Expression tmp in args)
8496                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8497                 }
8498
8499                 protected override bool CommonResolve (EmitContext ec)
8500                 {
8501                         instance_expr = ec.GetThis (loc);
8502
8503                         current_type = ec.ContainerType.BaseType;
8504                         indexer_type = current_type;
8505
8506                         foreach (Argument a in arguments){
8507                                 if (!a.Resolve (ec, loc))
8508                                         return false;
8509                         }
8510
8511                         return true;
8512                 }
8513         }
8514         
8515         /// <summary>
8516         ///   This class exists solely to pass the Type around and to be a dummy
8517         ///   that can be passed to the conversion functions (this is used by
8518         ///   foreach implementation to typecast the object return value from
8519         ///   get_Current into the proper type.  All code has been generated and
8520         ///   we only care about the side effect conversions to be performed
8521         ///
8522         ///   This is also now used as a placeholder where a no-action expression
8523         ///   is needed (the `New' class).
8524         /// </summary>
8525         public class EmptyExpression : Expression {
8526                 public static readonly EmptyExpression Null = new EmptyExpression ();
8527
8528                 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8529                 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8530                 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8531
8532                 static EmptyExpression temp = new EmptyExpression ();
8533                 public static EmptyExpression Grab ()
8534                 {
8535                         EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8536                         temp = null;
8537                         return retval;
8538                 }
8539
8540                 public static void Release (EmptyExpression e)
8541                 {
8542                         temp = e;
8543                 }
8544
8545                 // TODO: should be protected
8546                 public EmptyExpression ()
8547                 {
8548                         type = TypeManager.object_type;
8549                         eclass = ExprClass.Value;
8550                         loc = Location.Null;
8551                 }
8552
8553                 public EmptyExpression (Type t)
8554                 {
8555                         type = t;
8556                         eclass = ExprClass.Value;
8557                         loc = Location.Null;
8558                 }
8559                 
8560                 public override Expression DoResolve (EmitContext ec)
8561                 {
8562                         return this;
8563                 }
8564
8565                 public override void Emit (EmitContext ec)
8566                 {
8567                         // nothing, as we only exist to not do anything.
8568                 }
8569
8570                 //
8571                 // This is just because we might want to reuse this bad boy
8572                 // instead of creating gazillions of EmptyExpressions.
8573                 // (CanImplicitConversion uses it)
8574                 //
8575                 public void SetType (Type t)
8576                 {
8577                         type = t;
8578                 }
8579         }
8580
8581         public class UserCast : Expression {
8582                 MethodBase method;
8583                 Expression source;
8584                 
8585                 public UserCast (MethodInfo method, Expression source, Location l)
8586                 {
8587                         this.method = method;
8588                         this.source = source;
8589                         type = method.ReturnType;
8590                         eclass = ExprClass.Value;
8591                         loc = l;
8592                 }
8593
8594                 public Expression Source {
8595                         get {
8596                                 return source;
8597                         }
8598                 }
8599                         
8600                 public override Expression DoResolve (EmitContext ec)
8601                 {
8602                         //
8603                         // We are born fully resolved
8604                         //
8605                         return this;
8606                 }
8607
8608                 public override void Emit (EmitContext ec)
8609                 {
8610                         ILGenerator ig = ec.ig;
8611
8612                         source.Emit (ec);
8613                         
8614                         if (method is MethodInfo)
8615                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8616                         else
8617                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8618
8619                 }
8620         }
8621
8622         // <summary>
8623         //   This class is used to "construct" the type during a typecast
8624         //   operation.  Since the Type.GetType class in .NET can parse
8625         //   the type specification, we just use this to construct the type
8626         //   one bit at a time.
8627         // </summary>
8628         public class ComposedCast : TypeExpr {
8629                 Expression left;
8630                 string dim;
8631                 
8632                 public ComposedCast (Expression left, string dim)
8633                         : this (left, dim, left.Location)
8634                 {
8635                 }
8636
8637                 public ComposedCast (Expression left, string dim, Location l)
8638                 {
8639                         this.left = left;
8640                         this.dim = dim;
8641                         loc = l;
8642                 }
8643
8644 #if GMCS_SOURCE
8645                 public Expression RemoveNullable ()
8646                 {
8647                         if (dim.EndsWith ("?")) {
8648                                 dim = dim.Substring (0, dim.Length - 1);
8649                                 if (dim == "")
8650                                         return left;
8651                         }
8652
8653                         return this;
8654                 }
8655 #endif
8656
8657                 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8658                 {
8659                         TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8660                         if (lexpr == null)
8661                                 return null;
8662
8663                         Type ltype = lexpr.Type;
8664                         if ((ltype == TypeManager.void_type) && (dim != "*")) {
8665                                 Error_VoidInvalidInTheContext (loc);
8666                                 return null;
8667                         }
8668
8669 #if GMCS_SOURCE
8670                         if ((dim.Length > 0) && (dim [0] == '?')) {
8671                                 TypeExpr nullable = new NullableType (left, loc);
8672                                 if (dim.Length > 1)
8673                                         nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8674                                 return nullable.ResolveAsTypeTerminal (ec, false);
8675                         }
8676 #endif
8677
8678                         if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8679                                 return null;
8680
8681                         if (dim != "" && dim [0] == '[' &&
8682                             (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8683                                 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8684                                 return null;
8685                         }
8686
8687                         if (dim != "")
8688                                 type = TypeManager.GetConstructedType (ltype, dim);
8689                         else
8690                                 type = ltype;
8691
8692                         if (type == null)
8693                                 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8694
8695                         if (type.IsPointer && !ec.IsInUnsafeScope){
8696                                 UnsafeError (loc);
8697                                 return null;
8698                         }
8699
8700                         eclass = ExprClass.Type;
8701                         return this;
8702                 }
8703
8704                 public override string Name {
8705                         get { return left + dim; }
8706                 }
8707
8708                 public override string FullName {
8709                         get { return type.FullName; }
8710                 }
8711
8712                 public override string GetSignatureForError ()
8713                 {
8714                         return left.GetSignatureForError () + dim;
8715                 }
8716         }
8717
8718         public class FixedBufferPtr : Expression {
8719                 Expression array;
8720
8721                 public FixedBufferPtr (Expression array, Type array_type, Location l)
8722                 {
8723                         this.array = array;
8724                         this.loc = l;
8725
8726                         type = TypeManager.GetPointerType (array_type);
8727                         eclass = ExprClass.Value;
8728                 }
8729
8730                 public override void Emit(EmitContext ec)
8731                 {
8732                         array.Emit (ec);
8733                 }
8734
8735                 public override Expression DoResolve (EmitContext ec)
8736                 {
8737                         //
8738                         // We are born fully resolved
8739                         //
8740                         return this;
8741                 }
8742         }
8743
8744
8745         //
8746         // This class is used to represent the address of an array, used
8747         // only by the Fixed statement, this generates "&a [0]" construct
8748         // for fixed (char *pa = a)
8749         //
8750         public class ArrayPtr : FixedBufferPtr {
8751                 Type array_type;
8752                 
8753                 public ArrayPtr (Expression array, Type array_type, Location l):
8754                         base (array, array_type, l)
8755                 {
8756                         this.array_type = array_type;
8757                 }
8758
8759                 public override void Emit (EmitContext ec)
8760                 {
8761                         base.Emit (ec);
8762                         
8763                         ILGenerator ig = ec.ig;
8764                         IntLiteral.EmitInt (ig, 0);
8765                         ig.Emit (OpCodes.Ldelema, array_type);
8766                 }
8767         }
8768
8769         //
8770         // Used by the fixed statement
8771         //
8772         public class StringPtr : Expression {
8773                 LocalBuilder b;
8774                 
8775                 public StringPtr (LocalBuilder b, Location l)
8776                 {
8777                         this.b = b;
8778                         eclass = ExprClass.Value;
8779                         type = TypeManager.char_ptr_type;
8780                         loc = l;
8781                 }
8782
8783                 public override Expression DoResolve (EmitContext ec)
8784                 {
8785                         // This should never be invoked, we are born in fully
8786                         // initialized state.
8787
8788                         return this;
8789                 }
8790
8791                 public override void Emit (EmitContext ec)
8792                 {
8793                         ILGenerator ig = ec.ig;
8794
8795                         ig.Emit (OpCodes.Ldloc, b);
8796                         ig.Emit (OpCodes.Conv_I);
8797                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8798                         ig.Emit (OpCodes.Add);
8799                 }
8800         }
8801         
8802         //
8803         // Implements the `stackalloc' keyword
8804         //
8805         public class StackAlloc : Expression {
8806                 Type otype;
8807                 Expression t;
8808                 Expression count;
8809                 
8810                 public StackAlloc (Expression type, Expression count, Location l)
8811                 {
8812                         t = type;
8813                         this.count = count;
8814                         loc = l;
8815                 }
8816
8817                 public override Expression DoResolve (EmitContext ec)
8818                 {
8819                         count = count.Resolve (ec);
8820                         if (count == null)
8821                                 return null;
8822                         
8823                         if (count.Type != TypeManager.int32_type){
8824                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8825                                 if (count == null)
8826                                         return null;
8827                         }
8828
8829                         Constant c = count as Constant;
8830                         if (c != null && c.IsNegative) {
8831                                 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8832                                 return null;
8833                         }
8834
8835                         if (ec.InCatch || ec.InFinally) {
8836                                 Error (255, "Cannot use stackalloc in finally or catch");
8837                                 return null;
8838                         }
8839
8840                         TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8841                         if (texpr == null)
8842                                 return null;
8843
8844                         otype = texpr.Type;
8845
8846                         if (!TypeManager.VerifyUnManaged (otype, loc))
8847                                 return null;
8848
8849                         type = TypeManager.GetPointerType (otype);
8850                         eclass = ExprClass.Value;
8851
8852                         return this;
8853                 }
8854
8855                 public override void Emit (EmitContext ec)
8856                 {
8857                         int size = GetTypeSize (otype);
8858                         ILGenerator ig = ec.ig;
8859                                 
8860                         if (size == 0)
8861                                 ig.Emit (OpCodes.Sizeof, otype);
8862                         else
8863                                 IntConstant.EmitInt (ig, size);
8864                         count.Emit (ec);
8865                         ig.Emit (OpCodes.Mul);
8866                         ig.Emit (OpCodes.Localloc);
8867                 }
8868         }
8869 }