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