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