Tue Nov 14 16:06:37 CET 2006 Paolo Molaro <lupus@ximian.com>
[mono.git] / mcs / mcs / expression.cs
1 //
2 // expression.cs: Expression representation for the IL tree.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Marek Safar (marek.safar@seznam.cz)
7 //
8 // (C) 2001, 2002, 2003 Ximian, Inc.
9 // (C) 2003, 2004 Novell, Inc.
10 //
11 #define USE_OLD
12
13 namespace Mono.CSharp {
14         using System;
15         using System.Collections;
16         using System.Reflection;
17         using System.Reflection.Emit;
18         using System.Text;
19
20         /// <summary>
21         ///   This is just a helper class, it is generated by Unary, UnaryMutator
22         ///   when an overloaded method has been found.  It just emits the code for a
23         ///   static call.
24         /// </summary>
25         public class StaticCallExpr : ExpressionStatement {
26                 ArrayList args;
27                 MethodInfo mi;
28
29                 public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
30                 {
31                         mi = m;
32                         args = a;
33
34                         type = m.ReturnType;
35                         eclass = ExprClass.Value;
36                         loc = l;
37                 }
38
39                 public override Expression DoResolve (EmitContext ec)
40                 {
41                         //
42                         // We are born fully resolved
43                         //
44                         return this;
45                 }
46
47                 public override void Emit (EmitContext ec)
48                 {
49                         if (args != null) 
50                                 Invocation.EmitArguments (ec, mi, args, false, null);
51
52                         ec.ig.Emit (OpCodes.Call, mi);
53                         return;
54                 }
55                 
56                 static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
57                                                          Expression e, Location loc)
58                 {
59                         ArrayList args;
60                         MethodBase method;
61                         
62                         args = new ArrayList (1);
63                         Argument a = new Argument (e, Argument.AType.Expression);
64
65                         // We need to resolve the arguments before sending them in !
66                         if (!a.Resolve (ec, loc))
67                                 return null;
68
69                         args.Add (a);
70                         method = Invocation.OverloadResolve (
71                                 ec, (MethodGroupExpr) mg, args, false, loc);
72
73                         if (method == null)
74                                 return null;
75
76                         return new StaticCallExpr ((MethodInfo) method, args, loc);
77                 }
78
79                 public override void EmitStatement (EmitContext ec)
80                 {
81                         Emit (ec);
82                         if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
83                                 ec.ig.Emit (OpCodes.Pop);
84                 }
85                 
86                 public MethodInfo Method {
87                         get { return mi; }
88                 }
89         }
90
91         public class ParenthesizedExpression : Expression
92         {
93                 public Expression Expr;
94
95                 public ParenthesizedExpression (Expression expr)
96                 {
97                         this.Expr = expr;
98                 }
99
100                 public override Expression DoResolve (EmitContext ec)
101                 {
102                         Expr = Expr.Resolve (ec);
103                         return Expr;
104                 }
105
106                 public override void Emit (EmitContext ec)
107                 {
108                         throw new Exception ("Should not happen");
109                 }
110
111                 public override Location Location
112                 {
113                         get {
114                                 return Expr.Location;
115                         }
116                 }
117         }
118         
119         /// <summary>
120         ///   Unary expressions.  
121         /// </summary>
122         ///
123         /// <remarks>
124         ///   Unary implements unary expressions.   It derives from
125         ///   ExpressionStatement becuase the pre/post increment/decrement
126         ///   operators can be used in a statement context.
127         /// </remarks>
128         public class Unary : Expression {
129                 public enum Operator : byte {
130                         UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
131                         Indirection, AddressOf,  TOP
132                 }
133
134                 public Operator Oper;
135                 public Expression Expr;
136                 
137                 public Unary (Operator op, Expression expr, Location loc)
138                 {
139                         this.Oper = op;
140                         this.Expr = expr;
141                         this.loc = loc;
142                 }
143
144                 /// <summary>
145                 ///   Returns a stringified representation of the Operator
146                 /// </summary>
147                 static public string OperName (Operator oper)
148                 {
149                         switch (oper){
150                         case Operator.UnaryPlus:
151                                 return "+";
152                         case Operator.UnaryNegation:
153                                 return "-";
154                         case Operator.LogicalNot:
155                                 return "!";
156                         case Operator.OnesComplement:
157                                 return "~";
158                         case Operator.AddressOf:
159                                 return "&";
160                         case Operator.Indirection:
161                                 return "*";
162                         }
163
164                         return oper.ToString ();
165                 }
166
167                 public static readonly string [] oper_names;
168
169                 static Unary ()
170                 {
171                         oper_names = new string [(int)Operator.TOP];
172
173                         oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
174                         oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
175                         oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
176                         oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
177                         oper_names [(int) Operator.Indirection] = "op_Indirection";
178                         oper_names [(int) Operator.AddressOf] = "op_AddressOf";
179                 }
180
181                 public static void Error_OperatorCannotBeApplied (Location loc, string oper, Type t)
182                 {
183                         Error_OperatorCannotBeApplied (loc, oper, TypeManager.CSharpName (t));
184                 }
185
186                 public static void Error_OperatorCannotBeApplied (Location loc, string oper, string type)
187                 {
188                         Report.Error (23, loc, "The `{0}' operator cannot be applied to operand of type `{1}'",
189                                 oper, type);
190                 }
191
192                 void Error23 (Type t)
193                 {
194                         Error_OperatorCannotBeApplied (loc, OperName (Oper), t);
195                 }
196
197                 /// <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, 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                         AnonymousMethodHost host = null;
3724                         ToplevelBlock toplevel = block.Toplevel;
3725                         while (toplevel != null) {
3726                                 if (toplevel.IsLocalParameter (name)) {
3727                                         host = toplevel.AnonymousMethodHost;
3728                                         break;
3729                                 }
3730
3731                                 toplevel = toplevel.Container;
3732                         }
3733
3734                         variable = host.AddParameter (par, idx);
3735                         type = variable.Type;
3736                         return true;
3737                 }
3738
3739                 public override int GetHashCode()
3740                 {
3741                         return name.GetHashCode ();
3742                 }
3743
3744                 public override bool Equals (object obj)
3745                 {
3746                         ParameterReference pr = obj as ParameterReference;
3747                         if (pr == null)
3748                                 return false;
3749
3750                         return name == pr.name && block == pr.block;
3751                 }
3752
3753                 //
3754                 // Notice that for ref/out parameters, the type exposed is not the
3755                 // same type exposed externally.
3756                 //
3757                 // for "ref int a":
3758                 //   externally we expose "int&"
3759                 //   here we expose       "int".
3760                 //
3761                 // We record this in "is_ref".  This means that the type system can treat
3762                 // the type as it is expected, but when we generate the code, we generate
3763                 // the alternate kind of code.
3764                 //
3765                 public override Expression DoResolve (EmitContext ec)
3766                 {
3767                         if (!DoResolveBase (ec))
3768                                 return null;
3769
3770                         if (is_out && ec.DoFlowAnalysis &&
3771                             (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3772                                 return null;
3773
3774                         return this;
3775                 }
3776
3777                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3778                 {
3779                         if (!DoResolveBase (ec))
3780                                 return null;
3781
3782                         SetAssigned (ec);
3783
3784                         return this;
3785                 }
3786
3787                 static public void EmitLdArg (ILGenerator ig, int x)
3788                 {
3789                         if (x <= 255){
3790                                 switch (x){
3791                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3792                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3793                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3794                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3795                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3796                                 }
3797                         } else
3798                                 ig.Emit (OpCodes.Ldarg, x);
3799                 }
3800                 
3801                 public override string ToString ()
3802                 {
3803                         return "ParameterReference[" + name + "]";
3804                 }
3805         }
3806         
3807         /// <summary>
3808         ///   Used for arguments to New(), Invocation()
3809         /// </summary>
3810         public class Argument {
3811                 public enum AType : byte {
3812                         Expression,
3813                         Ref,
3814                         Out,
3815                         ArgList
3816                 };
3817
3818                 public readonly AType ArgType;
3819                 public Expression Expr;
3820                 
3821                 public Argument (Expression expr, AType type)
3822                 {
3823                         this.Expr = expr;
3824                         this.ArgType = type;
3825                 }
3826
3827                 public Argument (Expression expr)
3828                 {
3829                         this.Expr = expr;
3830                         this.ArgType = AType.Expression;
3831                 }
3832
3833                 public Type Type {
3834                         get {
3835                                 if (ArgType == AType.Ref || ArgType == AType.Out)
3836                                         return TypeManager.GetReferenceType (Expr.Type);
3837                                 else
3838                                         return Expr.Type;
3839                         }
3840                 }
3841
3842                 public Parameter.Modifier Modifier
3843                 {
3844                         get {
3845                                 switch (ArgType) {
3846                                         case AType.Out:
3847                                                 return Parameter.Modifier.OUT;
3848
3849                                         case AType.Ref:
3850                                                 return Parameter.Modifier.REF;
3851
3852                                         default:
3853                                                 return Parameter.Modifier.NONE;
3854                                 }
3855                         }
3856                 }
3857
3858                 public static string FullDesc (Argument a)
3859                 {
3860                         if (a.ArgType == AType.ArgList)
3861                                 return "__arglist";
3862
3863                         return (a.ArgType == AType.Ref ? "ref " :
3864                                 (a.ArgType == AType.Out ? "out " : "")) +
3865                                 TypeManager.CSharpName (a.Expr.Type);
3866                 }
3867
3868                 public bool ResolveMethodGroup (EmitContext ec)
3869                 {
3870                         SimpleName sn = Expr as SimpleName;
3871                         if (sn != null)
3872                                 Expr = sn.GetMethodGroup ();
3873
3874                         // FIXME: csc doesn't report any error if you try to use `ref' or
3875                         //        `out' in a delegate creation expression.
3876                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3877                         if (Expr == null)
3878                                 return false;
3879
3880                         return true;
3881                 }
3882
3883                 public bool Resolve (EmitContext ec, Location loc)
3884                 {
3885                         using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
3886                                 // Verify that the argument is readable
3887                                 if (ArgType != AType.Out)
3888                                         Expr = Expr.Resolve (ec);
3889
3890                                 // Verify that the argument is writeable
3891                                 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
3892                                         Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
3893
3894                                 return Expr != null;
3895                         }
3896                 }
3897
3898                 public void Emit (EmitContext ec)
3899                 {
3900                         if (ArgType != AType.Ref && ArgType != AType.Out) {
3901                                 Expr.Emit (ec);
3902                                 return;
3903                         }
3904
3905                         AddressOp mode = AddressOp.Store;
3906                         if (ArgType == AType.Ref)
3907                                 mode |= AddressOp.Load;
3908                                 
3909                         IMemoryLocation ml = (IMemoryLocation) Expr;
3910                         ParameterReference pr = ml as ParameterReference;
3911
3912                         //
3913                         // ParameterReferences might already be references, so we want
3914                         // to pass just the value
3915                         //
3916                         if (pr != null && pr.IsRef)
3917                                 pr.EmitLoad (ec);
3918                         else
3919                                 ml.AddressOf (ec, mode);
3920                 }
3921         }
3922
3923         /// <summary>
3924         ///   Invocation of methods or delegates.
3925         /// </summary>
3926         public class Invocation : ExpressionStatement {
3927                 public readonly ArrayList Arguments;
3928
3929                 Expression expr;
3930                 MethodBase method = null;
3931                 
3932                 //
3933                 // arguments is an ArrayList, but we do not want to typecast,
3934                 // as it might be null.
3935                 //
3936                 // FIXME: only allow expr to be a method invocation or a
3937                 // delegate invocation (7.5.5)
3938                 //
3939                 public Invocation (Expression expr, ArrayList arguments)
3940                 {
3941                         this.expr = expr;
3942                         Arguments = arguments;
3943                         loc = expr.Location;
3944                 }
3945
3946                 public Expression Expr {
3947                         get {
3948                                 return expr;
3949                         }
3950                 }
3951
3952                 /// <summary>
3953                 ///   Determines "better conversion" as specified in 14.4.2.3
3954                 ///
3955                 ///    Returns : p    if a->p is better,
3956                 ///              q    if a->q is better,
3957                 ///              null if neither is better
3958                 /// </summary>
3959                 static Type BetterConversion (EmitContext ec, Argument a, Type p, Type q)
3960                 {
3961                         Type argument_type = TypeManager.TypeToCoreType (a.Type);
3962                         Expression argument_expr = a.Expr;
3963
3964                         if (argument_type == null)
3965                                 throw new Exception ("Expression of type " + a.Expr +
3966                                                      " does not resolve its type");
3967
3968                         if (p == null || q == null)
3969                                 throw new InternalErrorException ("BetterConversion Got a null conversion");
3970
3971                         if (p == q)
3972                                 return null;
3973
3974                         if (argument_expr is NullLiteral) {
3975                                 //
3976                                 // If the argument is null and one of the types to compare is 'object' and
3977                                 // the other is a reference type, we prefer the other.
3978                                 //
3979                                 // This follows from the usual rules:
3980                                 //   * There is an implicit conversion from 'null' to type 'object'
3981                                 //   * There is an implicit conversion from 'null' to any reference type
3982                                 //   * There is an implicit conversion from any reference type to type 'object'
3983                                 //   * There is no implicit conversion from type 'object' to other reference types
3984                                 //  => Conversion of 'null' to a reference type is better than conversion to 'object'
3985                                 //
3986                                 //  FIXME: This probably isn't necessary, since the type of a NullLiteral is the 
3987                                 //         null type. I think it used to be 'object' and thus needed a special 
3988                                 //         case to avoid the immediately following two checks.
3989                                 //
3990                                 if (!p.IsValueType && q == TypeManager.object_type)
3991                                         return p;
3992                                 if (!q.IsValueType && p == TypeManager.object_type)
3993                                         return q;
3994                         }
3995                                 
3996                         if (argument_type == p)
3997                                 return p;
3998
3999                         if (argument_type == q)
4000                                 return q;
4001
4002                         Expression p_tmp = new EmptyExpression (p);
4003                         Expression q_tmp = new EmptyExpression (q);
4004
4005                         bool p_to_q = Convert.ImplicitConversionExists (ec, p_tmp, q);
4006                         bool q_to_p = Convert.ImplicitConversionExists (ec, q_tmp, p);
4007
4008                         if (p_to_q && !q_to_p)
4009                                 return p;
4010
4011                         if (q_to_p && !p_to_q)
4012                                 return q;
4013
4014                         if (p == TypeManager.sbyte_type)
4015                                 if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
4016                                     q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4017                                         return p;
4018                         if (q == TypeManager.sbyte_type)
4019                                 if (p == TypeManager.byte_type || p == TypeManager.ushort_type ||
4020                                     p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4021                                         return q;
4022
4023                         if (p == TypeManager.short_type)
4024                                 if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
4025                                     q == TypeManager.uint64_type)
4026                                         return p;
4027                         if (q == TypeManager.short_type)
4028                                 if (p == TypeManager.ushort_type || p == TypeManager.uint32_type ||
4029                                     p == TypeManager.uint64_type)
4030                                         return q;
4031
4032                         if (p == TypeManager.int32_type)
4033                                 if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
4034                                         return p;
4035                         if (q == TypeManager.int32_type)
4036                                 if (p == TypeManager.uint32_type || p == TypeManager.uint64_type)
4037                                         return q;
4038
4039                         if (p == TypeManager.int64_type)
4040                                 if (q == TypeManager.uint64_type)
4041                                         return p;
4042                         if (q == TypeManager.int64_type)
4043                                 if (p == TypeManager.uint64_type)
4044                                         return q;
4045
4046                         return null;
4047                 }
4048
4049                 static Type MoreSpecific (Type p, Type q)
4050                 {
4051                         if (TypeManager.IsGenericParameter (p) && !TypeManager.IsGenericParameter (q))
4052                                 return q;
4053                         if (!TypeManager.IsGenericParameter (p) && TypeManager.IsGenericParameter (q))
4054                                 return p;
4055
4056                         if (TypeManager.HasElementType (p)) {
4057                                 Type pe = TypeManager.GetElementType (p);
4058                                 Type qe = TypeManager.GetElementType (q);
4059                                 Type specific = MoreSpecific (pe, qe);
4060                                 if (specific == pe)
4061                                         return p;
4062                                 if (specific == qe)
4063                                         return q;
4064                         } else if (TypeManager.IsGenericType (p)) {
4065                                 Type[] pargs = TypeManager.GetTypeArguments (p);
4066                                 Type[] qargs = TypeManager.GetTypeArguments (q);
4067
4068                                 bool p_specific_at_least_once = false;
4069                                 bool q_specific_at_least_once = false;
4070
4071                                 for (int i = 0; i < pargs.Length; i++) {
4072                                         Type specific = MoreSpecific (pargs [i], qargs [i]);
4073                                         if (specific == pargs [i])
4074                                                 p_specific_at_least_once = true;
4075                                         if (specific == qargs [i])
4076                                                 q_specific_at_least_once = true;
4077                                 }
4078
4079                                 if (p_specific_at_least_once && !q_specific_at_least_once)
4080                                         return p;
4081                                 if (!p_specific_at_least_once && q_specific_at_least_once)
4082                                         return q;
4083                         }
4084
4085                         return null;
4086                 }
4087                 
4088                 /// <summary>
4089                 ///   Determines "Better function" between candidate
4090                 ///   and the current best match
4091                 /// </summary>
4092                 /// <remarks>
4093                 ///    Returns a boolean indicating :
4094                 ///     false if candidate ain't better
4095                 ///     true  if candidate is better than the current best match
4096                 /// </remarks>
4097                 static bool BetterFunction (EmitContext ec, ArrayList args, int argument_count,
4098                                             MethodBase candidate, bool candidate_params,
4099                                             MethodBase best, bool best_params)
4100                 {
4101                         ParameterData candidate_pd = TypeManager.GetParameterData (candidate);
4102                         ParameterData best_pd = TypeManager.GetParameterData (best);
4103                 
4104                         bool better_at_least_one = false;
4105                         bool same = true;
4106                         for (int j = 0; j < argument_count; ++j) {
4107                                 Argument a = (Argument) args [j];
4108
4109                                 Type ct = TypeManager.TypeToCoreType (candidate_pd.ParameterType (j));
4110                                 Type bt = TypeManager.TypeToCoreType (best_pd.ParameterType (j));
4111
4112                                 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4113                                         if (candidate_params)
4114                                                 ct = TypeManager.GetElementType (ct);
4115
4116                                 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
4117                                         if (best_params)
4118                                                 bt = TypeManager.GetElementType (bt);
4119
4120                                 if (ct.Equals (bt))
4121                                         continue;
4122
4123                                 same = false;
4124                                 Type better = BetterConversion (ec, a, ct, bt);
4125
4126                                 // for each argument, the conversion to 'ct' should be no worse than 
4127                                 // the conversion to 'bt'.
4128                                 if (better == bt)
4129                                         return false;
4130
4131                                 // for at least one argument, the conversion to 'ct' should be better than 
4132                                 // the conversion to 'bt'.
4133                                 if (better == ct)
4134                                         better_at_least_one = true;
4135                         }
4136
4137                         if (better_at_least_one)
4138                                 return true;
4139
4140                         //
4141                         // This handles the case
4142                         //
4143                         //   Add (float f1, float f2, float f3);
4144                         //   Add (params decimal [] foo);
4145                         //
4146                         // The call Add (3, 4, 5) should be ambiguous.  Without this check, the
4147                         // first candidate would've chosen as better.
4148                         //
4149                         if (!same)
4150                                 return false;
4151
4152                         //
4153                         // The two methods have equal parameter types.  Now apply tie-breaking rules
4154                         //
4155                         if (TypeManager.IsGenericMethod (best) && !TypeManager.IsGenericMethod (candidate))
4156                                 return true;
4157                         if (!TypeManager.IsGenericMethod (best) && TypeManager.IsGenericMethod (candidate))
4158                                 return false;
4159
4160                         //
4161                         // This handles the following cases:
4162                         //
4163                         //   Trim () is better than Trim (params char[] chars)
4164                         //   Concat (string s1, string s2, string s3) is better than
4165                         //     Concat (string s1, params string [] srest)
4166                         //   Foo (int, params int [] rest) is better than Foo (params int [] rest)
4167                         //
4168                         if (!candidate_params && best_params)
4169                                 return true;
4170                         if (candidate_params && !best_params)
4171                                 return false;
4172
4173                         int candidate_param_count = candidate_pd.Count;
4174                         int best_param_count = best_pd.Count;
4175
4176                         if (candidate_param_count != best_param_count)
4177                                 // can only happen if (candidate_params && best_params)
4178                                 return candidate_param_count > best_param_count;
4179
4180                         //
4181                         // now, both methods have the same number of parameters, and the parameters have the same types
4182                         // Pick the "more specific" signature
4183                         //
4184
4185                         MethodBase orig_candidate = TypeManager.DropGenericMethodArguments (candidate);
4186                         MethodBase orig_best = TypeManager.DropGenericMethodArguments (best);
4187
4188                         ParameterData orig_candidate_pd = TypeManager.GetParameterData (orig_candidate);
4189                         ParameterData orig_best_pd = TypeManager.GetParameterData (orig_best);
4190
4191                         bool specific_at_least_once = false;
4192                         for (int j = 0; j < candidate_param_count; ++j) {
4193                                 Type ct = TypeManager.TypeToCoreType (orig_candidate_pd.ParameterType (j));
4194                                 Type bt = TypeManager.TypeToCoreType (orig_best_pd.ParameterType (j));
4195                                 if (ct.Equals (bt))
4196                                         continue;
4197                                 Type specific = MoreSpecific (ct, bt);
4198                                 if (specific == bt)
4199                                         return false;
4200                                 if (specific == ct)
4201                                         specific_at_least_once = true;
4202                         }
4203
4204                         if (specific_at_least_once)
4205                                 return true;
4206
4207                         // FIXME: handle lifted operators
4208                         // ...
4209
4210                         return false;
4211                 }
4212
4213                 internal static bool IsOverride (MethodBase cand_method, MethodBase base_method)
4214                 {
4215                         if (!IsAncestralType (base_method.DeclaringType, cand_method.DeclaringType))
4216                                 return false;
4217
4218                         ParameterData cand_pd = TypeManager.GetParameterData (cand_method);
4219                         ParameterData base_pd = TypeManager.GetParameterData (base_method);
4220                 
4221                         if (cand_pd.Count != base_pd.Count)
4222                                 return false;
4223
4224                         for (int j = 0; j < cand_pd.Count; ++j) {
4225                                 Parameter.Modifier cm = cand_pd.ParameterModifier (j);
4226                                 Parameter.Modifier bm = base_pd.ParameterModifier (j);
4227                                 Type ct = TypeManager.TypeToCoreType (cand_pd.ParameterType (j));
4228                                 Type bt = TypeManager.TypeToCoreType (base_pd.ParameterType (j));
4229
4230                                 if (cm != bm || ct != bt)
4231                                         return false;
4232                         }
4233
4234                         return true;
4235                 }
4236
4237                 public static string FullMethodDesc (MethodBase mb)
4238                 {
4239                         if (mb == null)
4240                                 return "";
4241
4242                         StringBuilder sb;
4243                         if (mb is MethodInfo) {
4244                                 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4245                                 sb.Append (" ");
4246                         }
4247                         else
4248                                 sb = new StringBuilder ();
4249
4250                         sb.Append (TypeManager.CSharpSignature (mb));
4251                         return sb.ToString ();
4252                 }
4253
4254                 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
4255                 {
4256                         MemberInfo [] miset;
4257                         MethodGroupExpr union;
4258
4259                         if (mg1 == null) {
4260                                 if (mg2 == null)
4261                                         return null;
4262                                 return (MethodGroupExpr) mg2;
4263                         } else {
4264                                 if (mg2 == null)
4265                                         return (MethodGroupExpr) mg1;
4266                         }
4267                         
4268                         MethodGroupExpr left_set = null, right_set = null;
4269                         int length1 = 0, length2 = 0;
4270                         
4271                         left_set = (MethodGroupExpr) mg1;
4272                         length1 = left_set.Methods.Length;
4273                         
4274                         right_set = (MethodGroupExpr) mg2;
4275                         length2 = right_set.Methods.Length;
4276                         
4277                         ArrayList common = new ArrayList ();
4278
4279                         foreach (MethodBase r in right_set.Methods){
4280                                 if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
4281                                         common.Add (r);
4282                         }
4283
4284                         miset = new MemberInfo [length1 + length2 - common.Count];
4285                         left_set.Methods.CopyTo (miset, 0);
4286                         
4287                         int k = length1;
4288
4289                         foreach (MethodBase r in right_set.Methods) {
4290                                 if (!common.Contains (r))
4291                                         miset [k++] = r;
4292                         }
4293
4294                         union = new MethodGroupExpr (miset, loc);
4295                         
4296                         return union;
4297                 }
4298
4299                 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4300                                                              ArrayList arguments, int arg_count,
4301                                                              ref MethodBase candidate)
4302                 {
4303                         return IsParamsMethodApplicable (
4304                                 ec, me, arguments, arg_count, false, ref candidate) ||
4305                                 IsParamsMethodApplicable (
4306                                         ec, me, arguments, arg_count, true, ref candidate);
4307
4308
4309                 }
4310
4311                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4312                                                       ArrayList arguments, int arg_count,
4313                                                       bool do_varargs, ref MethodBase candidate)
4314                 {
4315 #if GMCS_SOURCE
4316                         if (!me.HasTypeArguments &&
4317                             !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4318                                 return false;
4319
4320                         if (TypeManager.IsGenericMethodDefinition (candidate))
4321                                 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4322 #endif
4323
4324                         return IsParamsMethodApplicable (
4325                                 ec, arguments, arg_count, candidate, do_varargs);
4326                 }
4327
4328                 /// <summary>
4329                 ///   Determines if the candidate method, if a params method, is applicable
4330                 ///   in its expanded form to the given set of arguments
4331                 /// </summary>
4332                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4333                                                       int arg_count, MethodBase candidate,
4334                                                       bool do_varargs)
4335                 {
4336                         ParameterData pd = TypeManager.GetParameterData (candidate);
4337
4338                         int pd_count = pd.Count;
4339                         if (pd_count == 0)
4340                                 return false;
4341
4342                         int count = pd_count - 1;
4343                         if (do_varargs) {
4344                                 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4345                                         return false;
4346                                 if (pd_count != arg_count)
4347                                         return false;
4348                         } else {
4349                                 if (!pd.HasParams)
4350                                         return false;
4351                         }
4352                         
4353                         if (count > arg_count)
4354                                 return false;
4355                         
4356                         if (pd_count == 1 && arg_count == 0)
4357                                 return true;
4358
4359                         //
4360                         // If we have come this far, the case which
4361                         // remains is when the number of parameters is
4362                         // less than or equal to the argument count.
4363                         //
4364                         for (int i = 0; i < count; ++i) {
4365
4366                                 Argument a = (Argument) arguments [i];
4367
4368                                 Parameter.Modifier a_mod = a.Modifier & 
4369                                         (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4370                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4371                                         (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4372
4373                                 if (a_mod == p_mod) {
4374
4375                                         if (a_mod == Parameter.Modifier.NONE)
4376                                                 if (!Convert.ImplicitConversionExists (ec,
4377                                                                                        a.Expr,
4378                                                                                        pd.ParameterType (i)))
4379                                 return false;
4380
4381                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4382                                                 Type pt = pd.ParameterType (i);
4383
4384                                                 if (!pt.IsByRef)
4385                                                         pt = TypeManager.GetReferenceType (pt);
4386                                                 
4387                                                 if (pt != a.Type)
4388                                                         return false;
4389                                         }
4390                                 } else
4391                                         return false;
4392                                 
4393                         }
4394
4395                         if (do_varargs) {
4396                                 Argument a = (Argument) arguments [count];
4397                                 if (!(a.Expr is Arglist))
4398                                         return false;
4399
4400                                 return true;
4401                         }
4402
4403                         Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
4404
4405                         for (int i = pd_count - 1; i < arg_count; i++) {
4406                                 Argument a = (Argument) arguments [i];
4407
4408                                 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4409                                         return false;
4410                         }
4411                         
4412                         return true;
4413                 }
4414
4415                 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4416                                                  ArrayList arguments, int arg_count,
4417                                                  ref MethodBase candidate)
4418                 {
4419 #if GMCS_SOURCE
4420                         if (!me.HasTypeArguments &&
4421                             !TypeManager.InferTypeArguments (arguments, ref candidate))
4422                                 return false;
4423
4424                         if (TypeManager.IsGenericMethodDefinition (candidate))
4425                                 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4426 #endif
4427
4428                         return IsApplicable (ec, arguments, arg_count, candidate);
4429                 }
4430
4431                 /// <summary>
4432                 ///   Determines if the candidate method is applicable (section 14.4.2.1)
4433                 ///   to the given set of arguments
4434                 /// </summary>
4435                 public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4436                         MethodBase candidate)
4437                 {
4438                         ParameterData pd = TypeManager.GetParameterData (candidate);
4439
4440                         if (arg_count != pd.Count)
4441                                 return false;
4442
4443                         for (int i = arg_count; i > 0; ) {
4444                                 i--;
4445
4446                                 Argument a = (Argument) arguments [i];
4447
4448                                 Parameter.Modifier a_mod = a.Modifier &
4449                                         ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4450
4451                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4452                                         ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
4453
4454                                 if (a_mod == p_mod) {
4455                                         Type pt = pd.ParameterType (i);
4456
4457                                         if (a_mod == Parameter.Modifier.NONE) {
4458                                                 if (!TypeManager.IsEqual (a.Type, pt) &&
4459                                                     !Convert.ImplicitConversionExists (ec, a.Expr, pt))
4460                                                         return false;
4461                                                 continue;
4462                                         }
4463                                         
4464                                         if (pt != a.Type)
4465                                                 return false;
4466                                 } else
4467                                         return false;
4468                         }
4469
4470                         return true;
4471                 }
4472
4473                 static internal bool IsAncestralType (Type first_type, Type second_type)
4474                 {
4475                         return first_type != second_type &&
4476                                 (TypeManager.IsSubclassOf (second_type, first_type) ||
4477                                  TypeManager.ImplementsInterface (second_type, first_type));
4478                 }
4479                 
4480                 /// <summary>
4481                 ///   Find the Applicable Function Members (7.4.2.1)
4482                 ///
4483                 ///   me: Method Group expression with the members to select.
4484                 ///       it might contain constructors or methods (or anything
4485                 ///       that maps to a method).
4486                 ///
4487                 ///   Arguments: ArrayList containing resolved Argument objects.
4488                 ///
4489                 ///   loc: The location if we want an error to be reported, or a Null
4490                 ///        location for "probing" purposes.
4491                 ///
4492                 ///   Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4493                 ///            that is the best match of me on Arguments.
4494                 ///
4495                 /// </summary>
4496                 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4497                                                           ArrayList Arguments, bool may_fail,
4498                                                           Location loc)
4499                 {
4500                         MethodBase method = null;
4501                         bool method_params = false;
4502                         Type applicable_type = null;
4503                         int arg_count = 0;
4504                         ArrayList candidates = new ArrayList (2);
4505                         ArrayList candidate_overrides = null;
4506
4507                         //
4508                         // Used to keep a map between the candidate
4509                         // and whether it is being considered in its
4510                         // normal or expanded form
4511                         //
4512                         // false is normal form, true is expanded form
4513                         //
4514                         Hashtable candidate_to_form = null;
4515
4516                         if (Arguments != null)
4517                                 arg_count = Arguments.Count;
4518
4519                         if ((me.Name == "Invoke") &&
4520                                 TypeManager.IsDelegateType (me.DeclaringType)) {
4521                                 Error_InvokeOnDelegate (loc);
4522                                 return null;
4523                         }
4524
4525                         MethodBase[] methods = me.Methods;
4526
4527                         int nmethods = methods.Length;
4528
4529                         if (!me.IsBase) {
4530                                 //
4531                                 // Methods marked 'override' don't take part in 'applicable_type'
4532                                 // computation, nor in the actual overload resolution.
4533                                 // However, they still need to be emitted instead of a base virtual method.
4534                                 // So, we salt them away into the 'candidate_overrides' array.
4535                                 //
4536                                 // In case of reflected methods, we replace each overriding method with
4537                                 // its corresponding base virtual method.  This is to improve compatibility
4538                                 // with non-C# libraries which change the visibility of overrides (#75636)
4539                                 //
4540                                 int j = 0;
4541                                 for (int i = 0; i < methods.Length; ++i) {
4542                                         MethodBase m = methods [i];
4543 #if GMCS_SOURCE
4544                                         Type [] gen_args = null;
4545                                         if (m.IsGenericMethod && !m.IsGenericMethodDefinition)
4546                                                 gen_args = m.GetGenericArguments ();
4547 #endif
4548                                         if (TypeManager.IsOverride (m)) {
4549                                                 if (candidate_overrides == null)
4550                                                         candidate_overrides = new ArrayList ();
4551                                                 candidate_overrides.Add (m);
4552                                                 m = TypeManager.TryGetBaseDefinition (m);
4553 #if GMCS_SOURCE
4554                                                 if (m != null && gen_args != null) {
4555                                                         if (!m.IsGenericMethodDefinition)
4556                                                                 throw new InternalErrorException ("GetBaseDefinition didn't return a GenericMethodDefinition");
4557                                                         m = ((MethodInfo) m).MakeGenericMethod (gen_args);
4558                                                 }
4559 #endif
4560                                         }
4561                                         if (m != null)
4562                                                 methods [j++] = m;
4563                                 }
4564                                 nmethods = j;
4565                         }
4566
4567                         int applicable_errors = Report.Errors;
4568                         
4569                         //
4570                         // First we construct the set of applicable methods
4571                         //
4572                         bool is_sorted = true;
4573                         for (int i = 0; i < nmethods; i++){
4574                                 Type decl_type = methods [i].DeclaringType;
4575
4576                                 //
4577                                 // If we have already found an applicable method
4578                                 // we eliminate all base types (Section 14.5.5.1)
4579                                 //
4580                                 if (applicable_type != null && IsAncestralType (decl_type, applicable_type))
4581                                         continue;
4582
4583                                 //
4584                                 // Check if candidate is applicable (section 14.4.2.1)
4585                                 //   Is candidate applicable in normal form?
4586                                 //
4587                                 bool is_applicable = IsApplicable (ec, me, Arguments, arg_count, ref methods [i]);
4588
4589                                 if (!is_applicable && IsParamsMethodApplicable (ec, me, Arguments, arg_count, ref methods [i])) {
4590                                         MethodBase candidate = methods [i];
4591                                         if (candidate_to_form == null)
4592                                                 candidate_to_form = new PtrHashtable ();
4593                                         candidate_to_form [candidate] = candidate;
4594                                         // Candidate is applicable in expanded form
4595                                         is_applicable = true;
4596                                 }
4597
4598                                 if (!is_applicable)
4599                                         continue;
4600
4601                                 candidates.Add (methods [i]);
4602
4603                                 if (applicable_type == null)
4604                                         applicable_type = decl_type;
4605                                 else if (applicable_type != decl_type) {
4606                                         is_sorted = false;
4607                                         if (IsAncestralType (applicable_type, decl_type))
4608                                                 applicable_type = decl_type;
4609                                 }
4610                         }
4611
4612                         if (applicable_errors != Report.Errors)
4613                                 return null;
4614                         
4615                         int candidate_top = candidates.Count;
4616
4617                         if (applicable_type == null) {
4618                                 //
4619                                 // Okay so we have failed to find anything so we
4620                                 // return by providing info about the closest match
4621                                 //
4622                                 int errors = Report.Errors;
4623                                 for (int i = 0; i < nmethods; ++i) {
4624                                         MethodBase c = (MethodBase) methods [i];
4625                                         ParameterData pd = TypeManager.GetParameterData (c);
4626
4627                                         if (pd.Count != arg_count)
4628                                                 continue;
4629
4630 #if GMCS_SOURCE
4631                                         if (!TypeManager.InferTypeArguments (Arguments, ref c))
4632                                                 continue;
4633                                         if (TypeManager.IsGenericMethodDefinition (c))
4634                                                 continue;
4635 #endif
4636
4637                                         VerifyArgumentsCompat (ec, Arguments, arg_count,
4638                                                 c, false, null, may_fail, loc);
4639
4640                                         if (!may_fail && errors == Report.Errors)
4641                                                 throw new InternalErrorException (
4642                                                         "VerifyArgumentsCompat and IsApplicable do not agree; " +
4643                                                         "likely reason: ImplicitConversion and ImplicitConversionExists have gone out of sync");
4644
4645                                         break;
4646                                 }
4647
4648                                 if (!may_fail && errors == Report.Errors) {
4649                                         string report_name = me.Name;
4650                                         if (report_name == ".ctor")
4651                                                 report_name = TypeManager.CSharpName (me.DeclaringType);
4652                                         
4653 #if GMCS_SOURCE
4654                                         //
4655                                         // Type inference
4656                                         //
4657                                         for (int i = 0; i < methods.Length; ++i) {
4658                                                 MethodBase c = methods [i];
4659                                                 ParameterData pd = TypeManager.GetParameterData (c);
4660
4661                                                 if (pd.Count != arg_count)
4662                                                         continue;
4663
4664                                                 if (TypeManager.InferTypeArguments (Arguments, ref c))
4665                                                         continue;
4666
4667                                                 Report.Error (
4668                                                         411, loc, "The type arguments for " +
4669                                                         "method `{0}' cannot be infered from " +
4670                                                         "the usage. Try specifying the type " +
4671                                                         "arguments explicitly.", report_name);
4672                                                 return null;
4673                                         }
4674 #endif
4675
4676                                         Error_WrongNumArguments (loc, report_name, arg_count);
4677                                 }
4678                                 
4679                                 return null;
4680                         }
4681
4682                         if (!is_sorted) {
4683                                 //
4684                                 // At this point, applicable_type is _one_ of the most derived types
4685                                 // in the set of types containing the methods in this MethodGroup.
4686                                 // Filter the candidates so that they only contain methods from the
4687                                 // most derived types.
4688                                 //
4689
4690                                 int finalized = 0; // Number of finalized candidates
4691
4692                                 do {
4693                                         // Invariant: applicable_type is a most derived type
4694                                         
4695                                         // We'll try to complete Section 14.5.5.1 for 'applicable_type' by 
4696                                         // eliminating all it's base types.  At the same time, we'll also move
4697                                         // every unrelated type to the end of the array, and pick the next
4698                                         // 'applicable_type'.
4699
4700                                         Type next_applicable_type = null;
4701                                         int j = finalized; // where to put the next finalized candidate
4702                                         int k = finalized; // where to put the next undiscarded candidate
4703                                         for (int i = finalized; i < candidate_top; ++i) {
4704                                                 MethodBase candidate = (MethodBase) candidates [i];
4705                                                 Type decl_type = candidate.DeclaringType;
4706
4707                                                 if (decl_type == applicable_type) {
4708                                                         candidates [k++] = candidates [j];
4709                                                         candidates [j++] = candidates [i];
4710                                                         continue;
4711                                                 }
4712
4713                                                 if (IsAncestralType (decl_type, applicable_type))
4714                                                         continue;
4715
4716                                                 if (next_applicable_type != null &&
4717                                                     IsAncestralType (decl_type, next_applicable_type))
4718                                                         continue;
4719
4720                                                 candidates [k++] = candidates [i];
4721
4722                                                 if (next_applicable_type == null ||
4723                                                     IsAncestralType (next_applicable_type, decl_type))
4724                                                         next_applicable_type = decl_type;
4725                                         }
4726
4727                                         applicable_type = next_applicable_type;
4728                                         finalized = j;
4729                                         candidate_top = k;
4730                                 } while (applicable_type != null);
4731                         }
4732
4733                         //
4734                         // Now we actually find the best method
4735                         //
4736
4737                         method = (MethodBase) candidates [0];
4738                         method_params = candidate_to_form != null && candidate_to_form.Contains (method);
4739                         for (int ix = 1; ix < candidate_top; ix++){
4740                                 MethodBase candidate = (MethodBase) candidates [ix];
4741
4742                                 if (candidate == method)
4743                                         continue;
4744
4745                                 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4746
4747                                 if (BetterFunction (ec, Arguments, arg_count, 
4748                                                     candidate, cand_params,
4749                                                     method, method_params)) {
4750                                         method = candidate;
4751                                         method_params = cand_params;
4752                                 }
4753                         }
4754                         //
4755                         // Now check that there are no ambiguities i.e the selected method
4756                         // should be better than all the others
4757                         //
4758                         MethodBase ambiguous = null;
4759                         for (int ix = 0; ix < candidate_top; ix++){
4760                                 MethodBase candidate = (MethodBase) candidates [ix];
4761
4762                                 if (candidate == method)
4763                                         continue;
4764
4765                                 bool cand_params = candidate_to_form != null && candidate_to_form.Contains (candidate);
4766                                 if (!BetterFunction (ec, Arguments, arg_count,
4767                                                      method, method_params,
4768                                                      candidate, cand_params)) {
4769                                         Report.SymbolRelatedToPreviousError (candidate);
4770                                         ambiguous = candidate;
4771                                 }
4772                         }
4773
4774                         if (ambiguous != null) {
4775                                 Report.SymbolRelatedToPreviousError (method);
4776                                 Report.Error (121, loc, "The call is ambiguous between the following methods or properties: `{0}' and `{1}'",
4777                                         TypeManager.CSharpSignature (ambiguous), TypeManager.CSharpSignature (method));
4778                                 return null;
4779                         }
4780
4781                         //
4782                         // If the method is a virtual function, pick an override closer to the LHS type.
4783                         //
4784                         if (!me.IsBase && method.IsVirtual) {
4785                                 if (TypeManager.IsOverride (method))
4786                                         throw new InternalErrorException (
4787                                                 "Should not happen.  An 'override' method took part in overload resolution: " + method);
4788
4789                                 if (candidate_overrides != null)
4790                                         foreach (MethodBase candidate in candidate_overrides) {
4791                                                 if (IsOverride (candidate, method))
4792                                                         method = candidate;
4793                                         }
4794                         }
4795
4796                         //
4797                         // And now check if the arguments are all
4798                         // compatible, perform conversions if
4799                         // necessary etc. and return if everything is
4800                         // all right
4801                         //
4802                         if (!VerifyArgumentsCompat (ec, Arguments, arg_count, method,
4803                                                     method_params, null, may_fail, loc))
4804                                 return null;
4805
4806                         if (method == null)
4807                                 return null;
4808
4809                         MethodBase the_method = TypeManager.DropGenericMethodArguments (method);
4810 #if GMCS_SOURCE
4811                         if (the_method.IsGenericMethodDefinition &&
4812                             !ConstraintChecker.CheckConstraints (ec, the_method, method, loc))
4813                                 return null;
4814 #endif
4815
4816                         IMethodData data = TypeManager.GetMethod (the_method);
4817                         if (data != null)
4818                                 data.SetMemberIsUsed ();
4819
4820                         return method;
4821                 }
4822
4823                 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4824                 {
4825                         Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4826                                 name, arg_count.ToString ());
4827                 }
4828
4829                 static void Error_InvokeOnDelegate (Location loc)
4830                 {
4831                         Report.Error (1533, loc,
4832                                       "Invoke cannot be called directly on a delegate");
4833                 }
4834                         
4835                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4836                                                     Type delegate_type, Argument a, ParameterData expected_par)
4837                 {
4838                         if (delegate_type == null) 
4839                                 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4840                                               TypeManager.CSharpSignature (method));
4841                         else
4842                                 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4843                                         TypeManager.CSharpName (delegate_type));
4844
4845                         Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4846
4847                         string index = (idx + 1).ToString ();
4848                         if (mod != Parameter.Modifier.ARGLIST && mod != a.Modifier) {
4849                                 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4850                                         Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4851                                                 index, Parameter.GetModifierSignature (a.Modifier));
4852                                 else
4853                                         Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4854                                                 index, Parameter.GetModifierSignature (mod));
4855                         } else {
4856                                 Report.Error (1503, loc, "Argument {0}: Cannot convert from `{1}' to `{2}'",
4857                                         index, Argument.FullDesc (a), expected_par.ParameterDesc (idx));
4858                         }
4859                 }
4860                 
4861                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4862                                                           int arg_count, MethodBase method, 
4863                                                           bool chose_params_expanded,
4864                                                           Type delegate_type, bool may_fail,
4865                                                           Location loc)
4866                 {
4867                         ParameterData pd = TypeManager.GetParameterData (method);
4868                         int j;
4869                         for (j = 0; j < arg_count; j++) {
4870                                 Argument a = (Argument) Arguments [j];
4871                                 Expression a_expr = a.Expr;
4872                                 Type parameter_type = pd.ParameterType (j);
4873                                 Parameter.Modifier pm = pd.ParameterModifier (j);
4874                                 Parameter.Modifier am = a.Modifier;
4875
4876                                 if (pm == Parameter.Modifier.ARGLIST) {
4877                                         if (!(a.Expr is Arglist))
4878                                                 break;
4879                                         continue;
4880                                 }
4881
4882                                 if (pm == Parameter.Modifier.PARAMS) {
4883                                         pm = Parameter.Modifier.NONE;
4884                                         if (chose_params_expanded)
4885                                                 parameter_type = TypeManager.GetElementType (parameter_type);
4886                                 }
4887
4888                                 if (pm != am)
4889                                         break;
4890
4891                                 if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4892                                         if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4893                                                 break;
4894
4895                                         Expression conv = Convert.ImplicitConversion (ec, a_expr, parameter_type, loc);
4896                                         if (conv == null)
4897                                                 break;
4898
4899                                         // Update the argument with the implicit conversion
4900                                         if (a_expr != conv)
4901                                                 a.Expr = conv;
4902                                 }
4903
4904                                 if (parameter_type.IsPointer && !ec.InUnsafe) {
4905                                         UnsafeError (loc);
4906                                         return false;
4907                                 }
4908                         }
4909
4910                         if (j == arg_count)
4911                                 return true;
4912
4913                         if (!may_fail)
4914                                 Error_InvalidArguments (loc, j, method, delegate_type, (Argument) Arguments [j], pd);
4915                         return false;
4916                 }
4917
4918                 private bool resolved = false;
4919                 public override Expression DoResolve (EmitContext ec)
4920                 {
4921                         if (resolved)
4922                                 return this.method == null ? null : this;
4923
4924                         resolved = true;
4925                         //
4926                         // First, resolve the expression that is used to
4927                         // trigger the invocation
4928                         //
4929                         SimpleName sn = expr as SimpleName;
4930                         if (sn != null)
4931                                 expr = sn.GetMethodGroup ();
4932
4933                         expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4934                         if (expr == null)
4935                                 return null;
4936
4937                         if (!(expr is MethodGroupExpr)) {
4938                                 Type expr_type = expr.Type;
4939
4940                                 if (expr_type != null){
4941                                         bool IsDelegate = TypeManager.IsDelegateType (expr_type);
4942                                         if (IsDelegate)
4943                                                 return (new DelegateInvocation (
4944                                                         this.expr, Arguments, loc)).Resolve (ec);
4945                                 }
4946                         }
4947
4948                         if (!(expr is MethodGroupExpr)){
4949                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4950                                 return null;
4951                         }
4952
4953                         //
4954                         // Next, evaluate all the expressions in the argument list
4955                         //
4956                         if (Arguments != null){
4957                                 foreach (Argument a in Arguments){
4958                                         if (!a.Resolve (ec, loc))
4959                                                 return null;
4960                                 }
4961                         }
4962
4963                         MethodGroupExpr mg = (MethodGroupExpr) expr;
4964                         MethodBase method = OverloadResolve (ec, mg, Arguments, false, loc);
4965
4966                         if (method == null)
4967                                 return null;
4968
4969                         MethodInfo mi = method as MethodInfo;
4970                         if (mi != null) {
4971                                 type = TypeManager.TypeToCoreType (mi.ReturnType);
4972                                 Expression iexpr = mg.InstanceExpression;
4973                                 if (mi.IsStatic) {
4974                                         if (iexpr == null || 
4975                                             iexpr is This || iexpr is EmptyExpression ||
4976                                             mg.IdenticalTypeName) {
4977                                                 mg.InstanceExpression = null;
4978                                         } else {
4979                                                 MemberExpr.error176 (loc, TypeManager.CSharpSignature (mi));
4980                                                 return null;
4981                                         }
4982                                 } else {
4983                                         if (iexpr == null || iexpr is EmptyExpression) {
4984                                                 SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (mi));
4985                                                 return null;
4986                                         }
4987                                 }
4988                         }
4989
4990                         if (type.IsPointer){
4991                                 if (!ec.InUnsafe){
4992                                         UnsafeError (loc);
4993                                         return null;
4994                                 }
4995                         }
4996                         
4997                         //
4998                         // Only base will allow this invocation to happen.
4999                         //
5000                         if (mg.IsBase && method.IsAbstract){
5001                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
5002                                 return null;
5003                         }
5004
5005                         if (Arguments == null && method.Name == "Finalize") {
5006                                 if (mg.IsBase)
5007                                         Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
5008                                 else
5009                                         Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
5010                                 return null;
5011                         }
5012
5013                         if ((method.Attributes & MethodAttributes.SpecialName) != 0 && IsSpecialMethodInvocation (method)) {
5014                                 return null;
5015                         }
5016                         
5017                         if (mg.InstanceExpression != null)
5018                                 mg.InstanceExpression.CheckMarshalByRefAccess ();
5019
5020                         eclass = ExprClass.Value;
5021                         this.method = method;
5022                         return this;
5023                 }
5024
5025                 bool IsSpecialMethodInvocation (MethodBase method)
5026                 {
5027                         IMethodData md = TypeManager.GetMethod (method);
5028                         if (md != null) {
5029                                 if (!(md is AbstractPropertyEventMethod) && !(md is Operator))
5030                                         return false;
5031                         } else {
5032                                 if (!TypeManager.IsSpecialMethod (method))
5033                                         return false;
5034
5035                                 int args = TypeManager.GetParameterData (method).Count;
5036                                 if (method.Name.StartsWith ("get_") && args > 0)
5037                                         return false;
5038                                 else if (method.Name.StartsWith ("set_") && args > 2)
5039                                         return false;
5040
5041                                 // TODO: check operators and events as well ?
5042                         }
5043
5044                         Report.SymbolRelatedToPreviousError (method);
5045                         Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
5046                                 TypeManager.CSharpSignature (method, true));
5047         
5048                         return true;
5049                 }
5050
5051                 // <summary>
5052                 //   Emits the list of arguments as an array
5053                 // </summary>
5054                 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
5055                 {
5056                         ILGenerator ig = ec.ig;
5057                         int count = arguments.Count - idx;
5058                         Argument a = (Argument) arguments [idx];
5059                         Type t = a.Expr.Type;
5060
5061                         IntConstant.EmitInt (ig, count);
5062                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
5063
5064                         int top = arguments.Count;
5065                         for (int j = idx; j < top; j++){
5066                                 a = (Argument) arguments [j];
5067                                 
5068                                 ig.Emit (OpCodes.Dup);
5069                                 IntConstant.EmitInt (ig, j - idx);
5070
5071                                 bool is_stobj, has_type_arg;
5072                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
5073                                 if (is_stobj)
5074                                         ig.Emit (OpCodes.Ldelema, t);
5075
5076                                 a.Emit (ec);
5077
5078                                 if (has_type_arg)
5079                                         ig.Emit (op, t);
5080                                 else
5081                                         ig.Emit (op);
5082                         }
5083                 }
5084                 
5085                 /// <summary>
5086                 ///   Emits a list of resolved Arguments that are in the arguments
5087                 ///   ArrayList.
5088                 /// 
5089                 ///   The MethodBase argument might be null if the
5090                 ///   emission of the arguments is known not to contain
5091                 ///   a `params' field (for example in constructors or other routines
5092                 ///   that keep their arguments in this structure)
5093                 ///   
5094                 ///   if `dup_args' is true, a copy of the arguments will be left
5095                 ///   on the stack. If `dup_args' is true, you can specify `this_arg'
5096                 ///   which will be duplicated before any other args. Only EmitCall
5097                 ///   should be using this interface.
5098                 /// </summary>
5099                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
5100                 {
5101                         ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
5102                         int top = arguments == null ? 0 : arguments.Count;
5103                         LocalTemporary [] temps = null;
5104                         
5105                         if (dup_args && top != 0)
5106                                 temps = new LocalTemporary [top];
5107
5108                         for (int i = 0; i < top; i++){
5109                                 Argument a = (Argument) arguments [i];
5110
5111                                 if (pd != null){
5112                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
5113                                                 //
5114                                                 // Special case if we are passing the same data as the
5115                                                 // params argument, do not put it in an array.
5116                                                 //
5117                                                 if (pd.ParameterType (i) == a.Type)
5118                                                         a.Emit (ec);
5119                                                 else
5120                                                         EmitParams (ec, i, arguments);
5121                                                 return;
5122                                         }
5123                                 }
5124                                             
5125                                 a.Emit (ec);
5126                                 if (dup_args) {
5127                                         ec.ig.Emit (OpCodes.Dup);
5128                                         (temps [i] = new LocalTemporary (a.Type)).Store (ec);
5129                                 }
5130                         }
5131                         
5132                         if (dup_args) {
5133                                 if (this_arg != null)
5134                                         this_arg.Emit (ec);
5135                                 
5136                                 for (int i = 0; i < top; i ++) {
5137                                         temps [i].Emit (ec);
5138                                         temps [i].Release (ec);
5139                                 }
5140                         }
5141
5142                         if (pd != null && pd.Count > top &&
5143                             pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
5144                                 ILGenerator ig = ec.ig;
5145
5146                                 IntConstant.EmitInt (ig, 0);
5147                                 ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (top)));
5148                         }
5149                 }
5150
5151                 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
5152                 {
5153                         ParameterData pd = TypeManager.GetParameterData (mb);
5154
5155                         if (arguments == null)
5156                                 return new Type [0];
5157
5158                         Argument a = (Argument) arguments [pd.Count - 1];
5159                         Arglist list = (Arglist) a.Expr;
5160
5161                         return list.ArgumentTypes;
5162                 }
5163
5164                 /// <summary>
5165                 /// This checks the ConditionalAttribute on the method 
5166                 /// </summary>
5167                 static bool IsMethodExcluded (MethodBase method)
5168                 {
5169                         if (method.IsConstructor)
5170                                 return false;
5171
5172                         IMethodData md = TypeManager.GetMethod (method);
5173                         if (md != null)
5174                                 return md.IsExcluded ();
5175
5176                         // For some methods (generated by delegate class) GetMethod returns null
5177                         // because they are not included in builder_to_method table
5178                         if (method.DeclaringType is TypeBuilder)
5179                                 return false;
5180
5181                         return AttributeTester.IsConditionalMethodExcluded (method);
5182                 }
5183
5184                 /// <remarks>
5185                 ///   is_base tells whether we want to force the use of the `call'
5186                 ///   opcode instead of using callvirt.  Call is required to call
5187                 ///   a specific method, while callvirt will always use the most
5188                 ///   recent method in the vtable.
5189                 ///
5190                 ///   is_static tells whether this is an invocation on a static method
5191                 ///
5192                 ///   instance_expr is an expression that represents the instance
5193                 ///   it must be non-null if is_static is false.
5194                 ///
5195                 ///   method is the method to invoke.
5196                 ///
5197                 ///   Arguments is the list of arguments to pass to the method or constructor.
5198                 /// </remarks>
5199                 public static void EmitCall (EmitContext ec, bool is_base,
5200                                              bool is_static, Expression instance_expr,
5201                                              MethodBase method, ArrayList Arguments, Location loc)
5202                 {
5203                         EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false);
5204                 }
5205                 
5206                 // `dup_args' leaves an extra copy of the arguments on the stack
5207                 // `omit_args' does not leave any arguments at all.
5208                 // So, basically, you could make one call with `dup_args' set to true,
5209                 // and then another with `omit_args' set to true, and the two calls
5210                 // would have the same set of arguments. However, each argument would
5211                 // only have been evaluated once.
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                                              bool dup_args, bool omit_args)
5216                 {
5217                         ILGenerator ig = ec.ig;
5218                         bool struct_call = false;
5219                         bool this_call = false;
5220                         LocalTemporary this_arg = null;
5221
5222                         Type decl_type = method.DeclaringType;
5223
5224                         if (!RootContext.StdLib) {
5225                                 // Replace any calls to the system's System.Array type with calls to
5226                                 // the newly created one.
5227                                 if (method == TypeManager.system_int_array_get_length)
5228                                         method = TypeManager.int_array_get_length;
5229                                 else if (method == TypeManager.system_int_array_get_rank)
5230                                         method = TypeManager.int_array_get_rank;
5231                                 else if (method == TypeManager.system_object_array_clone)
5232                                         method = TypeManager.object_array_clone;
5233                                 else if (method == TypeManager.system_int_array_get_length_int)
5234                                         method = TypeManager.int_array_get_length_int;
5235                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
5236                                         method = TypeManager.int_array_get_lower_bound_int;
5237                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
5238                                         method = TypeManager.int_array_get_upper_bound_int;
5239                                 else if (method == TypeManager.system_void_array_copyto_array_int)
5240                                         method = TypeManager.void_array_copyto_array_int;
5241                         }
5242
5243                         if (!ec.IsInObsoleteScope) {
5244                                 //
5245                                 // This checks ObsoleteAttribute on the method and on the declaring type
5246                                 //
5247                                 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
5248                                 if (oa != null)
5249                                         AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
5250
5251                                 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
5252                                 if (oa != null) {
5253                                         AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
5254                                 }
5255                         }
5256
5257                         if (IsMethodExcluded (method))
5258                                 return;
5259                         
5260                         if (!is_static){
5261                                 if (instance_expr == EmptyExpression.Null) {
5262                                         SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
5263                                         return;
5264                                 }
5265
5266                                 this_call = instance_expr is This;
5267                                 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
5268                                         struct_call = true;
5269
5270                                 //
5271                                 // If this is ourselves, push "this"
5272                                 //
5273                                 if (!omit_args) {
5274                                         Type t = null;
5275                                         Type iexpr_type = instance_expr.Type;
5276
5277                                         //
5278                                         // Push the instance expression
5279                                         //
5280                                         if (TypeManager.IsValueType (iexpr_type)) {
5281                                                 //
5282                                                 // Special case: calls to a function declared in a 
5283                                                 // reference-type with a value-type argument need
5284                                                 // to have their value boxed.
5285                                                 if (decl_type.IsValueType ||
5286                                                     TypeManager.IsGenericParameter (iexpr_type)) {
5287                                                         //
5288                                                         // If the expression implements IMemoryLocation, then
5289                                                         // we can optimize and use AddressOf on the
5290                                                         // return.
5291                                                         //
5292                                                         // If not we have to use some temporary storage for
5293                                                         // it.
5294                                                         if (instance_expr is IMemoryLocation) {
5295                                                                 ((IMemoryLocation)instance_expr).
5296                                                                         AddressOf (ec, AddressOp.LoadStore);
5297                                                         } else {
5298                                                                 LocalTemporary temp = new LocalTemporary (iexpr_type);
5299                                                                 instance_expr.Emit (ec);
5300                                                                 temp.Store (ec);
5301                                                                 temp.AddressOf (ec, AddressOp.Load);
5302                                                         }
5303
5304                                                         // avoid the overhead of doing this all the time.
5305                                                         if (dup_args)
5306                                                                 t = TypeManager.GetReferenceType (iexpr_type);
5307                                                 } else {
5308                                                         instance_expr.Emit (ec);
5309                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
5310                                                         t = TypeManager.object_type;
5311                                                 }
5312                                         } else {
5313                                                 instance_expr.Emit (ec);
5314                                                 t = instance_expr.Type;
5315                                         }
5316
5317                                         if (dup_args) {
5318                                                 ig.Emit (OpCodes.Dup);
5319                                                 if (Arguments != null && Arguments.Count != 0) {
5320                                                         this_arg = new LocalTemporary (t);
5321                                                         this_arg.Store (ec);
5322                                                 }
5323                                         }
5324                                 }
5325                         }
5326
5327                         if (!omit_args)
5328                                 EmitArguments (ec, method, Arguments, dup_args, this_arg);
5329
5330 #if GMCS_SOURCE
5331                         if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
5332                                 ig.Emit (OpCodes.Constrained, instance_expr.Type);
5333 #endif
5334
5335                         OpCode call_op;
5336                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
5337                                 call_op = OpCodes.Call;
5338                         else
5339                                 call_op = OpCodes.Callvirt;
5340
5341                         if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
5342                                 Type[] varargs_types = GetVarargsTypes (method, Arguments);
5343                                 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
5344                                 return;
5345                         }
5346
5347                         //
5348                         // If you have:
5349                         // this.DoFoo ();
5350                         // and DoFoo is not virtual, you can omit the callvirt,
5351                         // because you don't need the null checking behavior.
5352                         //
5353                         if (method is MethodInfo)
5354                                 ig.Emit (call_op, (MethodInfo) method);
5355                         else
5356                                 ig.Emit (call_op, (ConstructorInfo) method);
5357                 }
5358                 
5359                 public override void Emit (EmitContext ec)
5360                 {
5361                         MethodGroupExpr mg = (MethodGroupExpr) this.expr;
5362
5363                         EmitCall (ec, mg.IsBase, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
5364                 }
5365                 
5366                 public override void EmitStatement (EmitContext ec)
5367                 {
5368                         Emit (ec);
5369
5370                         // 
5371                         // Pop the return value if there is one
5372                         //
5373                         if (method is MethodInfo){
5374                                 Type ret = ((MethodInfo)method).ReturnType;
5375                                 if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
5376                                         ec.ig.Emit (OpCodes.Pop);
5377                         }
5378                 }
5379         }
5380
5381         public class InvocationOrCast : ExpressionStatement
5382         {
5383                 Expression expr;
5384                 Expression argument;
5385
5386                 public InvocationOrCast (Expression expr, Expression argument)
5387                 {
5388                         this.expr = expr;
5389                         this.argument = argument;
5390                         this.loc = expr.Location;
5391                 }
5392
5393                 public override Expression DoResolve (EmitContext ec)
5394                 {
5395                         //
5396                         // First try to resolve it as a cast.
5397                         //
5398                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5399                         if ((te != null) && (te.eclass == ExprClass.Type)) {
5400                                 Cast cast = new Cast (te, argument, loc);
5401                                 return cast.Resolve (ec);
5402                         }
5403
5404                         //
5405                         // This can either be a type or a delegate invocation.
5406                         // Let's just resolve it and see what we'll get.
5407                         //
5408                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5409                         if (expr == null)
5410                                 return null;
5411
5412                         //
5413                         // Ok, so it's a Cast.
5414                         //
5415                         if (expr.eclass == ExprClass.Type) {
5416                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
5417                                 return cast.Resolve (ec);
5418                         }
5419
5420                         //
5421                         // It's a delegate invocation.
5422                         //
5423                         if (!TypeManager.IsDelegateType (expr.Type)) {
5424                                 Error (149, "Method name expected");
5425                                 return null;
5426                         }
5427
5428                         ArrayList args = new ArrayList ();
5429                         args.Add (new Argument (argument, Argument.AType.Expression));
5430                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5431                         return invocation.Resolve (ec);
5432                 }
5433
5434                 void error201 ()
5435                 {
5436                         Error (201, "Only assignment, call, increment, decrement and new object " +
5437                                "expressions can be used as a statement");
5438                 }
5439
5440                 public override ExpressionStatement ResolveStatement (EmitContext ec)
5441                 {
5442                         //
5443                         // First try to resolve it as a cast.
5444                         //
5445                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
5446                         if ((te != null) && (te.eclass == ExprClass.Type)) {
5447                                 error201 ();
5448                                 return null;
5449                         }
5450
5451                         //
5452                         // This can either be a type or a delegate invocation.
5453                         // Let's just resolve it and see what we'll get.
5454                         //
5455                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
5456                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
5457                                 error201 ();
5458                                 return null;
5459                         }
5460
5461                         //
5462                         // It's a delegate invocation.
5463                         //
5464                         if (!TypeManager.IsDelegateType (expr.Type)) {
5465                                 Error (149, "Method name expected");
5466                                 return null;
5467                         }
5468
5469                         ArrayList args = new ArrayList ();
5470                         args.Add (new Argument (argument, Argument.AType.Expression));
5471                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
5472                         return invocation.ResolveStatement (ec);
5473                 }
5474
5475                 public override void Emit (EmitContext ec)
5476                 {
5477                         throw new Exception ("Cannot happen");
5478                 }
5479
5480                 public override void EmitStatement (EmitContext ec)
5481                 {
5482                         throw new Exception ("Cannot happen");
5483                 }
5484         }
5485
5486         //
5487         // This class is used to "disable" the code generation for the
5488         // temporary variable when initializing value types.
5489         //
5490         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
5491                 public void AddressOf (EmitContext ec, AddressOp Mode)
5492                 {
5493                         // nothing
5494                 }
5495         }
5496         
5497         /// <summary>
5498         ///    Implements the new expression 
5499         /// </summary>
5500         public class New : ExpressionStatement, IMemoryLocation {
5501                 public readonly ArrayList Arguments;
5502
5503                 //
5504                 // During bootstrap, it contains the RequestedType,
5505                 // but if `type' is not null, it *might* contain a NewDelegate
5506                 // (because of field multi-initialization)
5507                 //
5508                 public Expression RequestedType;
5509
5510                 MethodBase method = null;
5511
5512                 //
5513                 // If set, the new expression is for a value_target, and
5514                 // we will not leave anything on the stack.
5515                 //
5516                 Expression value_target;
5517                 bool value_target_set = false;
5518                 bool is_type_parameter = false;
5519                 
5520                 public New (Expression requested_type, ArrayList arguments, Location l)
5521                 {
5522                         RequestedType = requested_type;
5523                         Arguments = arguments;
5524                         loc = l;
5525                 }
5526
5527                 public bool SetValueTypeVariable (Expression value)
5528                 {
5529                         value_target = value;
5530                         value_target_set = true;
5531                         if (!(value_target is IMemoryLocation)){
5532                                 Error_UnexpectedKind (null, "variable", loc);
5533                                 return false;
5534                         }
5535                         return true;
5536                 }
5537
5538                 //
5539                 // This function is used to disable the following code sequence for
5540                 // value type initialization:
5541                 //
5542                 // AddressOf (temporary)
5543                 // Construct/Init
5544                 // LoadTemporary
5545                 //
5546                 // Instead the provide will have provided us with the address on the
5547                 // stack to store the results.
5548                 //
5549                 static Expression MyEmptyExpression;
5550                 
5551                 public void DisableTemporaryValueType ()
5552                 {
5553                         if (MyEmptyExpression == null)
5554                                 MyEmptyExpression = new EmptyAddressOf ();
5555
5556                         //
5557                         // To enable this, look into:
5558                         // test-34 and test-89 and self bootstrapping.
5559                         //
5560                         // For instance, we can avoid a copy by using `newobj'
5561                         // instead of Call + Push-temp on value types.
5562 //                      value_target = MyEmptyExpression;
5563                 }
5564
5565
5566                 /// <summary>
5567                 /// Converts complex core type syntax like 'new int ()' to simple constant
5568                 /// </summary>
5569                 public static Constant Constantify (Type t)
5570                 {
5571                         if (t == TypeManager.int32_type)
5572                                 return new IntConstant (0, Location.Null);
5573                         if (t == TypeManager.uint32_type)
5574                                 return new UIntConstant (0, Location.Null);
5575                         if (t == TypeManager.int64_type)
5576                                 return new LongConstant (0, Location.Null);
5577                         if (t == TypeManager.uint64_type)
5578                                 return new ULongConstant (0, Location.Null);
5579                         if (t == TypeManager.float_type)
5580                                 return new FloatConstant (0, Location.Null);
5581                         if (t == TypeManager.double_type)
5582                                 return new DoubleConstant (0, Location.Null);
5583                         if (t == TypeManager.short_type)
5584                                 return new ShortConstant (0, Location.Null);
5585                         if (t == TypeManager.ushort_type)
5586                                 return new UShortConstant (0, Location.Null);
5587                         if (t == TypeManager.sbyte_type)
5588                                 return new SByteConstant (0, Location.Null);
5589                         if (t == TypeManager.byte_type)
5590                                 return new ByteConstant (0, Location.Null);
5591                         if (t == TypeManager.char_type)
5592                                 return new CharConstant ('\0', Location.Null);
5593                         if (t == TypeManager.bool_type)
5594                                 return new BoolConstant (false, Location.Null);
5595                         if (t == TypeManager.decimal_type)
5596                                 return new DecimalConstant (0, Location.Null);
5597                         if (TypeManager.IsEnumType (t))
5598                                 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5599
5600                         return null;
5601                 }
5602
5603                 //
5604                 // Checks whether the type is an interface that has the
5605                 // [ComImport, CoClass] attributes and must be treated
5606                 // specially
5607                 //
5608                 public Expression CheckComImport (EmitContext ec)
5609                 {
5610                         if (!type.IsInterface)
5611                                 return null;
5612
5613                         //
5614                         // Turn the call into:
5615                         // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5616                         //
5617                         Type real_class = AttributeTester.GetCoClassAttribute (type);
5618                         if (real_class == null)
5619                                 return null;
5620
5621                         New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5622                         Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5623                         return cast.Resolve (ec);
5624                 }
5625                 
5626                 public override Expression DoResolve (EmitContext ec)
5627                 {
5628                         //
5629                         // The New DoResolve might be called twice when initializing field
5630                         // expressions (see EmitFieldInitializers, the call to
5631                         // GetInitializerExpression will perform a resolve on the expression,
5632                         // and later the assign will trigger another resolution
5633                         //
5634                         // This leads to bugs (#37014)
5635                         //
5636                         if (type != null){
5637                                 if (RequestedType is NewDelegate)
5638                                         return RequestedType;
5639                                 return this;
5640                         }
5641
5642                         TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5643                         if (texpr == null)
5644                                 return null;
5645
5646                         type = texpr.Type;
5647
5648                         if (type == TypeManager.void_type) {
5649                                 Error_VoidInvalidInTheContext (loc);
5650                                 return null;
5651                         }
5652
5653                         if (Arguments == null) {
5654                                 Expression c = Constantify (type);
5655                                 if (c != null)
5656                                         return c;
5657                         }
5658
5659                         if (TypeManager.IsDelegateType (type)) {
5660                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5661                                 if (RequestedType != null)
5662                                         if (!(RequestedType is DelegateCreation))
5663                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5664                                 return RequestedType;
5665                         }
5666
5667 #if GMCS_SOURCE
5668                         if (type.IsGenericParameter) {
5669                                 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5670
5671                                 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5672                                         Error (304, String.Format (
5673                                                        "Cannot create an instance of the " +
5674                                                        "variable type '{0}' because it " +
5675                                                        "doesn't have the new() constraint",
5676                                                        type));
5677                                         return null;
5678                                 }
5679
5680                                 if ((Arguments != null) && (Arguments.Count != 0)) {
5681                                         Error (417, String.Format (
5682                                                        "`{0}': cannot provide arguments " +
5683                                                        "when creating an instance of a " +
5684                                                        "variable type.", type));
5685                                         return null;
5686                                 }
5687
5688                                 is_type_parameter = true;
5689                                 eclass = ExprClass.Value;
5690                                 return this;
5691                         }
5692 #endif
5693
5694                         if (type.IsAbstract && type.IsSealed) {
5695                                 Report.SymbolRelatedToPreviousError (type);
5696                                 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5697                                 return null;
5698                         }
5699
5700                         if (type.IsInterface || type.IsAbstract){
5701                                 RequestedType = CheckComImport (ec);
5702                                 if (RequestedType != null)
5703                                         return RequestedType;
5704                                 
5705                                 Report.SymbolRelatedToPreviousError (type);
5706                                 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5707                                 return null;
5708                         }
5709
5710                         bool is_struct = type.IsValueType;
5711                         eclass = ExprClass.Value;
5712
5713                         //
5714                         // SRE returns a match for .ctor () on structs (the object constructor), 
5715                         // so we have to manually ignore it.
5716                         //
5717                         if (is_struct && Arguments == null)
5718                                 return this;
5719
5720                         // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5721                         Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5722                                 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5723
5724                         if (ml == null)
5725                                 return null;
5726
5727                         MethodGroupExpr mg = ml as MethodGroupExpr;
5728
5729                         if (mg == null) {
5730                                 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5731                                 return null;
5732                         }
5733
5734                         if (Arguments != null){
5735                                 foreach (Argument a in Arguments){
5736                                         if (!a.Resolve (ec, loc))
5737                                                 return null;
5738                                 }
5739                         }
5740
5741                         method = Invocation.OverloadResolve (ec, mg, Arguments, false, loc);
5742                         if (method == null) {
5743                                 if (almostMatchedMembers.Count != 0)
5744                                         MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
5745                                 return null;
5746                         }
5747
5748                         return this;
5749                 }
5750
5751                 bool DoEmitTypeParameter (EmitContext ec)
5752                 {
5753 #if GMCS_SOURCE
5754                         ILGenerator ig = ec.ig;
5755
5756                         ig.Emit (OpCodes.Ldtoken, type);
5757                         ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
5758                         ig.Emit (OpCodes.Call, TypeManager.activator_create_instance);
5759                         ig.Emit (OpCodes.Unbox_Any, type);
5760                         return true;
5761 #else
5762                         throw new InternalErrorException ();
5763 #endif
5764                 }
5765
5766                 //
5767                 // This DoEmit can be invoked in two contexts:
5768                 //    * As a mechanism that will leave a value on the stack (new object)
5769                 //    * As one that wont (init struct)
5770                 //
5771                 // You can control whether a value is required on the stack by passing
5772                 // need_value_on_stack.  The code *might* leave a value on the stack
5773                 // so it must be popped manually
5774                 //
5775                 // If we are dealing with a ValueType, we have a few
5776                 // situations to deal with:
5777                 //
5778                 //    * The target is a ValueType, and we have been provided
5779                 //      the instance (this is easy, we are being assigned).
5780                 //
5781                 //    * The target of New is being passed as an argument,
5782                 //      to a boxing operation or a function that takes a
5783                 //      ValueType.
5784                 //
5785                 //      In this case, we need to create a temporary variable
5786                 //      that is the argument of New.
5787                 //
5788                 // Returns whether a value is left on the stack
5789                 //
5790                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5791                 {
5792                         bool is_value_type = TypeManager.IsValueType (type);
5793                         ILGenerator ig = ec.ig;
5794
5795                         if (is_value_type){
5796                                 IMemoryLocation ml;
5797
5798                                 // Allow DoEmit() to be called multiple times.
5799                                 // We need to create a new LocalTemporary each time since
5800                                 // you can't share LocalBuilders among ILGeneators.
5801                                 if (!value_target_set)
5802                                         value_target = new LocalTemporary (type);
5803
5804                                 ml = (IMemoryLocation) value_target;
5805                                 ml.AddressOf (ec, AddressOp.Store);
5806                         }
5807
5808                         if (method != null)
5809                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
5810
5811                         if (is_value_type){
5812                                 if (method == null)
5813                                         ig.Emit (OpCodes.Initobj, type);
5814                                 else 
5815                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5816                                 if (need_value_on_stack){
5817                                         value_target.Emit (ec);
5818                                         return true;
5819                                 }
5820                                 return false;
5821                         } else {
5822                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5823                                 return true;
5824                         }
5825                 }
5826
5827                 public override void Emit (EmitContext ec)
5828                 {
5829                         if (is_type_parameter)
5830                                 DoEmitTypeParameter (ec);
5831                         else
5832                                 DoEmit (ec, true);
5833                 }
5834                 
5835                 public override void EmitStatement (EmitContext ec)
5836                 {
5837                         if (is_type_parameter)
5838                                 throw new InvalidOperationException ();
5839
5840                         if (DoEmit (ec, false))
5841                                 ec.ig.Emit (OpCodes.Pop);
5842                 }
5843
5844                 public void AddressOf (EmitContext ec, AddressOp Mode)
5845                 {
5846                         if (is_type_parameter)
5847                                 throw new InvalidOperationException ();
5848
5849                         if (!type.IsValueType){
5850                                 //
5851                                 // We throw an exception.  So far, I believe we only need to support
5852                                 // value types:
5853                                 // foreach (int j in new StructType ())
5854                                 // see bug 42390
5855                                 //
5856                                 throw new Exception ("AddressOf should not be used for classes");
5857                         }
5858
5859                         if (!value_target_set)
5860                                 value_target = new LocalTemporary (type);
5861                                         
5862                         IMemoryLocation ml = (IMemoryLocation) value_target;
5863                         ml.AddressOf (ec, AddressOp.Store);
5864                         if (method != null)
5865                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
5866
5867                         if (method == null)
5868                                 ec.ig.Emit (OpCodes.Initobj, type);
5869                         else 
5870                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5871                         
5872                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5873                 }
5874         }
5875
5876         /// <summary>
5877         ///   14.5.10.2: Represents an array creation expression.
5878         /// </summary>
5879         ///
5880         /// <remarks>
5881         ///   There are two possible scenarios here: one is an array creation
5882         ///   expression that specifies the dimensions and optionally the
5883         ///   initialization data and the other which does not need dimensions
5884         ///   specified but where initialization data is mandatory.
5885         /// </remarks>
5886         public class ArrayCreation : Expression {
5887                 Expression requested_base_type;
5888                 ArrayList initializers;
5889
5890                 //
5891                 // The list of Argument types.
5892                 // This is used to construct the `newarray' or constructor signature
5893                 //
5894                 ArrayList arguments;
5895
5896                 //
5897                 // Method used to create the array object.
5898                 //
5899                 MethodBase new_method = null;
5900                 
5901                 Type array_element_type;
5902                 Type underlying_type;
5903                 bool is_one_dimensional = false;
5904                 bool is_builtin_type = false;
5905                 bool expect_initializers = false;
5906                 int num_arguments = 0;
5907                 int dimensions = 0;
5908                 string rank;
5909
5910                 ArrayList array_data;
5911
5912                 IDictionary bounds;
5913
5914                 // The number of constants in array initializers
5915                 int const_initializers_count;
5916                 
5917                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5918                 {
5919                         this.requested_base_type = requested_base_type;
5920                         this.initializers = initializers;
5921                         this.rank = rank;
5922                         loc = l;
5923
5924                         arguments = new ArrayList ();
5925
5926                         foreach (Expression e in exprs) {
5927                                 arguments.Add (new Argument (e, Argument.AType.Expression));
5928                                 num_arguments++;
5929                         }
5930                 }
5931
5932                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5933                 {
5934                         this.requested_base_type = requested_base_type;
5935                         this.initializers = initializers;
5936                         this.rank = rank;
5937                         loc = l;
5938
5939                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5940                         //
5941                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
5942                         //
5943                         //dimensions = tmp.Length - 1;
5944                         expect_initializers = true;
5945                 }
5946
5947                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5948                 {
5949                         StringBuilder sb = new StringBuilder (rank);
5950                         
5951                         sb.Append ("[");
5952                         for (int i = 1; i < idx_count; i++)
5953                                 sb.Append (",");
5954                         
5955                         sb.Append ("]");
5956
5957                         return new ComposedCast (base_type, sb.ToString (), loc);
5958                 }
5959
5960                 void Error_IncorrectArrayInitializer ()
5961                 {
5962                         Error (178, "Invalid rank specifier: expected `,' or `]'");
5963                 }
5964                 
5965                 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5966                 {
5967                         if (specified_dims) { 
5968                                 Argument a = (Argument) arguments [idx];
5969
5970                                 if (!a.Resolve (ec, loc))
5971                                         return false;
5972
5973                                 Constant c = a.Expr as Constant;
5974                                 if (c != null) {
5975                                         c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5976                                 }
5977
5978                                 if (c == null) {
5979                                         Report.Error (150, a.Expr.Location, "A constant value is expected");
5980                                         return false;
5981                                 }
5982
5983                                 int value = (int) c.GetValue ();
5984                                 
5985                                 if (value != probe.Count) {
5986                                         Error_IncorrectArrayInitializer ();
5987                                         return false;
5988                                 }
5989                                 
5990                                 bounds [idx] = value;
5991                         }
5992
5993                         int child_bounds = -1;
5994                         for (int i = 0; i < probe.Count; ++i) {
5995                                 object o = probe [i];
5996                                 if (o is ArrayList) {
5997                                         ArrayList sub_probe = o as ArrayList;
5998                                         int current_bounds = sub_probe.Count;
5999                                         
6000                                         if (child_bounds == -1) 
6001                                                 child_bounds = current_bounds;
6002
6003                                         else if (child_bounds != current_bounds){
6004                                                 Error_IncorrectArrayInitializer ();
6005                                                 return false;
6006                                         }
6007                                         if (idx + 1 >= dimensions){
6008                                                 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
6009                                                 return false;
6010                                         }
6011                                         
6012                                         bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
6013                                         if (!ret)
6014                                                 return false;
6015                                 } else {
6016                                         if (child_bounds != -1){
6017                                                 Error_IncorrectArrayInitializer ();
6018                                                 return false;
6019                                         }
6020                                         
6021                                         Expression tmp = (Expression) o;
6022                                         tmp = tmp.Resolve (ec);
6023                                         if (tmp == null)
6024                                                 return false;
6025
6026                                         Expression conv = Convert.ImplicitConversionRequired (
6027                                                 ec, tmp, underlying_type, loc);
6028                                         
6029                                         if (conv == null) 
6030                                                 return false;
6031
6032                                         // Initializers with the default values can be ignored
6033                                         Constant c = tmp as Constant;
6034                                         if (c != null) {
6035                                                 if (c.IsDefaultInitializer (array_element_type)) {
6036                                                         conv = null;
6037                                                 }
6038                                                 else {
6039                                                         ++const_initializers_count;
6040                                                 }
6041                                         } else {
6042                                                 // Used to invalidate static initializer
6043                                                 const_initializers_count = int.MinValue;
6044                                         }
6045                                         
6046                                         array_data.Add (conv);
6047                                 }
6048                         }
6049
6050                         return true;
6051                 }
6052                 
6053                 public void UpdateIndices ()
6054                 {
6055                         int i = 0;
6056                         for (ArrayList probe = initializers; probe != null;) {
6057                                 if (probe.Count > 0 && probe [0] is ArrayList) {
6058                                         Expression e = new IntConstant (probe.Count, Location.Null);
6059                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6060
6061                                         bounds [i++] =  probe.Count;
6062                                         
6063                                         probe = (ArrayList) probe [0];
6064                                         
6065                                 } else {
6066                                         Expression e = new IntConstant (probe.Count, Location.Null);
6067                                         arguments.Add (new Argument (e, Argument.AType.Expression));
6068
6069                                         bounds [i++] = probe.Count;
6070                                         return;
6071                                 }
6072                         }
6073
6074                 }
6075                 
6076                 bool ResolveInitializers (EmitContext ec)
6077                 {
6078                         if (initializers == null) {
6079                                 return !expect_initializers;
6080                         }
6081                         
6082                         if (underlying_type == null)
6083                                 return false;
6084                         
6085                         //
6086                         // We use this to store all the date values in the order in which we
6087                         // will need to store them in the byte blob later
6088                         //
6089                         array_data = new ArrayList ();
6090                         bounds = new System.Collections.Specialized.HybridDictionary ();
6091                         
6092                         if (arguments != null)
6093                                 return CheckIndices (ec, initializers, 0, true);
6094
6095                         arguments = new ArrayList ();
6096
6097                         if (!CheckIndices (ec, initializers, 0, false))
6098                                 return false;
6099                                 
6100                         UpdateIndices ();
6101                                 
6102                         if (arguments.Count != dimensions) {
6103                                 Error_IncorrectArrayInitializer ();
6104                                 return false;
6105                         }
6106
6107                         return true;
6108                 }
6109
6110                 //
6111                 // Creates the type of the array
6112                 //
6113                 bool LookupType (EmitContext ec)
6114                 {
6115                         StringBuilder array_qualifier = new StringBuilder (rank);
6116
6117                         //
6118                         // `In the first form allocates an array instace of the type that results
6119                         // from deleting each of the individual expression from the expression list'
6120                         //
6121                         if (num_arguments > 0) {
6122                                 array_qualifier.Append ("[");
6123                                 for (int i = num_arguments-1; i > 0; i--)
6124                                         array_qualifier.Append (",");
6125                                 array_qualifier.Append ("]");                           
6126                         }
6127
6128                         //
6129                         // Lookup the type
6130                         //
6131                         TypeExpr array_type_expr;
6132                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
6133                         array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
6134                         if (array_type_expr == null)
6135                                 return false;
6136
6137                         type = array_type_expr.Type;
6138                         underlying_type = TypeManager.GetElementType (type);
6139                         dimensions = type.GetArrayRank ();
6140
6141                         return true;
6142                 }
6143                 
6144                 public override Expression DoResolve (EmitContext ec)
6145                 {
6146                         if (type != null)
6147                                 return this;
6148
6149                         if (!LookupType (ec))
6150                                 return null;
6151                         
6152                         array_element_type = TypeManager.GetElementType (type);
6153                         if (array_element_type.IsAbstract && array_element_type.IsSealed) {
6154                                 Report.Error (719, loc, "`{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
6155                                 return null;
6156                         }
6157
6158                         //
6159                         // First step is to validate the initializers and fill
6160                         // in any missing bits
6161                         //
6162                         if (!ResolveInitializers (ec))
6163                                 return null;
6164
6165                         int arg_count;
6166                         if (arguments == null)
6167                                 arg_count = 0;
6168                         else {
6169                                 arg_count = arguments.Count;
6170                                 foreach (Argument a in arguments){
6171                                         if (!a.Resolve (ec, loc))
6172                                                 return null;
6173
6174                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
6175                                         if (real_arg == null)
6176                                                 return null;
6177
6178                                         a.Expr = real_arg;
6179                                 }
6180                         }
6181                         
6182                         if (arg_count == 1) {
6183                                 is_one_dimensional = true;
6184                                 eclass = ExprClass.Value;
6185                                 return this;
6186                         }
6187
6188                         is_builtin_type = TypeManager.IsBuiltinType (type);
6189
6190                         if (is_builtin_type) {
6191                                 Expression ml;
6192                                 
6193                                 ml = MemberLookup (ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
6194                                                    AllBindingFlags, loc);
6195                                 
6196                                 if (!(ml is MethodGroupExpr)) {
6197                                         ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
6198                                         return null;
6199                                 }
6200                                 
6201                                 if (ml == null) {
6202                                         Error (-6, "New invocation: Can not find a constructor for " +
6203                                                       "this argument list");
6204                                         return null;
6205                                 }
6206                                 
6207                                 new_method = Invocation.OverloadResolve (
6208                                         ec, (MethodGroupExpr) ml, arguments, false, loc);
6209
6210                                 if (new_method == null) {
6211                                         Error (-6, "New invocation: Can not find a constructor for " +
6212                                                       "this argument list");
6213                                         return null;
6214                                 }
6215                                 
6216                                 eclass = ExprClass.Value;
6217                                 return this;
6218                         } else {
6219                                 ModuleBuilder mb = CodeGen.Module.Builder;
6220                                 ArrayList args = new ArrayList ();
6221                                 
6222                                 if (arguments != null) {
6223                                         for (int i = 0; i < arg_count; i++)
6224                                                 args.Add (TypeManager.int32_type);
6225                                 }
6226                                 
6227                                 Type [] arg_types = null;
6228
6229                                 if (args.Count > 0)
6230                                         arg_types = new Type [args.Count];
6231                                 
6232                                 args.CopyTo (arg_types, 0);
6233                                 
6234                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
6235                                                             arg_types);
6236
6237                                 if (new_method == null) {
6238                                         Error (-6, "New invocation: Can not find a constructor for " +
6239                                                       "this argument list");
6240                                         return null;
6241                                 }
6242                                 
6243                                 eclass = ExprClass.Value;
6244                                 return this;
6245                         }
6246                 }
6247
6248                 byte [] MakeByteBlob ()
6249                 {
6250                         int factor;
6251                         byte [] data;
6252                         byte [] element;
6253                         int count = array_data.Count;
6254
6255                         if (underlying_type.IsEnum)
6256                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
6257                         
6258                         factor = GetTypeSize (underlying_type);
6259                         if (factor == 0)
6260                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
6261
6262                         data = new byte [(count * factor + 4) & ~3];
6263                         int idx = 0;
6264
6265                         for (int i = 0; i < count; ++i) {
6266                                 object v = array_data [i];
6267
6268                                 if (v is EnumConstant)
6269                                         v = ((EnumConstant) v).Child;
6270                                 
6271                                 if (v is Constant && !(v is StringConstant))
6272                                         v = ((Constant) v).GetValue ();
6273                                 else {
6274                                         idx += factor;
6275                                         continue;
6276                                 }
6277                                 
6278                                 if (underlying_type == TypeManager.int64_type){
6279                                         if (!(v is Expression)){
6280                                                 long val = (long) v;
6281                                                 
6282                                                 for (int j = 0; j < factor; ++j) {
6283                                                         data [idx + j] = (byte) (val & 0xFF);
6284                                                         val = (val >> 8);
6285                                                 }
6286                                         }
6287                                 } else if (underlying_type == TypeManager.uint64_type){
6288                                         if (!(v is Expression)){
6289                                                 ulong val = (ulong) v;
6290
6291                                                 for (int j = 0; j < factor; ++j) {
6292                                                         data [idx + j] = (byte) (val & 0xFF);
6293                                                         val = (val >> 8);
6294                                                 }
6295                                         }
6296                                 } else if (underlying_type == TypeManager.float_type) {
6297                                         if (!(v is Expression)){
6298                                                 element = BitConverter.GetBytes ((float) v);
6299                                                         
6300                                                 for (int j = 0; j < factor; ++j)
6301                                                         data [idx + j] = element [j];
6302                                         }
6303                                 } else if (underlying_type == TypeManager.double_type) {
6304                                         if (!(v is Expression)){
6305                                                 element = BitConverter.GetBytes ((double) v);
6306
6307                                                 for (int j = 0; j < factor; ++j)
6308                                                         data [idx + j] = element [j];
6309                                         }
6310                                 } else if (underlying_type == TypeManager.char_type){
6311                                         if (!(v is Expression)){
6312                                                 int val = (int) ((char) v);
6313                                                 
6314                                                 data [idx] = (byte) (val & 0xff);
6315                                                 data [idx+1] = (byte) (val >> 8);
6316                                         }
6317                                 } else if (underlying_type == TypeManager.short_type){
6318                                         if (!(v is Expression)){
6319                                                 int val = (int) ((short) v);
6320                                         
6321                                                 data [idx] = (byte) (val & 0xff);
6322                                                 data [idx+1] = (byte) (val >> 8);
6323                                         }
6324                                 } else if (underlying_type == TypeManager.ushort_type){
6325                                         if (!(v is Expression)){
6326                                                 int val = (int) ((ushort) v);
6327                                         
6328                                                 data [idx] = (byte) (val & 0xff);
6329                                                 data [idx+1] = (byte) (val >> 8);
6330                                         }
6331                                 } else if (underlying_type == TypeManager.int32_type) {
6332                                         if (!(v is Expression)){
6333                                                 int val = (int) v;
6334                                         
6335                                                 data [idx]   = (byte) (val & 0xff);
6336                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6337                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6338                                                 data [idx+3] = (byte) (val >> 24);
6339                                         }
6340                                 } else if (underlying_type == TypeManager.uint32_type) {
6341                                         if (!(v is Expression)){
6342                                                 uint val = (uint) v;
6343                                         
6344                                                 data [idx]   = (byte) (val & 0xff);
6345                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
6346                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
6347                                                 data [idx+3] = (byte) (val >> 24);
6348                                         }
6349                                 } else if (underlying_type == TypeManager.sbyte_type) {
6350                                         if (!(v is Expression)){
6351                                                 sbyte val = (sbyte) v;
6352                                                 data [idx] = (byte) val;
6353                                         }
6354                                 } else if (underlying_type == TypeManager.byte_type) {
6355                                         if (!(v is Expression)){
6356                                                 byte val = (byte) v;
6357                                                 data [idx] = (byte) val;
6358                                         }
6359                                 } else if (underlying_type == TypeManager.bool_type) {
6360                                         if (!(v is Expression)){
6361                                                 bool val = (bool) v;
6362                                                 data [idx] = (byte) (val ? 1 : 0);
6363                                         }
6364                                 } else if (underlying_type == TypeManager.decimal_type){
6365                                         if (!(v is Expression)){
6366                                                 int [] bits = Decimal.GetBits ((decimal) v);
6367                                                 int p = idx;
6368
6369                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
6370                                                 int [] nbits = new int [4];
6371                                                 nbits [0] = bits [3];
6372                                                 nbits [1] = bits [2];
6373                                                 nbits [2] = bits [0];
6374                                                 nbits [3] = bits [1];
6375                                                 
6376                                                 for (int j = 0; j < 4; j++){
6377                                                         data [p++] = (byte) (nbits [j] & 0xff);
6378                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
6379                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
6380                                                         data [p++] = (byte) (nbits [j] >> 24);
6381                                                 }
6382                                         }
6383                                 } else
6384                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
6385
6386                                 idx += factor;
6387                         }
6388
6389                         return data;
6390                 }
6391
6392                 //
6393                 // Emits the initializers for the array
6394                 //
6395                 void EmitStaticInitializers (EmitContext ec)
6396                 {
6397                         //
6398                         // First, the static data
6399                         //
6400                         FieldBuilder fb;
6401                         ILGenerator ig = ec.ig;
6402                         
6403                         byte [] data = MakeByteBlob ();
6404
6405                         fb = RootContext.MakeStaticData (data);
6406
6407                         ig.Emit (OpCodes.Dup);
6408                         ig.Emit (OpCodes.Ldtoken, fb);
6409                         ig.Emit (OpCodes.Call,
6410                                  TypeManager.void_initializearray_array_fieldhandle);
6411                 }
6412
6413                 //
6414                 // Emits pieces of the array that can not be computed at compile
6415                 // time (variables and string locations).
6416                 //
6417                 // This always expect the top value on the stack to be the array
6418                 //
6419                 void EmitDynamicInitializers (EmitContext ec)
6420                 {
6421                         ILGenerator ig = ec.ig;
6422                         int dims = bounds.Count;
6423                         int [] current_pos = new int [dims];
6424
6425                         MethodInfo set = null;
6426
6427                         if (dims != 1){
6428                                 Type [] args = new Type [dims + 1];
6429
6430                                 for (int j = 0; j < dims; j++)
6431                                         args [j] = TypeManager.int32_type;
6432                                 args [dims] = array_element_type;
6433                                 
6434                                 set = CodeGen.Module.Builder.GetArrayMethod (
6435                                         type, "Set",
6436                                         CallingConventions.HasThis | CallingConventions.Standard,
6437                                         TypeManager.void_type, args);
6438                         }
6439
6440                         for (int i = 0; i < array_data.Count; i++){
6441
6442                                 Expression e = (Expression)array_data [i];
6443
6444                                 if (e != null) {
6445                                         Type etype = e.Type;
6446
6447                                         ig.Emit (OpCodes.Dup);
6448
6449                                         for (int idx = 0; idx < dims; idx++) 
6450                                                 IntConstant.EmitInt (ig, current_pos [idx]);
6451
6452                                         //
6453                                         // If we are dealing with a struct, get the
6454                                         // address of it, so we can store it.
6455                                         //
6456                                         if ((dims == 1) && etype.IsValueType &&
6457                                             (!TypeManager.IsBuiltinOrEnum (etype) ||
6458                                              etype == TypeManager.decimal_type)) {
6459                                                 if (e is New){
6460                                                         New n = (New) e;
6461
6462                                                         //
6463                                                         // Let new know that we are providing
6464                                                         // the address where to store the results
6465                                                         //
6466                                                         n.DisableTemporaryValueType ();
6467                                                 }
6468
6469                                                 ig.Emit (OpCodes.Ldelema, etype);
6470                                         }
6471
6472                                         e.Emit (ec);
6473
6474                                         if (dims == 1) {
6475                                                 bool is_stobj, has_type_arg;
6476                                                 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
6477                                                 if (is_stobj)
6478                                                         ig.Emit (OpCodes.Stobj, etype);
6479                                                 else if (has_type_arg)
6480                                                         ig.Emit (op, etype);
6481                                                 else
6482                                                         ig.Emit (op);
6483                                         } else 
6484                                                 ig.Emit (OpCodes.Call, set);
6485
6486                                 }
6487                                 
6488                                 //
6489                                 // Advance counter
6490                                 //
6491                                 for (int j = dims - 1; j >= 0; j--){
6492                                         current_pos [j]++;
6493                                         if (current_pos [j] < (int) bounds [j])
6494                                                 break;
6495                                         current_pos [j] = 0;
6496                                 }
6497                         }
6498                 }
6499
6500                 void EmitArrayArguments (EmitContext ec)
6501                 {
6502                         ILGenerator ig = ec.ig;
6503                         
6504                         foreach (Argument a in arguments) {
6505                                 Type atype = a.Type;
6506                                 a.Emit (ec);
6507
6508                                 if (atype == TypeManager.uint64_type)
6509                                         ig.Emit (OpCodes.Conv_Ovf_U4);
6510                                 else if (atype == TypeManager.int64_type)
6511                                         ig.Emit (OpCodes.Conv_Ovf_I4);
6512                         }
6513                 }
6514                 
6515                 public override void Emit (EmitContext ec)
6516                 {
6517                         ILGenerator ig = ec.ig;
6518                         
6519                         EmitArrayArguments (ec);
6520                         if (is_one_dimensional)
6521                                 ig.Emit (OpCodes.Newarr, array_element_type);
6522                         else {
6523                                 if (is_builtin_type) 
6524                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6525                                 else 
6526                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6527                         }
6528                         
6529                         if (initializers == null)
6530                                 return;
6531
6532                         // This is a treshold for static initializers
6533                         // I tried to make more accurate but it seems to me that Array.Initialize is
6534                         // always slower (managed -> unmanaged switch?)
6535                         const int max_automatic_initializers = 200;
6536
6537                         if (const_initializers_count > max_automatic_initializers && TypeManager.IsPrimitiveType (array_element_type)) {
6538                                 EmitStaticInitializers (ec);
6539                                 return;
6540                         }
6541                                 
6542                         EmitDynamicInitializers (ec);
6543                 }
6544
6545                 public override bool GetAttributableValue (Type valueType, out object value)
6546                 {
6547                         if (!is_one_dimensional){
6548 //                              Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6549                                 return base.GetAttributableValue (null, out value);
6550                         }
6551
6552                         if (array_data == null) {
6553                                 Constant c = (Constant)((Argument)arguments [0]).Expr;
6554                                 if (c.IsDefaultValue) {
6555                                         value = Array.CreateInstance (array_element_type, 0);
6556                                         return true;
6557                                 }
6558 //                              Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6559                                 return base.GetAttributableValue (null, out value);
6560                         }
6561                         
6562                         Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6563                         object element_value;
6564                         for (int i = 0; i < ret.Length; ++i)
6565                         {
6566                                 Expression e = (Expression)array_data [i];
6567
6568                                 // Is null when an initializer is optimized (value == predefined value)
6569                                 if (e == null) 
6570                                         continue;
6571
6572                                 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6573                                         value = null;
6574                                         return false;
6575                                 }
6576                                 ret.SetValue (element_value, i);
6577                         }
6578                         value = ret;
6579                         return true;
6580                 }
6581         }
6582         
6583         public sealed class CompilerGeneratedThis : This
6584         {
6585                 public static This Instance = new CompilerGeneratedThis ();
6586
6587                 private CompilerGeneratedThis ()
6588                         : base (Location.Null)
6589                 {
6590                 }
6591
6592                 public override Expression DoResolve (EmitContext ec)
6593                 {
6594                         eclass = ExprClass.Variable;
6595                         type = ec.ContainerType;
6596                         variable = new SimpleThis (type);
6597                         return this;
6598                 }
6599         }
6600         
6601         /// <summary>
6602         ///   Represents the `this' construct
6603         /// </summary>
6604
6605         public class This : VariableReference, IVariable
6606         {
6607                 Block block;
6608                 VariableInfo variable_info;
6609                 protected Variable variable;
6610                 bool is_struct;
6611
6612                 public This (Block block, Location loc)
6613                 {
6614                         this.loc = loc;
6615                         this.block = block;
6616                 }
6617
6618                 public This (Location loc)
6619                 {
6620                         this.loc = loc;
6621                 }
6622
6623                 public VariableInfo VariableInfo {
6624                         get { return variable_info; }
6625                 }
6626
6627                 public bool VerifyFixed ()
6628                 {
6629                         return !TypeManager.IsValueType (Type);
6630                 }
6631
6632                 public override bool IsRef {
6633                         get { return is_struct; }
6634                 }
6635
6636                 public override Variable Variable {
6637                         get { return variable; }
6638                 }
6639
6640                 public bool ResolveBase (EmitContext ec)
6641                 {
6642                         eclass = ExprClass.Variable;
6643
6644                         if (ec.TypeContainer.CurrentType != null)
6645                                 type = ec.TypeContainer.CurrentType;
6646                         else
6647                                 type = ec.ContainerType;
6648
6649                         is_struct = ec.TypeContainer is Struct;
6650
6651                         if (ec.IsStatic) {
6652                                 Error (26, "Keyword `this' is not valid in a static property, " +
6653                                        "static method, or static field initializer");
6654                                 return false;
6655                         }
6656
6657                         if (block != null) {
6658                                 if (block.Toplevel.ThisVariable != null)
6659                                         variable_info = block.Toplevel.ThisVariable.VariableInfo;
6660
6661                                 AnonymousContainer am = ec.CurrentAnonymousMethod;
6662                                 if (is_struct && (am != null) && !am.IsIterator) {
6663                                         Report.Error (1673, loc, "Anonymous methods inside structs " +
6664                                                       "cannot access instance members of `this'. " +
6665                                                       "Consider copying `this' to a local variable " +
6666                                                       "outside the anonymous method and using the " +
6667                                                       "local instead.");
6668                                         return false;
6669                                 }
6670
6671                                 AnonymousMethodHost host = block.Toplevel.AnonymousMethodHost;
6672                                 if ((host != null) && (!is_struct || host.IsIterator)) {
6673                                         variable = host.CaptureThis ();
6674                                         type = variable.Type;
6675                                         is_struct = false;
6676                                 }
6677                         }
6678
6679                         if (variable == null)
6680                                 variable = new SimpleThis (type);
6681                         
6682                         return true;
6683                 }
6684
6685                 public override Expression DoResolve (EmitContext ec)
6686                 {
6687                         if (!ResolveBase (ec))
6688                                 return null;
6689
6690                         if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6691                             !variable_info.IsAssigned (ec)) {
6692                                 Error (188, "The `this' object cannot be used before all of its " +
6693                                        "fields are assigned to");
6694                                 variable_info.SetAssigned (ec);
6695                                 return this;
6696                         }
6697
6698                         if (ec.IsFieldInitializer) {
6699                                 Error (27, "Keyword `this' is not available in the current context");
6700                                 return null;
6701                         }
6702
6703                         return this;
6704                 }
6705
6706                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6707                 {
6708                         if (!ResolveBase (ec))
6709                                 return null;
6710
6711                         if (variable_info != null)
6712                                 variable_info.SetAssigned (ec);
6713                         
6714                         if (ec.TypeContainer is Class){
6715                                 Error (1604, "Cannot assign to 'this' because it is read-only");
6716                                 return null;
6717                         }
6718
6719                         return this;
6720                 }
6721                 public override int GetHashCode()
6722                 {
6723                         return block.GetHashCode ();
6724                 }
6725
6726                 public override bool Equals (object obj)
6727                 {
6728                         This t = obj as This;
6729                         if (t == null)
6730                                 return false;
6731
6732                         return block == t.block;
6733                 }
6734
6735                 protected class SimpleThis : Variable
6736                 {
6737                         Type type;
6738
6739                         public SimpleThis (Type type)
6740                         {
6741                                 this.type = type;
6742                         }
6743
6744                         public override Type Type {
6745                                 get { return type; }
6746                         }
6747
6748                         public override bool HasInstance {
6749                                 get { return false; }
6750                         }
6751
6752                         public override bool NeedsTemporary {
6753                                 get { return false; }
6754                         }
6755
6756                         public override void EmitInstance (EmitContext ec)
6757                         {
6758                                 // Do nothing.
6759                         }
6760
6761                         public override void Emit (EmitContext ec)
6762                         {
6763                                 ec.ig.Emit (OpCodes.Ldarg_0);
6764                         }
6765
6766                         public override void EmitAssign (EmitContext ec)
6767                         {
6768                                 throw new InvalidOperationException ();
6769                         }
6770
6771                         public override void EmitAddressOf (EmitContext ec)
6772                         {
6773                                 ec.ig.Emit (OpCodes.Ldarg_0);
6774                         }
6775                 }
6776         }
6777
6778         /// <summary>
6779         ///   Represents the `__arglist' construct
6780         /// </summary>
6781         public class ArglistAccess : Expression
6782         {
6783                 public ArglistAccess (Location loc)
6784                 {
6785                         this.loc = loc;
6786                 }
6787
6788                 public override Expression DoResolve (EmitContext ec)
6789                 {
6790                         eclass = ExprClass.Variable;
6791                         type = TypeManager.runtime_argument_handle_type;
6792
6793                         if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs) 
6794                         {
6795                                 Error (190, "The __arglist construct is valid only within " +
6796                                        "a variable argument method");
6797                                 return null;
6798                         }
6799
6800                         return this;
6801                 }
6802
6803                 public override void Emit (EmitContext ec)
6804                 {
6805                         ec.ig.Emit (OpCodes.Arglist);
6806                 }
6807         }
6808
6809         /// <summary>
6810         ///   Represents the `__arglist (....)' construct
6811         /// </summary>
6812         public class Arglist : Expression
6813         {
6814                 public readonly Argument[] Arguments;
6815
6816                 public Arglist (Argument[] args, Location l)
6817                 {
6818                         Arguments = args;
6819                         loc = l;
6820                 }
6821
6822                 public Type[] ArgumentTypes {
6823                         get {
6824                                 Type[] retval = new Type [Arguments.Length];
6825                                 for (int i = 0; i < Arguments.Length; i++)
6826                                         retval [i] = Arguments [i].Type;
6827                                 return retval;
6828                         }
6829                 }
6830
6831                 public override Expression DoResolve (EmitContext ec)
6832                 {
6833                         eclass = ExprClass.Variable;
6834                         type = TypeManager.runtime_argument_handle_type;
6835
6836                         foreach (Argument arg in Arguments) {
6837                                 if (!arg.Resolve (ec, loc))
6838                                         return null;
6839                         }
6840
6841                         return this;
6842                 }
6843
6844                 public override void Emit (EmitContext ec)
6845                 {
6846                         foreach (Argument arg in Arguments)
6847                                 arg.Emit (ec);
6848                 }
6849         }
6850
6851         //
6852         // This produces the value that renders an instance, used by the iterators code
6853         //
6854         public class ProxyInstance : Expression, IMemoryLocation  {
6855                 public override Expression DoResolve (EmitContext ec)
6856                 {
6857                         eclass = ExprClass.Variable;
6858                         type = ec.ContainerType;
6859                         return this;
6860                 }
6861                 
6862                 public override void Emit (EmitContext ec)
6863                 {
6864                         ec.ig.Emit (OpCodes.Ldarg_0);
6865
6866                 }
6867                 
6868                 public void AddressOf (EmitContext ec, AddressOp mode)
6869                 {
6870                         ec.ig.Emit (OpCodes.Ldarg_0);
6871                 }
6872         }
6873
6874         /// <summary>
6875         ///   Implements the typeof operator
6876         /// </summary>
6877         public class TypeOf : Expression {
6878                 readonly Expression QueriedType;
6879                 protected Type typearg;
6880                 
6881                 public TypeOf (Expression queried_type, Location l)
6882                 {
6883                         QueriedType = queried_type;
6884                         loc = l;
6885                 }
6886
6887                 public override Expression DoResolve (EmitContext ec)
6888                 {
6889                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6890                         if (texpr == null)
6891                                 return null;
6892
6893                         typearg = texpr.Type;
6894
6895                         if (typearg == TypeManager.void_type) {
6896                                 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6897                                 return null;
6898                         }
6899
6900                         if (typearg.IsPointer && !ec.InUnsafe){
6901                                 UnsafeError (loc);
6902                                 return null;
6903                         }
6904
6905                         type = TypeManager.type_type;
6906                         // Even though what is returned is a type object, it's treated as a value by the compiler.
6907                         // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6908                         eclass = ExprClass.Value;
6909                         return this;
6910                 }
6911
6912                 public override void Emit (EmitContext ec)
6913                 {
6914                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
6915                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6916                 }
6917
6918                 public override bool GetAttributableValue (Type valueType, out object value)
6919                 {
6920                         if (TypeManager.ContainsGenericParameters (typearg)) {
6921                                 Report.SymbolRelatedToPreviousError(typearg);
6922                                 Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters",
6923                                              TypeManager.CSharpName(typearg));
6924                                 value = null;
6925                                 return false;
6926                         }
6927
6928                         if (valueType == TypeManager.object_type) {
6929                                 value = (object)typearg;
6930                                 return true;
6931                         }
6932                         value = typearg;
6933                         return true;
6934                 }
6935
6936                 public Type TypeArgument
6937                 {
6938                         get
6939                         {
6940                                 return typearg;
6941                         }
6942                 }
6943         }
6944
6945         /// <summary>
6946         ///   Implements the `typeof (void)' operator
6947         /// </summary>
6948         public class TypeOfVoid : TypeOf {
6949                 public TypeOfVoid (Location l) : base (null, l)
6950                 {
6951                         loc = l;
6952                 }
6953
6954                 public override Expression DoResolve (EmitContext ec)
6955                 {
6956                         type = TypeManager.type_type;
6957                         typearg = TypeManager.void_type;
6958                         // See description in TypeOf.
6959                         eclass = ExprClass.Value;
6960                         return this;
6961                 }
6962         }
6963
6964         /// <summary>
6965         ///   Implements the sizeof expression
6966         /// </summary>
6967         public class SizeOf : Expression {
6968                 public Expression QueriedType;
6969                 Type type_queried;
6970                 
6971                 public SizeOf (Expression queried_type, Location l)
6972                 {
6973                         this.QueriedType = queried_type;
6974                         loc = l;
6975                 }
6976
6977                 public override Expression DoResolve (EmitContext ec)
6978                 {
6979                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6980                         if (texpr == null)
6981                                 return null;
6982
6983 #if GMCS_SOURCE
6984                         if (texpr is TypeParameterExpr){
6985                                 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6986                                 return null;
6987                         }
6988 #endif
6989
6990                         type_queried = texpr.Type;
6991                         if (type_queried.IsEnum)
6992                                 type_queried = TypeManager.EnumToUnderlying (type_queried);
6993
6994                         if (type_queried == TypeManager.void_type) {
6995                                 Expression.Error_VoidInvalidInTheContext (loc);
6996                                 return null;
6997                         }
6998
6999                         int size_of = GetTypeSize (type_queried);
7000                         if (size_of > 0) {
7001                                 return new IntConstant (size_of, loc);
7002                         }
7003
7004                         if (!ec.InUnsafe) {
7005                                 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)",
7006                                          TypeManager.CSharpName (type_queried));
7007                                 return null;
7008                         }
7009
7010                         if (!TypeManager.VerifyUnManaged (type_queried, loc)){
7011                                 return null;
7012                         }
7013                         
7014                         type = TypeManager.int32_type;
7015                         eclass = ExprClass.Value;
7016                         return this;
7017                 }
7018
7019                 public override void Emit (EmitContext ec)
7020                 {
7021                         int size = GetTypeSize (type_queried);
7022
7023                         if (size == 0)
7024                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
7025                         else
7026                                 IntConstant.EmitInt (ec.ig, size);
7027                 }
7028         }
7029
7030         /// <summary>
7031         ///   Implements the qualified-alias-member (::) expression.
7032         /// </summary>
7033         public class QualifiedAliasMember : Expression
7034         {
7035                 string alias, identifier;
7036
7037                 public QualifiedAliasMember (string alias, string identifier, Location l)
7038                 {
7039                         this.alias = alias;
7040                         this.identifier = identifier;
7041                         loc = l;
7042                 }
7043
7044                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7045                 {
7046                         if (alias == "global")
7047                                 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
7048
7049                         int errors = Report.Errors;
7050                         FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7051                         if (fne == null) {
7052                                 if (errors == Report.Errors)
7053                                         Report.Error (432, loc, "Alias `{0}' not found", alias);
7054                                 return null;
7055                         }
7056                         if (fne.eclass != ExprClass.Namespace) {
7057                                 if (!silent)
7058                                         Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
7059                                 return null;
7060                         }
7061                         return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
7062                 }
7063
7064                 public override Expression DoResolve (EmitContext ec)
7065                 {
7066                         FullNamedExpression fne;
7067                         if (alias == "global") {
7068                                 fne = RootNamespace.Global;
7069                         } else {
7070                                 int errors = Report.Errors;
7071                                 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
7072                                 if (fne == null) {
7073                                         if (errors == Report.Errors)
7074                                                 Report.Error (432, loc, "Alias `{0}' not found", alias);
7075                                         return null;
7076                                 }
7077                         }
7078
7079                         Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
7080                         if (retval == null)
7081                                 return null;
7082
7083                         if (!(retval is FullNamedExpression)) {
7084                                 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
7085                                 return null;
7086                         }
7087
7088                         // We defer this check till the end to match the behaviour of CSC
7089                         if (fne.eclass != ExprClass.Namespace) {
7090                                 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
7091                                 return null;
7092                         }
7093                         return retval;
7094                 }
7095
7096                 public override void Emit (EmitContext ec)
7097                 {
7098                         throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
7099                 }
7100
7101
7102                 public override string ToString ()
7103                 {
7104                         return alias + "::" + identifier;
7105                 }
7106
7107                 public override string GetSignatureForError ()
7108                 {
7109                         return ToString ();
7110                 }
7111         }
7112
7113         /// <summary>
7114         ///   Implements the member access expression
7115         /// </summary>
7116         public class MemberAccess : Expression {
7117                 public readonly string Identifier;
7118                 Expression expr;
7119
7120                 public MemberAccess (Expression expr, string id)
7121                         : this (expr, id, expr.Location)
7122                 {
7123                 }
7124
7125                 public MemberAccess (Expression expr, string identifier, Location loc)
7126                 {
7127                         this.expr = expr;
7128                         Identifier = identifier;
7129                         this.loc = loc;
7130                 }
7131
7132                 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
7133                         : this (expr, identifier, loc)
7134                 {
7135                         this.args = args;
7136                 }
7137
7138                 TypeArguments args;
7139
7140                 public Expression Expr {
7141                         get { return expr; }
7142                 }
7143
7144                 protected string LookupIdentifier {
7145                         get { return MemberName.MakeName (Identifier, args); }
7146                 }
7147
7148                 // TODO: this method has very poor performace for Enum fields and
7149                 // probably for other constants as well
7150                 Expression DoResolve (EmitContext ec, Expression right_side)
7151                 {
7152                         if (type != null)
7153                                 throw new Exception ();
7154
7155                         //
7156                         // Resolve the expression with flow analysis turned off, we'll do the definite
7157                         // assignment checks later.  This is because we don't know yet what the expression
7158                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
7159                         // definite assignment check on the actual field and not on the whole struct.
7160                         //
7161
7162                         SimpleName original = expr as SimpleName;
7163                         Expression new_expr = expr.Resolve (ec,
7164                                 ResolveFlags.VariableOrValue | ResolveFlags.Type |
7165                                 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
7166
7167                         if (new_expr == null)
7168                                 return null;
7169
7170                         if (new_expr is Namespace) {
7171                                 Namespace ns = (Namespace) new_expr;
7172                                 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
7173 #if GMCS_SOURCE
7174                                 if ((retval != null) && (args != null))
7175                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
7176 #endif
7177
7178                                 if (retval == null)
7179                                         ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
7180                                 return retval;
7181                         }
7182
7183                         Type expr_type = new_expr.Type;
7184                         if (expr_type.IsPointer || expr_type == TypeManager.void_type || new_expr is NullLiteral){
7185                                 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
7186                                 return null;
7187                         }
7188                         if (expr_type == TypeManager.anonymous_method_type){
7189                                 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
7190                                 return null;
7191                         }
7192
7193                         Constant c = new_expr as Constant;
7194                         if (c != null && c.GetValue () == null) {
7195                                 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
7196                                         "System.NullReferenceException");
7197                         }
7198
7199                         Expression member_lookup;
7200                         member_lookup = MemberLookup (
7201                                 ec.ContainerType, expr_type, expr_type, Identifier, loc);
7202 #if GMCS_SOURCE
7203                         if ((member_lookup == null) && (args != null)) {
7204                                 member_lookup = MemberLookup (
7205                                         ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
7206                         }
7207 #endif
7208                         if (member_lookup == null) {
7209                                 MemberLookupFailed (
7210                                         ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
7211                                 return null;
7212                         }
7213
7214                         TypeExpr texpr = member_lookup as TypeExpr;
7215                         if (texpr != null) {
7216                                 if (!(new_expr is TypeExpr) && 
7217                                     (original == null || !original.IdenticalNameAndTypeName (ec, new_expr, loc))) {
7218                                         Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
7219                                                 Identifier, member_lookup.GetSignatureForError ());
7220                                         return null;
7221                                 }
7222
7223                                 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
7224                                         Report.SymbolRelatedToPreviousError (member_lookup.Type);
7225                                         ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
7226                                         return null;
7227                                 }
7228
7229 #if GMCS_SOURCE
7230                                 ConstructedType ct = new_expr as ConstructedType;
7231                                 if (ct != null) {
7232                                         //
7233                                         // When looking up a nested type in a generic instance
7234                                         // via reflection, we always get a generic type definition
7235                                         // and not a generic instance - so we have to do this here.
7236                                         //
7237                                         // See gtest-172-lib.cs and gtest-172.cs for an example.
7238                                         //
7239                                         ct = new ConstructedType (
7240                                                 member_lookup.Type, ct.TypeArguments, loc);
7241
7242                                         return ct.ResolveAsTypeStep (ec, false);
7243                                 }
7244 #endif
7245                                 return member_lookup;
7246                         }
7247
7248                         MemberExpr me = (MemberExpr) member_lookup;
7249                         member_lookup = me.ResolveMemberAccess (ec, new_expr, loc, original);
7250                         if (member_lookup == null)
7251                                 return null;
7252
7253                         if (args != null) {
7254                                 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
7255                                 if (mg == null)
7256                                         throw new InternalErrorException ();
7257
7258                                 return mg.ResolveGeneric (ec, args);
7259                         }
7260
7261                         if (original != null && !TypeManager.IsValueType (expr_type)) {
7262                                 me = member_lookup as MemberExpr;
7263                                 if (me != null && me.IsInstance) {
7264                                         LocalVariableReference var = new_expr as LocalVariableReference;
7265                                         if (var != null && !var.VerifyAssigned (ec))
7266                                                 return null;
7267                                 }
7268                         }
7269
7270                         // The following DoResolve/DoResolveLValue will do the definite assignment
7271                         // check.
7272
7273                         if (right_side != null)
7274                                 return member_lookup.DoResolveLValue (ec, right_side);
7275                         else
7276                                 return member_lookup.DoResolve (ec);
7277                 }
7278
7279                 public override Expression DoResolve (EmitContext ec)
7280                 {
7281                         return DoResolve (ec, null);
7282                 }
7283
7284                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7285                 {
7286                         return DoResolve (ec, right_side);
7287                 }
7288
7289                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
7290                 {
7291                         return ResolveNamespaceOrType (ec, silent);
7292                 }
7293
7294                 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
7295                 {
7296                         FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
7297
7298                         if (new_expr == null)
7299                                 return null;
7300
7301                         if (new_expr is Namespace) {
7302                                 Namespace ns = (Namespace) new_expr;
7303                                 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
7304 #if GMCS_SOURCE
7305                                 if ((retval != null) && (args != null))
7306                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
7307 #endif
7308                                 if (!silent && retval == null)
7309                                         ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
7310                                 return retval;
7311                         }
7312
7313                         TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
7314                         if (tnew_expr == null)
7315                                 return null;
7316
7317                         Type expr_type = tnew_expr.Type;
7318
7319                         if (expr_type.IsPointer){
7320                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
7321                                        TypeManager.CSharpName (expr_type) + ")");
7322                                 return null;
7323                         }
7324
7325                         Expression member_lookup = MemberLookup (
7326                                 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7327                                 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
7328                         if (member_lookup == null) {
7329                                 if (silent)
7330                                         return null;
7331
7332                                 member_lookup = MemberLookup(
7333                                     rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
7334                                         MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
7335
7336                                 if (member_lookup == null) {
7337                                         Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
7338                                                       Identifier, new_expr.GetSignatureForError ());
7339                                 } else {
7340                                 // TODO: Report.SymbolRelatedToPreviousError
7341                                     member_lookup.Error_UnexpectedKind (null, "type", loc);
7342                                 }
7343                                 return null;
7344                         }
7345
7346                         TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
7347                         if (texpr == null)
7348                                 return null;
7349
7350 #if GMCS_SOURCE
7351                         TypeArguments the_args = args;
7352                         if (TypeManager.HasGenericArguments (expr_type)) {
7353                                 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
7354
7355                                 TypeArguments new_args = new TypeArguments (loc);
7356                                 foreach (Type decl in decl_args)
7357                                         new_args.Add (new TypeExpression (decl, loc));
7358
7359                                 if (args != null)
7360                                         new_args.Add (args);
7361
7362                                 the_args = new_args;
7363                         }
7364
7365                         if (the_args != null) {
7366                                 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
7367                                 return ctype.ResolveAsTypeStep (rc, false);
7368                         }
7369 #endif
7370
7371                         return texpr;
7372                 }
7373
7374                 public override void Emit (EmitContext ec)
7375                 {
7376                         throw new Exception ("Should not happen");
7377                 }
7378
7379                 public override string ToString ()
7380                 {
7381                         return expr + "." + MemberName.MakeName (Identifier, args);
7382                 }
7383
7384                 public override string GetSignatureForError ()
7385                 {
7386                         return expr.GetSignatureForError () + "." + Identifier;
7387                 }
7388         }
7389
7390         /// <summary>
7391         ///   Implements checked expressions
7392         /// </summary>
7393         public class CheckedExpr : Expression {
7394
7395                 public Expression Expr;
7396
7397                 public CheckedExpr (Expression e, Location l)
7398                 {
7399                         Expr = e;
7400                         loc = l;
7401                 }
7402
7403                 public override Expression DoResolve (EmitContext ec)
7404                 {
7405                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7406                                 Expr = Expr.Resolve (ec);
7407                         
7408                         if (Expr == null)
7409                                 return null;
7410
7411                         if (Expr is Constant)
7412                                 return Expr;
7413                         
7414                         eclass = Expr.eclass;
7415                         type = Expr.Type;
7416                         return this;
7417                 }
7418
7419                 public override void Emit (EmitContext ec)
7420                 {
7421                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7422                                 Expr.Emit (ec);
7423                 }
7424
7425                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7426                 {
7427                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7428                                 Expr.EmitBranchable (ec, target, onTrue);
7429                 }
7430         }
7431
7432         /// <summary>
7433         ///   Implements the unchecked expression
7434         /// </summary>
7435         public class UnCheckedExpr : Expression {
7436
7437                 public Expression Expr;
7438
7439                 public UnCheckedExpr (Expression e, Location l)
7440                 {
7441                         Expr = e;
7442                         loc = l;
7443                 }
7444
7445                 public override Expression DoResolve (EmitContext ec)
7446                 {
7447                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7448                                 Expr = Expr.Resolve (ec);
7449
7450                         if (Expr == null)
7451                                 return null;
7452
7453                         if (Expr is Constant)
7454                                 return Expr;
7455                         
7456                         eclass = Expr.eclass;
7457                         type = Expr.Type;
7458                         return this;
7459                 }
7460
7461                 public override void Emit (EmitContext ec)
7462                 {
7463                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7464                                 Expr.Emit (ec);
7465                 }
7466                 
7467                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7468                 {
7469                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7470                                 Expr.EmitBranchable (ec, target, onTrue);
7471                 }
7472         }
7473
7474         /// <summary>
7475         ///   An Element Access expression.
7476         ///
7477         ///   During semantic analysis these are transformed into 
7478         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7479         /// </summary>
7480         public class ElementAccess : Expression {
7481                 public ArrayList  Arguments;
7482                 public Expression Expr;
7483                 
7484                 public ElementAccess (Expression e, ArrayList e_list)
7485                 {
7486                         Expr = e;
7487
7488                         loc  = e.Location;
7489                         
7490                         if (e_list == null)
7491                                 return;
7492                         
7493                         Arguments = new ArrayList ();
7494                         foreach (Expression tmp in e_list)
7495                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7496                         
7497                 }
7498
7499                 bool CommonResolve (EmitContext ec)
7500                 {
7501                         Expr = Expr.Resolve (ec);
7502
7503                         if (Expr == null) 
7504                                 return false;
7505
7506                         if (Arguments == null)
7507                                 return false;
7508
7509                         foreach (Argument a in Arguments){
7510                                 if (!a.Resolve (ec, loc))
7511                                         return false;
7512                         }
7513
7514                         return true;
7515                 }
7516
7517                 Expression MakePointerAccess (EmitContext ec, Type t)
7518                 {
7519                         if (t == TypeManager.void_ptr_type){
7520                                 Error (242, "The array index operation is not valid on void pointers");
7521                                 return null;
7522                         }
7523                         if (Arguments.Count != 1){
7524                                 Error (196, "A pointer must be indexed by only one value");
7525                                 return null;
7526                         }
7527                         Expression p;
7528
7529                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7530                         if (p == null)
7531                                 return null;
7532                         return new Indirection (p, loc).Resolve (ec);
7533                 }
7534                 
7535                 public override Expression DoResolve (EmitContext ec)
7536                 {
7537                         if (!CommonResolve (ec))
7538                                 return null;
7539
7540                         //
7541                         // We perform some simple tests, and then to "split" the emit and store
7542                         // code we create an instance of a different class, and return that.
7543                         //
7544                         // I am experimenting with this pattern.
7545                         //
7546                         Type t = Expr.Type;
7547
7548                         if (t == TypeManager.array_type){
7549                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7550                                 return null;
7551                         }
7552                         
7553                         if (t.IsArray)
7554                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7555                         if (t.IsPointer)
7556                                 return MakePointerAccess (ec, Expr.Type);
7557
7558                         FieldExpr fe = Expr as FieldExpr;
7559                         if (fe != null) {
7560                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7561                                 if (ff != null) {
7562                                         return MakePointerAccess (ec, ff.ElementType);
7563                                 }
7564                         }
7565                         return (new IndexerAccess (this, loc)).Resolve (ec);
7566                 }
7567
7568                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7569                 {
7570                         if (!CommonResolve (ec))
7571                                 return null;
7572
7573                         Type t = Expr.Type;
7574                         if (t.IsArray)
7575                                 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7576
7577                         if (t.IsPointer)
7578                                 return MakePointerAccess (ec, Expr.Type);
7579
7580                         FieldExpr fe = Expr as FieldExpr;
7581                         if (fe != null) {
7582                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7583                                 if (ff != null) {
7584                                         if (!(fe.InstanceExpression is LocalVariableReference) && 
7585                                                 !(fe.InstanceExpression is This)) {
7586                                                 Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields");
7587                                                 return null;
7588                                         }
7589                                         if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
7590                                                 Error (1666, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
7591                                                 return null;
7592                                         }
7593                                         return MakePointerAccess (ec, ff.ElementType);
7594                                 }
7595                         }
7596                         return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7597                 }
7598                 
7599                 public override void Emit (EmitContext ec)
7600                 {
7601                         throw new Exception ("Should never be reached");
7602                 }
7603         }
7604
7605         /// <summary>
7606         ///   Implements array access 
7607         /// </summary>
7608         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7609                 //
7610                 // Points to our "data" repository
7611                 //
7612                 ElementAccess ea;
7613
7614                 LocalTemporary temp;
7615                 bool prepared;
7616                 
7617                 public ArrayAccess (ElementAccess ea_data, Location l)
7618                 {
7619                         ea = ea_data;
7620                         eclass = ExprClass.Variable;
7621                         loc = l;
7622                 }
7623
7624                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7625                 {
7626                         return DoResolve (ec);
7627                 }
7628
7629                 public override Expression DoResolve (EmitContext ec)
7630                 {
7631 #if false
7632                         ExprClass eclass = ea.Expr.eclass;
7633
7634                         // As long as the type is valid
7635                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7636                               eclass == ExprClass.Value)) {
7637                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7638                                 return null;
7639                         }
7640 #endif
7641
7642                         Type t = ea.Expr.Type;
7643                         if (t.GetArrayRank () != ea.Arguments.Count){
7644                                 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7645                                           ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7646                                 return null;
7647                         }
7648
7649                         type = TypeManager.GetElementType (t);
7650                         if (type.IsPointer && !ec.InUnsafe){
7651                                 UnsafeError (ea.Location);
7652                                 return null;
7653                         }
7654
7655                         foreach (Argument a in ea.Arguments){
7656                                 Type argtype = a.Type;
7657
7658                                 if (argtype == TypeManager.int32_type ||
7659                                     argtype == TypeManager.uint32_type ||
7660                                     argtype == TypeManager.int64_type ||
7661                                     argtype == TypeManager.uint64_type) {
7662                                         Constant c = a.Expr as Constant;
7663                                         if (c != null && c.IsNegative) {
7664                                                 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7665                                         }
7666                                         continue;
7667                                 }
7668
7669                                 //
7670                                 // Mhm.  This is strage, because the Argument.Type is not the same as
7671                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7672                                 //
7673                                 // Wonder if I will run into trouble for this.
7674                                 //
7675                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7676                                 if (a.Expr == null)
7677                                         return null;
7678                         }
7679                         
7680                         eclass = ExprClass.Variable;
7681
7682                         return this;
7683                 }
7684
7685                 /// <summary>
7686                 ///    Emits the right opcode to load an object of Type `t'
7687                 ///    from an array of T
7688                 /// </summary>
7689                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7690                 {
7691                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7692                                 ig.Emit (OpCodes.Ldelem_U1);
7693                         else if (type == TypeManager.sbyte_type)
7694                                 ig.Emit (OpCodes.Ldelem_I1);
7695                         else if (type == TypeManager.short_type)
7696                                 ig.Emit (OpCodes.Ldelem_I2);
7697                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7698                                 ig.Emit (OpCodes.Ldelem_U2);
7699                         else if (type == TypeManager.int32_type)
7700                                 ig.Emit (OpCodes.Ldelem_I4);
7701                         else if (type == TypeManager.uint32_type)
7702                                 ig.Emit (OpCodes.Ldelem_U4);
7703                         else if (type == TypeManager.uint64_type)
7704                                 ig.Emit (OpCodes.Ldelem_I8);
7705                         else if (type == TypeManager.int64_type)
7706                                 ig.Emit (OpCodes.Ldelem_I8);
7707                         else if (type == TypeManager.float_type)
7708                                 ig.Emit (OpCodes.Ldelem_R4);
7709                         else if (type == TypeManager.double_type)
7710                                 ig.Emit (OpCodes.Ldelem_R8);
7711                         else if (type == TypeManager.intptr_type)
7712                                 ig.Emit (OpCodes.Ldelem_I);
7713                         else if (TypeManager.IsEnumType (type)){
7714                                 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7715                         } else if (type.IsValueType){
7716                                 ig.Emit (OpCodes.Ldelema, type);
7717                                 ig.Emit (OpCodes.Ldobj, type);
7718 #if GMCS_SOURCE
7719                         } else if (type.IsGenericParameter) {
7720 #if MS_COMPATIBLE
7721                                 ig.Emit (OpCodes.Ldelem, type);
7722 #else
7723                                 ig.Emit (OpCodes.Ldelem_Any, type);
7724 #endif
7725 #endif
7726                         } else if (type.IsPointer)
7727                                 ig.Emit (OpCodes.Ldelem_I);
7728                         else
7729                                 ig.Emit (OpCodes.Ldelem_Ref);
7730                 }
7731
7732                 /// <summary>
7733                 ///    Returns the right opcode to store an object of Type `t'
7734                 ///    from an array of T.  
7735                 /// </summary>
7736                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7737                 {
7738                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
7739                         has_type_arg = false; is_stobj = false;
7740                         t = TypeManager.TypeToCoreType (t);
7741                         if (TypeManager.IsEnumType (t))
7742                                 t = TypeManager.EnumToUnderlying (t);
7743                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7744                             t == TypeManager.bool_type)
7745                                 return OpCodes.Stelem_I1;
7746                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7747                                  t == TypeManager.char_type)
7748                                 return OpCodes.Stelem_I2;
7749                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7750                                 return OpCodes.Stelem_I4;
7751                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7752                                 return OpCodes.Stelem_I8;
7753                         else if (t == TypeManager.float_type)
7754                                 return OpCodes.Stelem_R4;
7755                         else if (t == TypeManager.double_type)
7756                                 return OpCodes.Stelem_R8;
7757                         else if (t == TypeManager.intptr_type) {
7758                                 has_type_arg = true;
7759                                 is_stobj = true;
7760                                 return OpCodes.Stobj;
7761                         } else if (t.IsValueType) {
7762                                 has_type_arg = true;
7763                                 is_stobj = true;
7764                                 return OpCodes.Stobj;
7765 #if GMCS_SOURCE
7766                         } else if (t.IsGenericParameter) {
7767                                 has_type_arg = true;
7768 #if MS_COMPATIBLE
7769                                 return OpCodes.Stelem;
7770 #else
7771                                 return OpCodes.Stelem_Any;
7772 #endif
7773 #endif
7774
7775                         } else if (t.IsPointer)
7776                                 return OpCodes.Stelem_I;
7777                         else
7778                                 return OpCodes.Stelem_Ref;
7779                 }
7780
7781                 MethodInfo FetchGetMethod ()
7782                 {
7783                         ModuleBuilder mb = CodeGen.Module.Builder;
7784                         int arg_count = ea.Arguments.Count;
7785                         Type [] args = new Type [arg_count];
7786                         MethodInfo get;
7787                         
7788                         for (int i = 0; i < arg_count; i++){
7789                                 //args [i++] = a.Type;
7790                                 args [i] = TypeManager.int32_type;
7791                         }
7792                         
7793                         get = mb.GetArrayMethod (
7794                                 ea.Expr.Type, "Get",
7795                                 CallingConventions.HasThis |
7796                                 CallingConventions.Standard,
7797                                 type, args);
7798                         return get;
7799                 }
7800                                 
7801
7802                 MethodInfo FetchAddressMethod ()
7803                 {
7804                         ModuleBuilder mb = CodeGen.Module.Builder;
7805                         int arg_count = ea.Arguments.Count;
7806                         Type [] args = new Type [arg_count];
7807                         MethodInfo address;
7808                         Type ret_type;
7809                         
7810                         ret_type = TypeManager.GetReferenceType (type);
7811                         
7812                         for (int i = 0; i < arg_count; i++){
7813                                 //args [i++] = a.Type;
7814                                 args [i] = TypeManager.int32_type;
7815                         }
7816                         
7817                         address = mb.GetArrayMethod (
7818                                 ea.Expr.Type, "Address",
7819                                 CallingConventions.HasThis |
7820                                 CallingConventions.Standard,
7821                                 ret_type, args);
7822
7823                         return address;
7824                 }
7825
7826                 //
7827                 // Load the array arguments into the stack.
7828                 //
7829                 // If we have been requested to cache the values (cached_locations array
7830                 // initialized), then load the arguments the first time and store them
7831                 // in locals.  otherwise load from local variables.
7832                 //
7833                 void LoadArrayAndArguments (EmitContext ec)
7834                 {
7835                         ILGenerator ig = ec.ig;
7836                         
7837                         ea.Expr.Emit (ec);
7838                         foreach (Argument a in ea.Arguments){
7839                                 Type argtype = a.Expr.Type;
7840                                 
7841                                 a.Expr.Emit (ec);
7842                                 
7843                                 if (argtype == TypeManager.int64_type)
7844                                         ig.Emit (OpCodes.Conv_Ovf_I);
7845                                 else if (argtype == TypeManager.uint64_type)
7846                                         ig.Emit (OpCodes.Conv_Ovf_I_Un);
7847                         }
7848                 }
7849
7850                 public void Emit (EmitContext ec, bool leave_copy)
7851                 {
7852                         int rank = ea.Expr.Type.GetArrayRank ();
7853                         ILGenerator ig = ec.ig;
7854
7855                         if (!prepared) {
7856                                 LoadArrayAndArguments (ec);
7857                                 
7858                                 if (rank == 1)
7859                                         EmitLoadOpcode (ig, type);
7860                                 else {
7861                                         MethodInfo method;
7862                                         
7863                                         method = FetchGetMethod ();
7864                                         ig.Emit (OpCodes.Call, method);
7865                                 }
7866                         } else
7867                                 LoadFromPtr (ec.ig, this.type);
7868                         
7869                         if (leave_copy) {
7870                                 ec.ig.Emit (OpCodes.Dup);
7871                                 temp = new LocalTemporary (this.type);
7872                                 temp.Store (ec);
7873                         }
7874                 }
7875                 
7876                 public override void Emit (EmitContext ec)
7877                 {
7878                         Emit (ec, false);
7879                 }
7880
7881                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7882                 {
7883                         int rank = ea.Expr.Type.GetArrayRank ();
7884                         ILGenerator ig = ec.ig;
7885                         Type t = source.Type;
7886                         prepared = prepare_for_load;
7887
7888                         if (prepare_for_load) {
7889                                 AddressOf (ec, AddressOp.LoadStore);
7890                                 ec.ig.Emit (OpCodes.Dup);
7891                                 source.Emit (ec);
7892                                 if (leave_copy) {
7893                                         ec.ig.Emit (OpCodes.Dup);
7894                                         temp = new LocalTemporary (this.type);
7895                                         temp.Store (ec);
7896                                 }
7897                                 StoreFromPtr (ec.ig, t);
7898                                 
7899                                 if (temp != null) {
7900                                         temp.Emit (ec);
7901                                         temp.Release (ec);
7902                                 }
7903                                 
7904                                 return;
7905                         }
7906                         
7907                         LoadArrayAndArguments (ec);
7908
7909                         if (rank == 1) {
7910                                 bool is_stobj, has_type_arg;
7911                                 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7912                                 //
7913                                 // The stobj opcode used by value types will need
7914                                 // an address on the stack, not really an array/array
7915                                 // pair
7916                                 //
7917                                 if (is_stobj)
7918                                         ig.Emit (OpCodes.Ldelema, t);
7919                                 
7920                                 source.Emit (ec);
7921                                 if (leave_copy) {
7922                                         ec.ig.Emit (OpCodes.Dup);
7923                                         temp = new LocalTemporary (this.type);
7924                                         temp.Store (ec);
7925                                 }
7926                                 
7927                                 if (is_stobj)
7928                                         ig.Emit (OpCodes.Stobj, t);
7929                                 else if (has_type_arg)
7930                                         ig.Emit (op, t);
7931                                 else
7932                                         ig.Emit (op);
7933                         } else {
7934                                 ModuleBuilder mb = CodeGen.Module.Builder;
7935                                 int arg_count = ea.Arguments.Count;
7936                                 Type [] args = new Type [arg_count + 1];
7937                                 MethodInfo set;
7938                                 
7939                                 source.Emit (ec);
7940                                 if (leave_copy) {
7941                                         ec.ig.Emit (OpCodes.Dup);
7942                                         temp = new LocalTemporary (this.type);
7943                                         temp.Store (ec);
7944                                 }
7945                                 
7946                                 for (int i = 0; i < arg_count; i++){
7947                                         //args [i++] = a.Type;
7948                                         args [i] = TypeManager.int32_type;
7949                                 }
7950
7951                                 args [arg_count] = type;
7952                                 
7953                                 set = mb.GetArrayMethod (
7954                                         ea.Expr.Type, "Set",
7955                                         CallingConventions.HasThis |
7956                                         CallingConventions.Standard,
7957                                         TypeManager.void_type, args);
7958                                 
7959                                 ig.Emit (OpCodes.Call, set);
7960                         }
7961                         
7962                         if (temp != null) {
7963                                 temp.Emit (ec);
7964                                 temp.Release (ec);
7965                         }
7966                 }
7967
7968                 public void AddressOf (EmitContext ec, AddressOp mode)
7969                 {
7970                         int rank = ea.Expr.Type.GetArrayRank ();
7971                         ILGenerator ig = ec.ig;
7972
7973                         LoadArrayAndArguments (ec);
7974
7975                         if (rank == 1){
7976                                 ig.Emit (OpCodes.Ldelema, type);
7977                         } else {
7978                                 MethodInfo address = FetchAddressMethod ();
7979                                 ig.Emit (OpCodes.Call, address);
7980                         }
7981                 }
7982
7983                 public void EmitGetLength (EmitContext ec, int dim)
7984                 {
7985                         int rank = ea.Expr.Type.GetArrayRank ();
7986                         ILGenerator ig = ec.ig;
7987
7988                         ea.Expr.Emit (ec);
7989                         if (rank == 1) {
7990                                 ig.Emit (OpCodes.Ldlen);
7991                                 ig.Emit (OpCodes.Conv_I4);
7992                         } else {
7993                                 IntLiteral.EmitInt (ig, dim);
7994                                 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7995                         }
7996                 }
7997         }
7998         
7999         class Indexers {
8000                 // note that the ArrayList itself in mutable.  We just can't assign to 'Properties' again.
8001                 public readonly ArrayList Properties;
8002                 static Indexers empty;
8003
8004                 public struct Indexer {
8005                         public readonly PropertyInfo PropertyInfo;
8006                         public readonly MethodInfo Getter, Setter;
8007
8008                         public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
8009                         {
8010                                 this.PropertyInfo = property_info;
8011                                 this.Getter = get;
8012                                 this.Setter = set;
8013                         }
8014                 }
8015
8016                 static Indexers ()
8017                 {
8018                         empty = new Indexers (null);
8019                 }
8020
8021                 Indexers (ArrayList array)
8022                 {
8023                         Properties = array;
8024                 }
8025
8026                 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
8027                 {
8028                         bool dummy;
8029                         if (mi == null)
8030                                 return;
8031                         foreach (PropertyInfo property in mi){
8032                                 MethodInfo get, set;
8033                                 
8034                                 get = property.GetGetMethod (true);
8035                                 set = property.GetSetMethod (true);
8036                                 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
8037                                         get = null;
8038                                 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
8039                                         set = null;
8040                                 if (get != null || set != null) {
8041                                         if (ix == empty)
8042                                                 ix = new Indexers (new ArrayList ());
8043                                         ix.Properties.Add (new Indexer (property, get, set));
8044                                 }
8045                         }
8046                 }
8047
8048                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
8049                 {
8050                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
8051
8052                         return TypeManager.MemberLookup (
8053                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
8054                                 BindingFlags.Public | BindingFlags.Instance |
8055                                 BindingFlags.DeclaredOnly, p_name, null);
8056                 }
8057                 
8058                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type) 
8059                 {
8060                         Indexers ix = empty;
8061
8062 #if GMCS_SOURCE
8063                         if (lookup_type.IsGenericParameter) {
8064                                 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
8065                                 if (gc == null)
8066                                         return empty;
8067
8068                                 if (gc.HasClassConstraint)
8069                                         Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
8070
8071                                 Type[] ifaces = gc.InterfaceConstraints;
8072                                 foreach (Type itype in ifaces)
8073                                         Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8074
8075                                 return ix;
8076                         }
8077 #endif
8078
8079                         Type copy = lookup_type;
8080                         while (copy != TypeManager.object_type && copy != null){
8081                                 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
8082                                 copy = copy.BaseType;
8083                         }
8084
8085                         if (lookup_type.IsInterface) {
8086                                 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
8087                                 if (ifaces != null) {
8088                                         foreach (Type itype in ifaces)
8089                                                 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
8090                                 }
8091                         }
8092
8093                         return ix;
8094                 }
8095         }
8096
8097         /// <summary>
8098         ///   Expressions that represent an indexer call.
8099         /// </summary>
8100         public class IndexerAccess : Expression, IAssignMethod {
8101                 //
8102                 // Points to our "data" repository
8103                 //
8104                 MethodInfo get, set;
8105                 ArrayList set_arguments;
8106                 bool is_base_indexer;
8107
8108                 protected Type indexer_type;
8109                 protected Type current_type;
8110                 protected Expression instance_expr;
8111                 protected ArrayList arguments;
8112                 
8113                 public IndexerAccess (ElementAccess ea, Location loc)
8114                         : this (ea.Expr, false, loc)
8115                 {
8116                         this.arguments = ea.Arguments;
8117                 }
8118
8119                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
8120                                          Location loc)
8121                 {
8122                         this.instance_expr = instance_expr;
8123                         this.is_base_indexer = is_base_indexer;
8124                         this.eclass = ExprClass.Value;
8125                         this.loc = loc;
8126                 }
8127
8128                 protected virtual bool CommonResolve (EmitContext ec)
8129                 {
8130                         indexer_type = instance_expr.Type;
8131                         current_type = ec.ContainerType;
8132
8133                         return true;
8134                 }
8135
8136                 public override Expression DoResolve (EmitContext ec)
8137                 {
8138                         if (!CommonResolve (ec))
8139                                 return null;
8140
8141                         //
8142                         // Step 1: Query for all `Item' *properties*.  Notice
8143                         // that the actual methods are pointed from here.
8144                         //
8145                         // This is a group of properties, piles of them.  
8146
8147                         ArrayList AllGetters = null;
8148
8149                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8150                         if (ilist.Properties != null) {
8151                                 AllGetters = new ArrayList(ilist.Properties.Count);
8152                                 foreach (Indexers.Indexer ix in ilist.Properties) {
8153                                         if (ix.Getter != null)
8154                                                 AllGetters.Add (ix.Getter);
8155                                 }
8156                         }
8157
8158                         if (AllGetters == null) {
8159                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8160                                         TypeManager.CSharpName (indexer_type));
8161                                 return null;
8162                         }
8163
8164                         if (AllGetters.Count == 0) {
8165                                 // FIXME: we cannot simply select first one as the error message is missleading when
8166                                 // multiple indexers exist
8167                                 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
8168                                 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
8169                                         TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
8170                                 return null;
8171                         }
8172
8173                         get = (MethodInfo)Invocation.OverloadResolve (ec, new MethodGroupExpr (AllGetters, loc),
8174                                         arguments, false, loc);
8175
8176                         if (get == null) {
8177                                 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
8178                                 return null;
8179                         }
8180
8181                         //
8182                         // Only base will allow this invocation to happen.
8183                         //
8184                         if (get.IsAbstract && this is BaseIndexerAccess){
8185                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
8186                                 return null;
8187                         }
8188
8189                         type = get.ReturnType;
8190                         if (type.IsPointer && !ec.InUnsafe){
8191                                 UnsafeError (loc);
8192                                 return null;
8193                         }
8194
8195                         instance_expr.CheckMarshalByRefAccess ();
8196                         
8197                         eclass = ExprClass.IndexerAccess;
8198                         return this;
8199                 }
8200
8201                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8202                 {
8203                         if (right_side == EmptyExpression.OutAccess) {
8204                                 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
8205                                               GetSignatureForError ());
8206                                 return null;
8207                         }
8208
8209                         // if the indexer returns a value type, and we try to set a field in it
8210                         if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
8211                                 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
8212                                               GetSignatureForError ());
8213                                 return null;
8214                         }
8215
8216                         ArrayList AllSetters = new ArrayList();
8217                         if (!CommonResolve (ec))
8218                                 return null;
8219
8220                         bool found_any = false, found_any_setters = false;
8221
8222                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
8223                         if (ilist.Properties != null) {
8224                                 found_any = true;
8225                                 foreach (Indexers.Indexer ix in ilist.Properties) {
8226                                         if (ix.Setter != null)
8227                                                 AllSetters.Add (ix.Setter);
8228                                 }
8229                         }
8230                         if (AllSetters.Count > 0) {
8231                                 found_any_setters = true;
8232                                 set_arguments = (ArrayList) arguments.Clone ();
8233                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
8234                                 set = (MethodInfo) Invocation.OverloadResolve (
8235                                         ec, new MethodGroupExpr (AllSetters, loc),
8236                                         set_arguments, false, loc);
8237                         }
8238
8239                         if (!found_any) {
8240                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
8241                                               TypeManager.CSharpName (indexer_type));
8242                                 return null;
8243                         }
8244
8245                         if (!found_any_setters) {
8246                                 Error (154, "indexer can not be used in this context, because " +
8247                                        "it lacks a `set' accessor");
8248                                 return null;
8249                         }
8250
8251                         if (set == null) {
8252                                 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
8253                                 return null;
8254                         }
8255
8256                         //
8257                         // Only base will allow this invocation to happen.
8258                         //
8259                         if (set.IsAbstract && this is BaseIndexerAccess){
8260                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
8261                                 return null;
8262                         }
8263
8264                         //
8265                         // Now look for the actual match in the list of indexers to set our "return" type
8266                         //
8267                         type = TypeManager.void_type;   // default value
8268                         foreach (Indexers.Indexer ix in ilist.Properties){
8269                                 if (ix.Setter == set){
8270                                         type = ix.PropertyInfo.PropertyType;
8271                                         break;
8272                                 }
8273                         }
8274
8275                         instance_expr.CheckMarshalByRefAccess ();
8276
8277                         eclass = ExprClass.IndexerAccess;
8278                         return this;
8279                 }
8280                 
8281                 bool prepared = false;
8282                 LocalTemporary temp;
8283                 
8284                 public void Emit (EmitContext ec, bool leave_copy)
8285                 {
8286                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
8287                         if (leave_copy) {
8288                                 ec.ig.Emit (OpCodes.Dup);
8289                                 temp = new LocalTemporary (Type);
8290                                 temp.Store (ec);
8291                         }
8292                 }
8293                 
8294                 //
8295                 // source is ignored, because we already have a copy of it from the
8296                 // LValue resolution and we have already constructed a pre-cached
8297                 // version of the arguments (ea.set_arguments);
8298                 //
8299                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
8300                 {
8301                         prepared = prepare_for_load;
8302                         Argument a = (Argument) set_arguments [set_arguments.Count - 1];
8303                         
8304                         if (prepared) {
8305                                 source.Emit (ec);
8306                                 if (leave_copy) {
8307                                         ec.ig.Emit (OpCodes.Dup);
8308                                         temp = new LocalTemporary (Type);
8309                                         temp.Store (ec);
8310                                 }
8311                         } else if (leave_copy) {
8312                                 temp = new LocalTemporary (Type);
8313                                 source.Emit (ec);
8314                                 temp.Store (ec);
8315                                 a.Expr = temp;
8316                         }
8317                         
8318                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
8319                         
8320                         if (temp != null) {
8321                                 temp.Emit (ec);
8322                                 temp.Release (ec);
8323                         }
8324                 }
8325                 
8326                 
8327                 public override void Emit (EmitContext ec)
8328                 {
8329                         Emit (ec, false);
8330                 }
8331
8332                 public override string GetSignatureForError ()
8333                 {
8334                         // FIXME: print the argument list of the indexer
8335                         return instance_expr.GetSignatureForError () + ".this[...]";
8336                 }
8337         }
8338
8339         /// <summary>
8340         ///   The base operator for method names
8341         /// </summary>
8342         public class BaseAccess : Expression {
8343                 public readonly string Identifier;
8344
8345                 public BaseAccess (string member, Location l)
8346                 {
8347                         this.Identifier = member;
8348                         loc = l;
8349                 }
8350
8351                 public BaseAccess (string member, TypeArguments args, Location l)
8352                         : this (member, l)
8353                 {
8354                         this.args = args;
8355                 }
8356
8357                 TypeArguments args;
8358
8359                 public override Expression DoResolve (EmitContext ec)
8360                 {
8361                         Expression c = CommonResolve (ec);
8362
8363                         if (c == null)
8364                                 return null;
8365
8366                         //
8367                         // MethodGroups use this opportunity to flag an error on lacking ()
8368                         //
8369                         if (!(c is MethodGroupExpr))
8370                                 return c.Resolve (ec);
8371                         return c;
8372                 }
8373
8374                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8375                 {
8376                         Expression c = CommonResolve (ec);
8377
8378                         if (c == null)
8379                                 return null;
8380
8381                         //
8382                         // MethodGroups use this opportunity to flag an error on lacking ()
8383                         //
8384                         if (! (c is MethodGroupExpr))
8385                                 return c.DoResolveLValue (ec, right_side);
8386
8387                         return c;
8388                 }
8389
8390                 Expression CommonResolve (EmitContext ec)
8391                 {
8392                         Expression member_lookup;
8393                         Type current_type = ec.ContainerType;
8394                         Type base_type = current_type.BaseType;
8395
8396                         if (ec.IsStatic){
8397                                 Error (1511, "Keyword `base' is not available in a static method");
8398                                 return null;
8399                         }
8400
8401                         if (ec.IsFieldInitializer){
8402                                 Error (1512, "Keyword `base' is not available in the current context");
8403                                 return null;
8404                         }
8405                         
8406                         member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8407                                                       AllMemberTypes, AllBindingFlags, loc);
8408                         if (member_lookup == null) {
8409                                 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8410                                 return null;
8411                         }
8412
8413                         Expression left;
8414                         
8415                         if (ec.IsStatic)
8416                                 left = new TypeExpression (base_type, loc);
8417                         else
8418                                 left = ec.GetThis (loc);
8419
8420                         MemberExpr me = (MemberExpr) member_lookup;
8421                         
8422                         Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8423
8424                         if (e is PropertyExpr) {
8425                                 PropertyExpr pe = (PropertyExpr) e;
8426
8427                                 pe.IsBase = true;
8428                         }
8429
8430                         MethodGroupExpr mg = e as MethodGroupExpr;
8431                         if (mg != null)
8432                                 mg.IsBase = true;
8433
8434                         if (args != null) {
8435                                 if (mg != null)
8436                                         return mg.ResolveGeneric (ec, args);
8437
8438                                 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8439                                               Identifier);
8440                                 return null;
8441                         }
8442
8443                         return e;
8444                 }
8445
8446                 public override void Emit (EmitContext ec)
8447                 {
8448                         throw new Exception ("Should never be called"); 
8449                 }
8450         }
8451
8452         /// <summary>
8453         ///   The base indexer operator
8454         /// </summary>
8455         public class BaseIndexerAccess : IndexerAccess {
8456                 public BaseIndexerAccess (ArrayList args, Location loc)
8457                         : base (null, true, loc)
8458                 {
8459                         arguments = new ArrayList ();
8460                         foreach (Expression tmp in args)
8461                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8462                 }
8463
8464                 protected override bool CommonResolve (EmitContext ec)
8465                 {
8466                         instance_expr = ec.GetThis (loc);
8467
8468                         current_type = ec.ContainerType.BaseType;
8469                         indexer_type = current_type;
8470
8471                         foreach (Argument a in arguments){
8472                                 if (!a.Resolve (ec, loc))
8473                                         return false;
8474                         }
8475
8476                         return true;
8477                 }
8478         }
8479         
8480         /// <summary>
8481         ///   This class exists solely to pass the Type around and to be a dummy
8482         ///   that can be passed to the conversion functions (this is used by
8483         ///   foreach implementation to typecast the object return value from
8484         ///   get_Current into the proper type.  All code has been generated and
8485         ///   we only care about the side effect conversions to be performed
8486         ///
8487         ///   This is also now used as a placeholder where a no-action expression
8488         ///   is needed (the `New' class).
8489         /// </summary>
8490         public class EmptyExpression : Expression {
8491                 public static readonly EmptyExpression Null = new EmptyExpression ();
8492
8493                 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8494                 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8495                 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8496
8497                 static EmptyExpression temp = new EmptyExpression ();
8498                 public static EmptyExpression Grab ()
8499                 {
8500                         EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8501                         temp = null;
8502                         return retval;
8503                 }
8504
8505                 public static void Release (EmptyExpression e)
8506                 {
8507                         temp = e;
8508                 }
8509
8510                 // TODO: should be protected
8511                 public EmptyExpression ()
8512                 {
8513                         type = TypeManager.object_type;
8514                         eclass = ExprClass.Value;
8515                         loc = Location.Null;
8516                 }
8517
8518                 public EmptyExpression (Type t)
8519                 {
8520                         type = t;
8521                         eclass = ExprClass.Value;
8522                         loc = Location.Null;
8523                 }
8524                 
8525                 public override Expression DoResolve (EmitContext ec)
8526                 {
8527                         return this;
8528                 }
8529
8530                 public override void Emit (EmitContext ec)
8531                 {
8532                         // nothing, as we only exist to not do anything.
8533                 }
8534
8535                 //
8536                 // This is just because we might want to reuse this bad boy
8537                 // instead of creating gazillions of EmptyExpressions.
8538                 // (CanImplicitConversion uses it)
8539                 //
8540                 public void SetType (Type t)
8541                 {
8542                         type = t;
8543                 }
8544         }
8545
8546         public class UserCast : Expression {
8547                 MethodBase method;
8548                 Expression source;
8549                 
8550                 public UserCast (MethodInfo method, Expression source, Location l)
8551                 {
8552                         this.method = method;
8553                         this.source = source;
8554                         type = method.ReturnType;
8555                         eclass = ExprClass.Value;
8556                         loc = l;
8557                 }
8558
8559                 public Expression Source {
8560                         get {
8561                                 return source;
8562                         }
8563                 }
8564                         
8565                 public override Expression DoResolve (EmitContext ec)
8566                 {
8567                         //
8568                         // We are born fully resolved
8569                         //
8570                         return this;
8571                 }
8572
8573                 public override void Emit (EmitContext ec)
8574                 {
8575                         ILGenerator ig = ec.ig;
8576
8577                         source.Emit (ec);
8578                         
8579                         if (method is MethodInfo)
8580                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8581                         else
8582                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8583
8584                 }
8585         }
8586
8587         // <summary>
8588         //   This class is used to "construct" the type during a typecast
8589         //   operation.  Since the Type.GetType class in .NET can parse
8590         //   the type specification, we just use this to construct the type
8591         //   one bit at a time.
8592         // </summary>
8593         public class ComposedCast : TypeExpr {
8594                 Expression left;
8595                 string dim;
8596                 
8597                 public ComposedCast (Expression left, string dim)
8598                         : this (left, dim, left.Location)
8599                 {
8600                 }
8601
8602                 public ComposedCast (Expression left, string dim, Location l)
8603                 {
8604                         this.left = left;
8605                         this.dim = dim;
8606                         loc = l;
8607                 }
8608
8609 #if GMCS_SOURCE
8610                 public Expression RemoveNullable ()
8611                 {
8612                         if (dim.EndsWith ("?")) {
8613                                 dim = dim.Substring (0, dim.Length - 1);
8614                                 if (dim == "")
8615                                         return left;
8616                         }
8617
8618                         return this;
8619                 }
8620 #endif
8621
8622                 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8623                 {
8624                         TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8625                         if (lexpr == null)
8626                                 return null;
8627
8628                         Type ltype = lexpr.Type;
8629                         if ((ltype == TypeManager.void_type) && (dim != "*")) {
8630                                 Error_VoidInvalidInTheContext (loc);
8631                                 return null;
8632                         }
8633
8634 #if GMCS_SOURCE
8635                         if ((dim.Length > 0) && (dim [0] == '?')) {
8636                                 TypeExpr nullable = new NullableType (left, loc);
8637                                 if (dim.Length > 1)
8638                                         nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8639                                 return nullable.ResolveAsTypeTerminal (ec, false);
8640                         }
8641 #endif
8642
8643                         if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8644                                 return null;
8645
8646                         if (dim != "" && dim [0] == '[' &&
8647                             (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8648                                 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8649                                 return null;
8650                         }
8651
8652                         if (dim != "")
8653                                 type = TypeManager.GetConstructedType (ltype, dim);
8654                         else
8655                                 type = ltype;
8656
8657                         if (type == null)
8658                                 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8659
8660                         if (type.IsPointer && !ec.IsInUnsafeScope){
8661                                 UnsafeError (loc);
8662                                 return null;
8663                         }
8664
8665                         eclass = ExprClass.Type;
8666                         return this;
8667                 }
8668
8669                 public override string Name {
8670                         get { return left + dim; }
8671                 }
8672
8673                 public override string FullName {
8674                         get { return type.FullName; }
8675                 }
8676
8677                 public override string GetSignatureForError ()
8678                 {
8679                         return left.GetSignatureForError () + dim;
8680                 }
8681         }
8682
8683         public class FixedBufferPtr : Expression {
8684                 Expression array;
8685
8686                 public FixedBufferPtr (Expression array, Type array_type, Location l)
8687                 {
8688                         this.array = array;
8689                         this.loc = l;
8690
8691                         type = TypeManager.GetPointerType (array_type);
8692                         eclass = ExprClass.Value;
8693                 }
8694
8695                 public override void Emit(EmitContext ec)
8696                 {
8697                         array.Emit (ec);
8698                 }
8699
8700                 public override Expression DoResolve (EmitContext ec)
8701                 {
8702                         //
8703                         // We are born fully resolved
8704                         //
8705                         return this;
8706                 }
8707         }
8708
8709
8710         //
8711         // This class is used to represent the address of an array, used
8712         // only by the Fixed statement, this generates "&a [0]" construct
8713         // for fixed (char *pa = a)
8714         //
8715         public class ArrayPtr : FixedBufferPtr {
8716                 Type array_type;
8717                 
8718                 public ArrayPtr (Expression array, Type array_type, Location l):
8719                         base (array, array_type, l)
8720                 {
8721                         this.array_type = array_type;
8722                 }
8723
8724                 public override void Emit (EmitContext ec)
8725                 {
8726                         base.Emit (ec);
8727                         
8728                         ILGenerator ig = ec.ig;
8729                         IntLiteral.EmitInt (ig, 0);
8730                         ig.Emit (OpCodes.Ldelema, array_type);
8731                 }
8732         }
8733
8734         //
8735         // Used by the fixed statement
8736         //
8737         public class StringPtr : Expression {
8738                 LocalBuilder b;
8739                 
8740                 public StringPtr (LocalBuilder b, Location l)
8741                 {
8742                         this.b = b;
8743                         eclass = ExprClass.Value;
8744                         type = TypeManager.char_ptr_type;
8745                         loc = l;
8746                 }
8747
8748                 public override Expression DoResolve (EmitContext ec)
8749                 {
8750                         // This should never be invoked, we are born in fully
8751                         // initialized state.
8752
8753                         return this;
8754                 }
8755
8756                 public override void Emit (EmitContext ec)
8757                 {
8758                         ILGenerator ig = ec.ig;
8759
8760                         ig.Emit (OpCodes.Ldloc, b);
8761                         ig.Emit (OpCodes.Conv_I);
8762                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8763                         ig.Emit (OpCodes.Add);
8764                 }
8765         }
8766         
8767         //
8768         // Implements the `stackalloc' keyword
8769         //
8770         public class StackAlloc : Expression {
8771                 Type otype;
8772                 Expression t;
8773                 Expression count;
8774                 
8775                 public StackAlloc (Expression type, Expression count, Location l)
8776                 {
8777                         t = type;
8778                         this.count = count;
8779                         loc = l;
8780                 }
8781
8782                 public override Expression DoResolve (EmitContext ec)
8783                 {
8784                         count = count.Resolve (ec);
8785                         if (count == null)
8786                                 return null;
8787                         
8788                         if (count.Type != TypeManager.int32_type){
8789                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8790                                 if (count == null)
8791                                         return null;
8792                         }
8793
8794                         Constant c = count as Constant;
8795                         if (c != null && c.IsNegative) {
8796                                 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8797                                 return null;
8798                         }
8799
8800                         if (ec.InCatch || ec.InFinally) {
8801                                 Error (255, "Cannot use stackalloc in finally or catch");
8802                                 return null;
8803                         }
8804
8805                         TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8806                         if (texpr == null)
8807                                 return null;
8808
8809                         otype = texpr.Type;
8810
8811                         if (!TypeManager.VerifyUnManaged (otype, loc))
8812                                 return null;
8813
8814                         type = TypeManager.GetPointerType (otype);
8815                         eclass = ExprClass.Value;
8816
8817                         return this;
8818                 }
8819
8820                 public override void Emit (EmitContext ec)
8821                 {
8822                         int size = GetTypeSize (otype);
8823                         ILGenerator ig = ec.ig;
8824                                 
8825                         if (size == 0)
8826                                 ig.Emit (OpCodes.Sizeof, otype);
8827                         else
8828                                 IntConstant.EmitInt (ig, size);
8829                         count.Emit (ec);
8830                         ig.Emit (OpCodes.Mul);
8831                         ig.Emit (OpCodes.Localloc);
8832                 }
8833         }
8834 }