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