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