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