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