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