* Makefile: integrate Mono.Mozilla wrapper in the build.
[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.Type == TypeManager.null_type){
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                         //
2985                         // Multiple (3+) concatenation are resolved as multiple StringConcat instances
2986                         //
2987                         StringConcat concat_oper = operand as StringConcat;
2988                         if (concat_oper != null) {
2989                                 operands.AddRange (concat_oper.operands);
2990                                 return;
2991                         }                       
2992                         
2993                         //
2994                         // Conversion to object
2995                         //
2996                         if (operand.Type != TypeManager.string_type) {
2997                                 Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
2998                                 
2999                                 if (no == null) {
3000                                         Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
3001                                         invalid = true;
3002                                 }
3003                                 operand = no;
3004                         }
3005                         
3006                         operands.Add (operand);
3007                 }
3008
3009                 public override void Emit (EmitContext ec)
3010                 {
3011                         MethodInfo concat_method = null;
3012                         
3013                         //
3014                         // Do conversion to arguments; check for strings only
3015                         //
3016                         
3017                         // This can get called multiple times, so we have to deal with that.
3018                         if (!emit_conv_done) {
3019                                 emit_conv_done = true;
3020                                 for (int i = 0; i < operands.Count; i ++) {
3021                                         Expression e = (Expression) operands [i];
3022                                         is_strings_only &= e.Type == TypeManager.string_type;
3023                                 }
3024                                 
3025                                 for (int i = 0; i < operands.Count; i ++) {
3026                                         Expression e = (Expression) operands [i];
3027                                         
3028                                         if (! is_strings_only && e.Type == TypeManager.string_type) {
3029                                                 // need to make sure this is an object, because the EmitParams
3030                                                 // method might look at the type of this expression, see it is a
3031                                                 // string and emit a string [] when we want an object [];
3032                                                 
3033                                                 e = new EmptyCast (e, TypeManager.object_type);
3034                                         }
3035                                         operands [i] = new Argument (e, Argument.AType.Expression);
3036                                 }
3037                         }
3038                         
3039                         //
3040                         // Find the right method
3041                         //
3042                         switch (operands.Count) {
3043                         case 1:
3044                                 //
3045                                 // This should not be possible, because simple constant folding
3046                                 // is taken care of in the Binary code.
3047                                 //
3048                                 throw new Exception ("how did you get here?");
3049                         
3050                         case 2:
3051                                 concat_method = is_strings_only ? 
3052                                         TypeManager.string_concat_string_string :
3053                                         TypeManager.string_concat_object_object ;
3054                                 break;
3055                         case 3:
3056                                 concat_method = is_strings_only ? 
3057                                         TypeManager.string_concat_string_string_string :
3058                                         TypeManager.string_concat_object_object_object ;
3059                                 break;
3060                         case 4:
3061                                 //
3062                                 // There is not a 4 param overlaod for object (the one that there is
3063                                 // is actually a varargs methods, and is only in corlib because it was
3064                                 // introduced there before.).
3065                                 //
3066                                 if (!is_strings_only)
3067                                         goto default;
3068                                 
3069                                 concat_method = TypeManager.string_concat_string_string_string_string;
3070                                 break;
3071                         default:
3072                                 concat_method = is_strings_only ? 
3073                                         TypeManager.string_concat_string_dot_dot_dot :
3074                                         TypeManager.string_concat_object_dot_dot_dot ;
3075                                 break;
3076                         }
3077                         
3078                         Invocation.EmitArguments (ec, concat_method, operands, false, null);
3079                         ec.ig.Emit (OpCodes.Call, concat_method);
3080                 }
3081         }
3082
3083         //
3084         // Object created with +/= on delegates
3085         //
3086         public class BinaryDelegate : Expression {
3087                 MethodInfo method;
3088                 ArrayList  args;
3089
3090                 public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
3091                 {
3092                         method = mi;
3093                         this.args = args;
3094                         type = t;
3095                         eclass = ExprClass.Value;
3096                 }
3097
3098                 public override Expression DoResolve (EmitContext ec)
3099                 {
3100                         return this;
3101                 }
3102
3103                 public override void Emit (EmitContext ec)
3104                 {
3105                         ILGenerator ig = ec.ig;
3106                         
3107                         Invocation.EmitArguments (ec, method, args, false, null);
3108                         
3109                         ig.Emit (OpCodes.Call, (MethodInfo) method);
3110                         ig.Emit (OpCodes.Castclass, type);
3111                 }
3112
3113                 public Expression Right {
3114                         get {
3115                                 Argument arg = (Argument) args [1];
3116                                 return arg.Expr;
3117                         }
3118                 }
3119
3120                 public bool IsAddition {
3121                         get {
3122                                 return method == TypeManager.delegate_combine_delegate_delegate;
3123                         }
3124                 }
3125         }
3126         
3127         //
3128         // User-defined conditional logical operator
3129         public class ConditionalLogicalOperator : Expression {
3130                 Expression left, right;
3131                 bool is_and;
3132
3133                 public ConditionalLogicalOperator (bool is_and, Expression left, Expression right, Type t, Location loc)
3134                 {
3135                         type = t;
3136                         eclass = ExprClass.Value;
3137                         this.loc = loc;
3138                         this.left = left;
3139                         this.right = right;
3140                         this.is_and = is_and;
3141                 }
3142
3143                 protected void Error19 ()
3144                 {
3145                         Binary.Error_OperatorCannotBeApplied (loc, is_and ? "&&" : "||", left.GetSignatureForError (), right.GetSignatureForError ());
3146                 }
3147
3148                 protected void Error218 ()
3149                 {
3150                         Error (218, "The type ('" + TypeManager.CSharpName (type) + "') must contain " +
3151                                "declarations of operator true and operator false");
3152                 }
3153
3154                 Expression op_true, op_false, op;
3155                 LocalTemporary left_temp;
3156
3157                 public override Expression DoResolve (EmitContext ec)
3158                 {
3159                         MethodGroupExpr operator_group;
3160
3161                         operator_group = MethodLookup (ec.ContainerType, type, is_and ? "op_BitwiseAnd" : "op_BitwiseOr", loc) as MethodGroupExpr;
3162                         if (operator_group == null) {
3163                                 Error19 ();
3164                                 return null;
3165                         }
3166
3167                         left_temp = new LocalTemporary (type);
3168
3169                         ArrayList arguments = new ArrayList (2);
3170                         arguments.Add (new Argument (left_temp, Argument.AType.Expression));
3171                         arguments.Add (new Argument (right, Argument.AType.Expression));
3172                         operator_group = operator_group.OverloadResolve (ec, arguments, false, loc);
3173                         if (operator_group == null) {
3174                                 Error19 ();
3175                                 return null;
3176                         }
3177
3178                         MethodInfo method = (MethodInfo)operator_group;
3179                         if (method.ReturnType != type) {
3180                                 Report.Error (217, loc, "In order to be applicable as a short circuit operator a user-defined logical operator `{0}' " +
3181                                                 "must have the same return type as the type of its 2 parameters", TypeManager.CSharpSignature (method));
3182                                 return null;
3183                         }
3184
3185                         op = new StaticCallExpr (method, arguments, loc);
3186
3187                         op_true = GetOperatorTrue (ec, left_temp, loc);
3188                         op_false = GetOperatorFalse (ec, left_temp, loc);
3189                         if ((op_true == null) || (op_false == null)) {
3190                                 Error218 ();
3191                                 return null;
3192                         }
3193
3194                         return this;
3195                 }
3196
3197                 public override void Emit (EmitContext ec)
3198                 {
3199                         ILGenerator ig = ec.ig;
3200                         Label false_target = ig.DefineLabel ();
3201                         Label end_target = ig.DefineLabel ();
3202
3203                         left.Emit (ec);
3204                         left_temp.Store (ec);
3205
3206                         (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
3207                         left_temp.Emit (ec);
3208                         ig.Emit (OpCodes.Br, end_target);
3209                         ig.MarkLabel (false_target);
3210                         op.Emit (ec);
3211                         ig.MarkLabel (end_target);
3212
3213                         // We release 'left_temp' here since 'op' may refer to it too
3214                         left_temp.Release (ec);
3215                 }
3216         }
3217
3218         public class PointerArithmetic : Expression {
3219                 Expression left, right;
3220                 bool is_add;
3221
3222                 //
3223                 // We assume that `l' is always a pointer
3224                 //
3225                 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
3226                 {
3227                         type = t;
3228                         this.loc = loc;
3229                         left = l;
3230                         right = r;
3231                         is_add = is_addition;
3232                 }
3233
3234                 public override Expression DoResolve (EmitContext ec)
3235                 {
3236                         eclass = ExprClass.Variable;
3237                         
3238                         if (left.Type == TypeManager.void_ptr_type) {
3239                                 Error (242, "The operation in question is undefined on void pointers");
3240                                 return null;
3241                         }
3242                         
3243                         return this;
3244                 }
3245
3246                 public override void Emit (EmitContext ec)
3247                 {
3248                         Type op_type = left.Type;
3249                         ILGenerator ig = ec.ig;
3250                         
3251                         // It must be either array or fixed buffer
3252                         Type element = TypeManager.HasElementType (op_type) ?
3253                                 element = TypeManager.GetElementType (op_type) :
3254                                 element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
3255
3256                         int size = GetTypeSize (element);
3257                         Type rtype = right.Type;
3258                         
3259                         if (rtype.IsPointer){
3260                                 //
3261                                 // handle (pointer - pointer)
3262                                 //
3263                                 left.Emit (ec);
3264                                 right.Emit (ec);
3265                                 ig.Emit (OpCodes.Sub);
3266
3267                                 if (size != 1){
3268                                         if (size == 0)
3269                                                 ig.Emit (OpCodes.Sizeof, element);
3270                                         else 
3271                                                 IntLiteral.EmitInt (ig, size);
3272                                         ig.Emit (OpCodes.Div);
3273                                 }
3274                                 ig.Emit (OpCodes.Conv_I8);
3275                         } else {
3276                                 //
3277                                 // handle + and - on (pointer op int)
3278                                 //
3279                                 left.Emit (ec);
3280                                 ig.Emit (OpCodes.Conv_I);
3281
3282                                 Constant right_const = right as Constant;
3283                                 if (right_const != null && size != 0) {
3284                                         Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
3285                                         if (ex == null)
3286                                                 return;
3287                                         ex.Emit (ec);
3288                                 } else {
3289                                         right.Emit (ec);
3290                                         if (size != 1){
3291                                                 if (size == 0)
3292                                                         ig.Emit (OpCodes.Sizeof, element);
3293                                                 else 
3294                                                         IntLiteral.EmitInt (ig, size);
3295                                                 if (rtype == TypeManager.int64_type)
3296                                                         ig.Emit (OpCodes.Conv_I8);
3297                                                 else if (rtype == TypeManager.uint64_type)
3298                                                         ig.Emit (OpCodes.Conv_U8);
3299                                                 ig.Emit (OpCodes.Mul);
3300                                         }
3301                                 }
3302                                 
3303                                 if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
3304                                         ig.Emit (OpCodes.Conv_I);
3305                                 
3306                                 if (is_add)
3307                                         ig.Emit (OpCodes.Add);
3308                                 else
3309                                         ig.Emit (OpCodes.Sub);
3310                         }
3311                 }
3312         }
3313         
3314         /// <summary>
3315         ///   Implements the ternary conditional operator (?:)
3316         /// </summary>
3317         public class Conditional : Expression {
3318                 Expression expr, trueExpr, falseExpr;
3319                 
3320                 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
3321                 {
3322                         this.expr = expr;
3323                         this.trueExpr = trueExpr;
3324                         this.falseExpr = falseExpr;
3325                         this.loc = expr.Location;
3326                 }
3327
3328                 public Expression Expr {
3329                         get {
3330                                 return expr;
3331                         }
3332                 }
3333
3334                 public Expression TrueExpr {
3335                         get {
3336                                 return trueExpr;
3337                         }
3338                 }
3339
3340                 public Expression FalseExpr {
3341                         get {
3342                                 return falseExpr;
3343                         }
3344                 }
3345
3346                 public override Expression DoResolve (EmitContext ec)
3347                 {
3348                         expr = expr.Resolve (ec);
3349
3350                         if (expr == null)
3351                                 return null;
3352
3353 #if GMCS_SOURCE
3354                         if (TypeManager.IsNullableValueType (expr.Type))
3355                                 return new Nullable.LiftedConditional (expr, trueExpr, falseExpr, loc).Resolve (ec);
3356 #endif
3357                         
3358                         if (expr.Type != TypeManager.bool_type){
3359                                 expr = Expression.ResolveBoolean (
3360                                         ec, expr, loc);
3361                                 
3362                                 if (expr == null)
3363                                         return null;
3364                         }
3365                         
3366                         Assign ass = expr as Assign;
3367                         if (ass != null && ass.Source is Constant) {
3368                                 Report.Warning (665, 3, loc, "Assignment in conditional expression is always constant; did you mean to use == instead of = ?");
3369                         }
3370
3371                         trueExpr = trueExpr.Resolve (ec);
3372                         falseExpr = falseExpr.Resolve (ec);
3373
3374                         if (trueExpr == null || falseExpr == null)
3375                                 return null;
3376
3377                         eclass = ExprClass.Value;
3378                         if (trueExpr.Type == falseExpr.Type) {
3379                                 type = trueExpr.Type;
3380                                 if (type == TypeManager.null_type) {
3381                                         // TODO: probably will have to implement ConditionalConstant
3382                                         // to call method without return constant as well
3383                                         Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
3384                                         return trueExpr;
3385                                 }
3386                         } else {
3387                                 Expression conv;
3388                                 Type true_type = trueExpr.Type;
3389                                 Type false_type = falseExpr.Type;
3390
3391                                 //
3392                                 // First, if an implicit conversion exists from trueExpr
3393                                 // to falseExpr, then the result type is of type falseExpr.Type
3394                                 //
3395                                 conv = Convert.ImplicitConversion (ec, trueExpr, false_type, loc);
3396                                 if (conv != null){
3397                                         //
3398                                         // Check if both can convert implicitl to each other's type
3399                                         //
3400                                         if (Convert.ImplicitConversion (ec, falseExpr, true_type, loc) != null){
3401                                                 Error (172,
3402                                                        "Can not compute type of conditional expression " +
3403                                                        "as `" + TypeManager.CSharpName (trueExpr.Type) +
3404                                                        "' and `" + TypeManager.CSharpName (falseExpr.Type) +
3405                                                        "' convert implicitly to each other");
3406                                                 return null;
3407                                         }
3408                                         type = false_type;
3409                                         trueExpr = conv;
3410                                 } else if ((conv = Convert.ImplicitConversion(ec, falseExpr, true_type,loc))!= null){
3411                                         type = true_type;
3412                                         falseExpr = conv;
3413                                 } else {
3414                                         Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
3415                                                 trueExpr.GetSignatureForError (), falseExpr.GetSignatureForError ());
3416                                         return null;
3417                                 }
3418                         }
3419
3420                         // Dead code optimalization
3421                         if (expr is BoolConstant){
3422                                 BoolConstant bc = (BoolConstant) expr;
3423
3424                                 Report.Warning (429, 4, bc.Value ? falseExpr.Location : trueExpr.Location, "Unreachable expression code detected");
3425                                 return bc.Value ? trueExpr : falseExpr;
3426                         }
3427
3428                         return this;
3429                 }
3430
3431                 public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
3432                 {
3433                         return null;
3434                 }
3435
3436                 public override void Emit (EmitContext ec)
3437                 {
3438                         ILGenerator ig = ec.ig;
3439                         Label false_target = ig.DefineLabel ();
3440                         Label end_target = ig.DefineLabel ();
3441
3442                         expr.EmitBranchable (ec, false_target, false);
3443                         trueExpr.Emit (ec);
3444                         ig.Emit (OpCodes.Br, end_target);
3445                         ig.MarkLabel (false_target);
3446                         falseExpr.Emit (ec);
3447                         ig.MarkLabel (end_target);
3448                 }
3449
3450                 protected override void CloneTo (CloneContext clonectx, Expression t)
3451                 {
3452                         Conditional target = (Conditional) t;
3453
3454                         target.expr = expr.Clone (clonectx);
3455                         target.trueExpr = trueExpr.Clone (clonectx);
3456                         target.falseExpr = falseExpr.Clone (clonectx);
3457                 }
3458         }
3459
3460         public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
3461                 bool prepared;
3462                 LocalTemporary temp;
3463
3464                 public abstract Variable Variable {
3465                         get;
3466                 }
3467
3468                 public abstract bool IsRef {
3469                         get;
3470                 }
3471
3472                 public override void Emit (EmitContext ec)
3473                 {
3474                         Emit (ec, false);
3475                 }
3476
3477                 //
3478                 // This method is used by parameters that are references, that are
3479                 // being passed as references:  we only want to pass the pointer (that
3480                 // is already stored in the parameter, not the address of the pointer,
3481                 // and not the value of the variable).
3482                 //
3483                 public void EmitLoad (EmitContext ec)
3484                 {
3485                         Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
3486                         if (!prepared)
3487                                 Variable.EmitInstance (ec);
3488                         Variable.Emit (ec);
3489                 }
3490                 
3491                 public void Emit (EmitContext ec, bool leave_copy)
3492                 {
3493                         Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
3494
3495                         EmitLoad (ec);
3496
3497                         if (IsRef) {
3498                                 if (prepared)
3499                                         ec.ig.Emit (OpCodes.Dup);
3500         
3501                                 //
3502                                 // If we are a reference, we loaded on the stack a pointer
3503                                 // Now lets load the real value
3504                                 //
3505                                 LoadFromPtr (ec.ig, type);
3506                         }
3507
3508                         if (leave_copy) {
3509                                 ec.ig.Emit (OpCodes.Dup);
3510
3511                                 if (IsRef || Variable.NeedsTemporary) {
3512                                         temp = new LocalTemporary (Type);
3513                                         temp.Store (ec);
3514                                 }
3515                         }
3516                 }
3517
3518                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
3519                                         bool prepare_for_load)
3520                 {
3521                         Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
3522                                       source, loc);
3523
3524                         ILGenerator ig = ec.ig;
3525                         prepared = prepare_for_load;
3526
3527                         Variable.EmitInstance (ec);
3528                         if (prepare_for_load && Variable.HasInstance)
3529                                 ig.Emit (OpCodes.Dup);
3530                         else if (IsRef && !prepared)
3531                                 Variable.Emit (ec);
3532
3533                         source.Emit (ec);
3534
3535                         if (leave_copy) {
3536                                 ig.Emit (OpCodes.Dup);
3537                                 if (IsRef || Variable.NeedsTemporary) {
3538                                         temp = new LocalTemporary (Type);
3539                                         temp.Store (ec);
3540                                 }
3541                         }
3542
3543                         if (IsRef)
3544                                 StoreFromPtr (ig, type);
3545                         else
3546                                 Variable.EmitAssign (ec);
3547
3548                         if (temp != null) {
3549                                 temp.Emit (ec);
3550                                 temp.Release (ec);
3551                         }
3552                 }
3553                 
3554                 public void AddressOf (EmitContext ec, AddressOp mode)
3555                 {
3556                         Variable.EmitInstance (ec);
3557                         Variable.EmitAddressOf (ec);
3558                 }
3559         }
3560
3561         /// <summary>
3562         ///   Local variables
3563         /// </summary>
3564         public class LocalVariableReference : VariableReference, IVariable {
3565                 public readonly string Name;
3566                 public Block Block;
3567                 public LocalInfo local_info;
3568                 bool is_readonly;
3569                 Variable variable;
3570
3571                 public LocalVariableReference (Block block, string name, Location l)
3572                 {
3573                         Block = block;
3574                         Name = name;
3575                         loc = l;
3576                         eclass = ExprClass.Variable;
3577                 }
3578
3579                 //
3580                 // Setting `is_readonly' to false will allow you to create a writable
3581                 // reference to a read-only variable.  This is used by foreach and using.
3582                 //
3583                 public LocalVariableReference (Block block, string name, Location l,
3584                                                LocalInfo local_info, bool is_readonly)
3585                         : this (block, name, l)
3586                 {
3587                         this.local_info = local_info;
3588                         this.is_readonly = is_readonly;
3589                 }
3590
3591                 public VariableInfo VariableInfo {
3592                         get { return local_info.VariableInfo; }
3593                 }
3594
3595                 public override bool IsRef {
3596                         get { return false; }
3597                 }
3598
3599                 public bool IsReadOnly {
3600                         get { return is_readonly; }
3601                 }
3602
3603                 public bool VerifyAssigned (EmitContext ec)
3604                 {
3605                         VariableInfo variable_info = local_info.VariableInfo;
3606                         return variable_info == null || variable_info.IsAssigned (ec, loc);
3607                 }
3608
3609                 void ResolveLocalInfo ()
3610                 {
3611                         if (local_info == null) {
3612                                 local_info = Block.GetLocalInfo (Name);
3613                                 type = local_info.VariableType;
3614                                 is_readonly = local_info.ReadOnly;
3615                         }
3616                 }
3617
3618                 protected Expression DoResolveBase (EmitContext ec)
3619                 {
3620                         type = local_info.VariableType;
3621
3622                         Expression e = Block.GetConstantExpression (Name);
3623                         if (e != null)
3624                                 return e.Resolve (ec);
3625
3626                         if (!VerifyAssigned (ec))
3627                                 return null;
3628
3629                         //
3630                         // If we are referencing a variable from the external block
3631                         // flag it for capturing
3632                         //
3633                         if (ec.MustCaptureVariable (local_info)) {
3634                                 if (local_info.AddressTaken){
3635                                         AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
3636                                         return null;
3637                                 }
3638
3639                                 ScopeInfo scope = local_info.Block.CreateScopeInfo ();
3640                                 variable = scope.AddLocal (local_info);
3641                                 type = variable.Type;
3642                         }
3643
3644                         return this;
3645                 }
3646
3647                 public override Expression DoResolve (EmitContext ec)
3648                 {
3649                         ResolveLocalInfo ();
3650                         local_info.Used = true;
3651
3652                         if (type == null && local_info.Type is VarExpr) {
3653                             local_info.VariableType = TypeManager.object_type;
3654                                 Error_VariableIsUsedBeforeItIsDeclared (Name);
3655                             return null;
3656                         }
3657                         
3658                         return DoResolveBase (ec);
3659                 }
3660
3661                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3662                 {
3663                         ResolveLocalInfo ();
3664
3665                         // is out param
3666                         if (right_side == EmptyExpression.OutAccess)
3667                                 local_info.Used = true;
3668
3669                         // Infer implicitly typed local variable
3670                         if (type == null) {
3671                                 VarExpr ve = local_info.Type as VarExpr;
3672                                 if (ve != null) {
3673                                         ve.DoResolveLValue (ec, right_side);
3674                                         type = local_info.VariableType = ve.Type;
3675                                 }
3676                         }
3677                                                 
3678                         if (is_readonly) {
3679                                 int code;
3680                                 string msg;
3681                                 if (right_side == EmptyExpression.OutAccess) {
3682                                         code = 1657; msg = "Cannot pass `{0}' as a ref or out argument because it is a `{1}'";
3683                                 } else if (right_side == EmptyExpression.LValueMemberAccess) {
3684                                         code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
3685                                 } else if (right_side == EmptyExpression.LValueMemberOutAccess) {
3686                                         code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
3687                                 } else {
3688                                         code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
3689                                 }
3690                                 Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
3691                                 return null;
3692                         }
3693
3694                         if (VariableInfo != null)
3695                                 VariableInfo.SetAssigned (ec);
3696
3697                         return DoResolveBase (ec);
3698                 }
3699
3700                 public bool VerifyFixed ()
3701                 {
3702                         // A local Variable is always fixed.
3703                         return true;
3704                 }
3705
3706                 public override int GetHashCode ()
3707                 {
3708                         return Name.GetHashCode ();
3709                 }
3710
3711                 public override bool Equals (object obj)
3712                 {
3713                         LocalVariableReference lvr = obj as LocalVariableReference;
3714                         if (lvr == null)
3715                                 return false;
3716
3717                         return Name == lvr.Name && Block == lvr.Block;
3718                 }
3719
3720                 public override Variable Variable {
3721                         get { return variable != null ? variable : local_info.Variable; }
3722                 }
3723
3724                 public override string ToString ()
3725                 {
3726                         return String.Format ("{0} ({1}:{2})", GetType (), Name, loc);
3727                 }
3728
3729                 protected override void CloneTo (CloneContext clonectx, Expression t)
3730                 {
3731                         LocalVariableReference target = (LocalVariableReference) t;
3732                         
3733                         target.Block = clonectx.LookupBlock (Block);
3734                         if (local_info != null)
3735                                 target.local_info = clonectx.LookupVariable (local_info);
3736                 }
3737         }
3738
3739         /// <summary>
3740         ///   This represents a reference to a parameter in the intermediate
3741         ///   representation.
3742         /// </summary>
3743         public class ParameterReference : VariableReference, IVariable {
3744                 readonly ToplevelParameterInfo pi;
3745                 readonly ToplevelBlock referenced;
3746                 Variable variable;
3747
3748                 public bool is_ref, is_out;
3749
3750                 public bool IsOut {
3751                         get { return is_out; }
3752                 }
3753
3754                 public override bool IsRef {
3755                         get { return is_ref; }
3756                 }
3757
3758                 public string Name {
3759                         get { return Parameter.Name; }
3760                 }
3761
3762                 public Parameter Parameter {
3763                         get { return pi.Parameter; }
3764                 }
3765
3766                 public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
3767                 {
3768                         this.pi = pi;
3769                         this.referenced = referenced;
3770                         this.loc = loc;
3771                         eclass = ExprClass.Variable;
3772                 }
3773
3774                 public VariableInfo VariableInfo {
3775                         get { return pi.VariableInfo; }
3776                 }
3777
3778                 public override Variable Variable {
3779                         get { return variable != null ? variable : Parameter.Variable; }
3780                 }
3781
3782                 public bool VerifyFixed ()
3783                 {
3784                         // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
3785                         return Parameter.ModFlags == Parameter.Modifier.NONE;
3786                 }
3787
3788                 public bool IsAssigned (EmitContext ec, Location loc)
3789                 {
3790                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
3791                                 return true;
3792
3793                         Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
3794                         return false;
3795                 }
3796
3797                 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3798                 {
3799                         if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
3800                                 return true;
3801
3802                         Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
3803                         return false;
3804                 }
3805
3806                 public void SetAssigned (EmitContext ec)
3807                 {
3808                         if (is_out && ec.DoFlowAnalysis)
3809                                 ec.CurrentBranching.SetAssigned (VariableInfo);
3810                 }
3811
3812                 public void SetFieldAssigned (EmitContext ec, string field_name)
3813                 {
3814                         if (is_out && ec.DoFlowAnalysis)
3815                                 ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
3816                 }
3817
3818                 protected bool DoResolveBase (EmitContext ec)
3819                 {
3820                         Parameter par = Parameter;
3821                         if (!par.Resolve (ec)) {
3822                                 //TODO:
3823                         }
3824
3825                         type = par.ParameterType;
3826                         Parameter.Modifier mod = par.ModFlags;
3827                         is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3828                         is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
3829                         eclass = ExprClass.Variable;
3830
3831                         AnonymousContainer am = ec.CurrentAnonymousMethod;
3832                         if (am == null)
3833                                 return true;
3834
3835                         ToplevelBlock declared = pi.Block;
3836                         if (is_ref && declared != referenced) {
3837                                 Report.Error (1628, Location,
3838                                               "Cannot use ref or out parameter `{0}' inside an " +
3839                                               "anonymous method block", par.Name);
3840                                 return false;
3841                         }
3842
3843                         if (!am.IsIterator && declared == referenced)
3844                                 return true;
3845
3846                         // Don't capture aruments when the probing is on
3847                         if (!ec.IsInProbingMode) {
3848                                 ScopeInfo scope = declared.CreateScopeInfo ();
3849                                 variable = scope.AddParameter (par, pi.Index);
3850                                 type = variable.Type;
3851                         }
3852                         return true;
3853                 }
3854
3855                 public override int GetHashCode ()
3856                 {
3857                         return Name.GetHashCode ();
3858                 }
3859
3860                 public override bool Equals (object obj)
3861                 {
3862                         ParameterReference pr = obj as ParameterReference;
3863                         if (pr == null)
3864                                 return false;
3865
3866                         return Name == pr.Name && referenced == pr.referenced;
3867                 }
3868
3869                 //
3870                 // Notice that for ref/out parameters, the type exposed is not the
3871                 // same type exposed externally.
3872                 //
3873                 // for "ref int a":
3874                 //   externally we expose "int&"
3875                 //   here we expose       "int".
3876                 //
3877                 // We record this in "is_ref".  This means that the type system can treat
3878                 // the type as it is expected, but when we generate the code, we generate
3879                 // the alternate kind of code.
3880                 //
3881                 public override Expression DoResolve (EmitContext ec)
3882                 {
3883                         if (!DoResolveBase (ec))
3884                                 return null;
3885
3886                         if (is_out && ec.DoFlowAnalysis &&
3887                             (!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
3888                                 return null;
3889
3890                         return this;
3891                 }
3892
3893                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3894                 {
3895                         if (!DoResolveBase (ec))
3896                                 return null;
3897
3898                         // HACK: parameters are not captured when probing is on
3899                         if (!ec.IsInProbingMode)
3900                                 SetAssigned (ec);
3901
3902                         return this;
3903                 }
3904
3905                 static public void EmitLdArg (ILGenerator ig, int x)
3906                 {
3907                         if (x <= 255){
3908                                 switch (x){
3909                                 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3910                                 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3911                                 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3912                                 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3913                                 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3914                                 }
3915                         } else
3916                                 ig.Emit (OpCodes.Ldarg, x);
3917                 }
3918                 
3919                 public override string ToString ()
3920                 {
3921                         return "ParameterReference[" + Name + "]";
3922                 }
3923         }
3924         
3925         /// <summary>
3926         ///   Used for arguments to New(), Invocation()
3927         /// </summary>
3928         public class Argument {
3929                 public enum AType : byte {
3930                         Expression,
3931                         Ref,
3932                         Out,
3933                         ArgList
3934                 };
3935
3936                 public static readonly Argument[] Empty = new Argument [0];
3937
3938                 public readonly AType ArgType;
3939                 public Expression Expr;
3940                 
3941                 public Argument (Expression expr, AType type)
3942                 {
3943                         this.Expr = expr;
3944                         this.ArgType = type;
3945                 }
3946
3947                 public Argument (Expression expr)
3948                 {
3949                         this.Expr = expr;
3950                         this.ArgType = AType.Expression;
3951                 }
3952
3953                 public Type Type {
3954                         get {
3955                                 if (ArgType == AType.Ref || ArgType == AType.Out)
3956                                         return TypeManager.GetReferenceType (Expr.Type);
3957                                 else
3958                                         return Expr.Type;
3959                         }
3960                 }
3961
3962                 public Parameter.Modifier Modifier
3963                 {
3964                         get {
3965                                 switch (ArgType) {
3966                                         case AType.Out:
3967                                                 return Parameter.Modifier.OUT;
3968
3969                                         case AType.Ref:
3970                                                 return Parameter.Modifier.REF;
3971
3972                                         default:
3973                                                 return Parameter.Modifier.NONE;
3974                                 }
3975                         }
3976                 }
3977
3978                 public static string FullDesc (Argument a)
3979                 {
3980                         if (a.ArgType == AType.ArgList)
3981                                 return "__arglist";
3982
3983                         return (a.ArgType == AType.Ref ? "ref " :
3984                                 (a.ArgType == AType.Out ? "out " : "")) +
3985                                 TypeManager.CSharpName (a.Expr.Type);
3986                 }
3987
3988                 public bool ResolveMethodGroup (EmitContext ec)
3989                 {
3990                         SimpleName sn = Expr as SimpleName;
3991                         if (sn != null)
3992                                 Expr = sn.GetMethodGroup ();
3993
3994                         // FIXME: csc doesn't report any error if you try to use `ref' or
3995                         //        `out' in a delegate creation expression.
3996                         Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
3997                         if (Expr == null)
3998                                 return false;
3999
4000                         return true;
4001                 }
4002
4003                 public bool Resolve (EmitContext ec, Location loc)
4004                 {
4005                         using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
4006                                 // Verify that the argument is readable
4007                                 if (ArgType != AType.Out)
4008                                         Expr = Expr.Resolve (ec);
4009
4010                                 // Verify that the argument is writeable
4011                                 if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
4012                                         Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
4013
4014                                 return Expr != null;
4015                         }
4016                 }
4017
4018                 public void Emit (EmitContext ec)
4019                 {
4020                         if (ArgType != AType.Ref && ArgType != AType.Out) {
4021                                 Expr.Emit (ec);
4022                                 return;
4023                         }
4024
4025                         AddressOp mode = AddressOp.Store;
4026                         if (ArgType == AType.Ref)
4027                                 mode |= AddressOp.Load;
4028                                 
4029                         IMemoryLocation ml = (IMemoryLocation) Expr;
4030                         ParameterReference pr = ml as ParameterReference;
4031
4032                         //
4033                         // ParameterReferences might already be references, so we want
4034                         // to pass just the value
4035                         //
4036                         if (pr != null && pr.IsRef)
4037                                 pr.EmitLoad (ec);
4038                         else
4039                                 ml.AddressOf (ec, mode);
4040                 }
4041
4042                 public Argument Clone (CloneContext clonectx)
4043                 {
4044                         return new Argument (Expr.Clone (clonectx), ArgType);
4045                 }
4046         }
4047
4048         /// <summary>
4049         ///   Invocation of methods or delegates.
4050         /// </summary>
4051         public class Invocation : ExpressionStatement {
4052                 ArrayList Arguments;
4053                 Expression expr;
4054                 MethodGroupExpr mg;
4055                 
4056                 //
4057                 // arguments is an ArrayList, but we do not want to typecast,
4058                 // as it might be null.
4059                 //
4060                 public Invocation (Expression expr, ArrayList arguments)
4061                 {
4062                         SimpleName sn = expr as SimpleName;
4063                         if (sn != null)
4064                                 this.expr = sn.GetMethodGroup ();
4065                         else
4066                                 this.expr = expr;
4067                         
4068                         Arguments = arguments;
4069                         loc = expr.Location;
4070                 }
4071
4072                 public static string FullMethodDesc (MethodBase mb)
4073                 {
4074                         if (mb == null)
4075                                 return "";
4076
4077                         StringBuilder sb;
4078                         if (mb is MethodInfo) {
4079                                 sb = new StringBuilder (TypeManager.CSharpName (((MethodInfo) mb).ReturnType));
4080                                 sb.Append (" ");
4081                         }
4082                         else
4083                                 sb = new StringBuilder ();
4084
4085                         sb.Append (TypeManager.CSharpSignature (mb));
4086                         return sb.ToString ();
4087                 }
4088
4089                 public static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4090                                                              ArrayList arguments, int arg_count,
4091                                                              ref MethodBase candidate)
4092                 {
4093                         return IsParamsMethodApplicable (
4094                                 ec, me, arguments, arg_count, false, ref candidate) ||
4095                                 IsParamsMethodApplicable (
4096                                         ec, me, arguments, arg_count, true, ref candidate);
4097
4098
4099                 }
4100
4101                 static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
4102                                                       ArrayList arguments, int arg_count,
4103                                                       bool do_varargs, ref MethodBase candidate)
4104                 {
4105 #if GMCS_SOURCE
4106                         if (!me.HasTypeArguments &&
4107                             !TypeManager.InferParamsTypeArguments (ec, arguments, ref candidate))
4108                                 return false;
4109
4110                         if (TypeManager.IsGenericMethodDefinition (candidate))
4111                                 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4112 #endif
4113
4114                         return IsParamsMethodApplicable (
4115                                 ec, arguments, arg_count, candidate, do_varargs);
4116                 }
4117
4118                 /// <summary>
4119                 ///   Determines if the candidate method, if a params method, is applicable
4120                 ///   in its expanded form to the given set of arguments
4121                 /// </summary>
4122                 static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
4123                                                       int arg_count, MethodBase candidate,
4124                                                       bool do_varargs)
4125                 {
4126                         ParameterData pd = TypeManager.GetParameterData (candidate);
4127
4128                         int pd_count = pd.Count;
4129                         if (pd_count == 0)
4130                                 return false;
4131
4132                         int count = pd_count - 1;
4133                         if (do_varargs) {
4134                                 if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
4135                                         return false;
4136                                 if (pd_count != arg_count)
4137                                         return false;
4138
4139                                 if (!(((Argument) arguments [count]).Expr is Arglist))
4140                                         return false;
4141                                 --pd_count;
4142                         } else {
4143                                 if (!pd.HasParams)
4144                                         return false;
4145                         }
4146                         
4147                         if (count > arg_count)
4148                                 return false;
4149                         
4150                         if (pd_count == 1 && arg_count == 0)
4151                                 return true;
4152
4153                         //
4154                         // If we have come this far, the case which
4155                         // remains is when the number of parameters is
4156                         // less than or equal to the argument count.
4157                         //
4158                         int argument_index = 0;
4159                         Argument a;
4160                         for (int i = 0; i < pd_count; ++i) {
4161
4162                                 if ((pd.ParameterModifier (i) & Parameter.Modifier.PARAMS) != 0) {
4163                                         Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4164                                         int params_args_count = arg_count - pd_count;
4165                                         if (params_args_count < 0)
4166                                                 continue;
4167
4168                                         do {
4169                                                 a = (Argument) arguments [argument_index++];
4170
4171                                                 if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
4172                                                         return false;
4173                                         } while (params_args_count-- > 0);
4174                                         continue;
4175                                 }
4176
4177                                 a = (Argument) arguments [argument_index++];
4178
4179                                 Parameter.Modifier a_mod = a.Modifier & 
4180                                         (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4181                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4182                                         (unchecked (~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK)));
4183
4184                                 if (a_mod == p_mod) {
4185
4186                                         if (a_mod == Parameter.Modifier.NONE)
4187                                                 if (!Convert.ImplicitConversionExists (ec,
4188                                                         a.Expr,
4189                                                         pd.ParameterType (i)))
4190                                                         return false;
4191
4192                                         if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
4193                                                 Type pt = pd.ParameterType (i);
4194
4195                                                 if (!pt.IsByRef)
4196                                                         pt = TypeManager.GetReferenceType (pt);
4197                                                 
4198                                                 if (pt != a.Type)
4199                                                         return false;
4200                                         }
4201                                 } else
4202                                         return false;
4203                                 
4204                         }
4205
4206                         return true;
4207                 }
4208
4209                 public static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
4210                                                  ArrayList arguments, int arg_count,
4211                                                  ref MethodBase method)
4212                 {
4213                         MethodBase candidate = method;
4214
4215 #if GMCS_SOURCE
4216                         if (!me.HasTypeArguments &&
4217                             !TypeManager.InferTypeArguments (ec, arguments, ref candidate))
4218                                 return false;
4219
4220                         if (TypeManager.IsGenericMethodDefinition (candidate))
4221                                 throw new InternalErrorException ("a generic method definition took part in overload resolution");
4222 #endif
4223
4224                         if (IsApplicable (ec, arguments, arg_count, candidate)) {
4225                                 method = candidate;
4226                                 return true;
4227                         }
4228
4229                         return false;
4230                 }
4231
4232                 /// <summary>
4233                 ///   Determines if the candidate method is applicable (section 14.4.2.1)
4234                 ///   to the given set of arguments
4235                 /// </summary>
4236                 public static bool IsApplicable (EmitContext ec, ArrayList arguments, int arg_count,
4237                                                  MethodBase candidate)
4238                 {
4239                         ParameterData pd = TypeManager.GetParameterData (candidate);
4240
4241                         if (arg_count != pd.Count)
4242                                 return false;
4243
4244                         for (int i = arg_count; i > 0; ) {
4245                                 i--;
4246
4247                                 Argument a = (Argument) arguments [i];
4248                                 
4249                                 Parameter.Modifier a_mod = a.Modifier &
4250                                         ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK);
4251
4252                                 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
4253                                         ~(Parameter.Modifier.OUTMASK | Parameter.Modifier.REFMASK | Parameter.Modifier.PARAMS);
4254
4255                                 if (a_mod != p_mod)
4256                                         return false;
4257
4258                                 Type pt = pd.ParameterType (i);
4259
4260                                 if (TypeManager.IsEqual (pt, a.Type))
4261                                         continue;
4262
4263                                 if (a_mod != Parameter.Modifier.NONE)
4264                                         return false;
4265
4266                                 // FIXME: Kill this abomination (EmitContext.TempEc)
4267                                 EmitContext prevec = EmitContext.TempEc;
4268                                 EmitContext.TempEc = ec;
4269                                 try {
4270                                         if (!Convert.ImplicitConversionExists (ec, a.Expr, pt))
4271                                                 return false;
4272                                 } finally {
4273                                         EmitContext.TempEc = prevec;
4274                                 }
4275                         }
4276
4277                         return true;
4278                 }
4279
4280                 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4281                 {
4282                         Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4283                                 name, arg_count.ToString ());
4284                 }
4285                         
4286                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4287                                                     Type delegate_type, Argument a, ParameterData expected_par)
4288                 {
4289                         if (delegate_type == null) 
4290                                 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4291                                               TypeManager.CSharpSignature (method));
4292                         else
4293                                 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4294                                         TypeManager.CSharpName (delegate_type));
4295
4296                         Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4297
4298                         string index = (idx + 1).ToString ();
4299                         if ((a.Modifier & Parameter.Modifier.ISBYREF) != 0 && mod != a.Modifier) {
4300                                 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4301                                         Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4302                                                 index, Parameter.GetModifierSignature (a.Modifier));
4303                                 else
4304                                         Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4305                                                 index, Parameter.GetModifierSignature (mod));
4306                         } else {
4307                                 string p1 = Argument.FullDesc (a);
4308                                 string p2 = TypeManager.CSharpName (expected_par.ParameterType (idx));
4309
4310                                 if (p1 == p2) {
4311                                         Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4312                                         Report.SymbolRelatedToPreviousError (a.Expr.Type);
4313                                         Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4314                                 }
4315                                 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
4316                         }
4317                 }
4318                 
4319                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4320                                                           int arg_count, MethodBase method, 
4321                                                           bool chose_params_expanded,
4322                                                           Type delegate_type, bool may_fail,
4323                                                           Location loc)
4324                 {
4325                         ParameterData pd = TypeManager.GetParameterData (method);
4326                         int j;
4327                         int a_idx = 0;
4328                         Argument a = null;
4329                         for (j = 0; j < pd.Count; j++) {
4330                                 Type parameter_type = pd.ParameterType (j);
4331                                 Parameter.Modifier pm = pd.ParameterModifier (j);
4332
4333                                 if (pm == Parameter.Modifier.ARGLIST) {
4334                                         a = (Argument) Arguments [a_idx];
4335                                         if (!(a.Expr is Arglist))
4336                                                 break;
4337                                         ++a_idx;
4338                                         continue;
4339                                 }
4340
4341                                 int params_arg_count = 1;
4342                                 if (pm == Parameter.Modifier.PARAMS) {
4343                                         pm = Parameter.Modifier.NONE;
4344                                         params_arg_count = arg_count - pd.Count + 1;
4345                                         if (chose_params_expanded)
4346                                                 parameter_type = TypeManager.GetElementType (parameter_type);
4347                                 }
4348
4349                                 while (params_arg_count > 0) {
4350                                         a = (Argument) Arguments [a_idx];
4351                                         if (pm != a.Modifier)
4352                                                 break;
4353
4354                                         if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4355                                                 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4356                                                         break;
4357
4358                                                 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4359                                                 if (conv == null)
4360                                                         break;
4361
4362                                                 // Update the argument with the implicit conversion
4363                                                 if (a.Expr != conv)
4364                                                         a.Expr = conv;
4365                                         }
4366
4367                                         --params_arg_count;
4368                                         ++a_idx;
4369                                 }
4370                                 if (params_arg_count > 0)
4371                                         break;
4372
4373                                 if (parameter_type.IsPointer && !ec.InUnsafe) {
4374                                         if (!may_fail)
4375                                                 UnsafeError (loc);
4376                                         return false;
4377                                 }
4378                         }
4379
4380                         if (a_idx == arg_count)
4381                                 return true;
4382
4383                         if (!may_fail)
4384                                 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4385                         return false;
4386                 }
4387
4388                 public override Expression DoResolve (EmitContext ec)
4389                 {
4390                         Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4391                         if (expr_resolved == null)
4392                                 return null;
4393
4394                         mg = expr_resolved as MethodGroupExpr;
4395                         if (mg == null) {
4396                                 Type expr_type = expr_resolved.Type;
4397
4398                                 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4399                                         return (new DelegateInvocation (
4400                                                 expr_resolved, Arguments, loc)).Resolve (ec);
4401                                 }
4402                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4403                                 return null;
4404                         }
4405
4406                         //
4407                         // Next, evaluate all the expressions in the argument list
4408                         //
4409                         if (Arguments != null){
4410                                 foreach (Argument a in Arguments){
4411                                         if (!a.Resolve (ec, loc))
4412                                                 return null;
4413                                 }
4414                         }
4415
4416                         mg = mg.OverloadResolve (ec, Arguments, false, loc);
4417                         if (mg == null)
4418                                 return null;
4419
4420                         MethodInfo method = (MethodInfo)mg;
4421                         if (method != null) {
4422                                 type = TypeManager.TypeToCoreType (method.ReturnType);
4423                                 Expression iexpr = mg.InstanceExpression;
4424                                 if (method.IsStatic) {
4425                                         if (iexpr == null || 
4426                                             iexpr is This || iexpr is EmptyExpression ||
4427                                             mg.IdenticalTypeName) {
4428                                                 mg.InstanceExpression = null;
4429                                         } else {
4430                                                 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4431                                                 return null;
4432                                         }
4433                                 } else {
4434                                         if (iexpr == null || iexpr is EmptyExpression) {
4435                                                 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4436                                                 return null;
4437                                         }
4438                                 }
4439                         }
4440
4441                         if (type.IsPointer){
4442                                 if (!ec.InUnsafe){
4443                                         UnsafeError (loc);
4444                                         return null;
4445                                 }
4446                         }
4447                         
4448                         //
4449                         // Only base will allow this invocation to happen.
4450                         //
4451                         if (mg.IsBase && method.IsAbstract){
4452                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4453                                 return null;
4454                         }
4455
4456                         if (Arguments == null && method.Name == "Finalize") {
4457                                 if (mg.IsBase)
4458                                         Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4459                                 else
4460                                         Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4461                                 return null;
4462                         }
4463
4464                         if (IsSpecialMethodInvocation (method)) {
4465                                 return null;
4466                         }
4467                         
4468                         if (mg.InstanceExpression != null){
4469                                 mg.InstanceExpression.CheckMarshalByRefAccess ();
4470
4471                                 //
4472                                 // This is used to check that no methods are called in struct
4473                                 // constructors before all the fields on the struct have been
4474                                 // initialized.
4475                                 //
4476                                 if (!method.IsStatic){
4477                                         This mgthis = mg.InstanceExpression as This;
4478                                         if (mgthis != null){
4479                                                 if (!mgthis.CheckThisUsage (ec))
4480                                                         return  null;
4481                                         }
4482                                 }
4483                         }
4484
4485                         eclass = ExprClass.Value;
4486                         return this;
4487                 }
4488
4489                 bool IsSpecialMethodInvocation (MethodBase method)
4490                 {
4491                         if (!TypeManager.IsSpecialMethod (method))
4492                                 return false;
4493
4494                         Report.SymbolRelatedToPreviousError (method);
4495                         Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4496                                 TypeManager.CSharpSignature (method, true));
4497         
4498                         return true;
4499                 }
4500
4501                 // <summary>
4502                 //   Emits the list of arguments as an array
4503                 // </summary>
4504                 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
4505                 {
4506                         ILGenerator ig = ec.ig;
4507                         Type t = null;
4508                         for (int j = 0; j < count; j++){
4509                                 Argument a = (Argument) arguments [j + idx];
4510                                 if (j == 0) {
4511                                         t = a.Expr.Type;
4512                                         IntConstant.EmitInt (ig, count);
4513                                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4514                                 }
4515                                 
4516                                 ig.Emit (OpCodes.Dup);
4517                                 IntConstant.EmitInt (ig, j);
4518
4519                                 bool is_stobj, has_type_arg;
4520                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
4521                                 if (is_stobj)
4522                                         ig.Emit (OpCodes.Ldelema, t);
4523
4524                                 a.Emit (ec);
4525
4526                                 if (has_type_arg)
4527                                         ig.Emit (op, t);
4528                                 else
4529                                         ig.Emit (op);
4530                         }
4531                 }
4532                 
4533                 /// <summary>
4534                 ///   Emits a list of resolved Arguments that are in the arguments
4535                 ///   ArrayList.
4536                 /// 
4537                 ///   The MethodBase argument might be null if the
4538                 ///   emission of the arguments is known not to contain
4539                 ///   a `params' field (for example in constructors or other routines
4540                 ///   that keep their arguments in this structure)
4541                 ///   
4542                 ///   if `dup_args' is true, a copy of the arguments will be left
4543                 ///   on the stack. If `dup_args' is true, you can specify `this_arg'
4544                 ///   which will be duplicated before any other args. Only EmitCall
4545                 ///   should be using this interface.
4546                 /// </summary>
4547                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4548                 {
4549                         ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
4550                         int top = pd.Count;
4551                         LocalTemporary [] temps = null;
4552                         
4553                         if (dup_args && top != 0)
4554                                 temps = new LocalTemporary [top];
4555
4556                         int argument_index = 0;
4557                         Argument a;
4558                         for (int i = 0; i < top; i++){
4559                                 if (pd != null){
4560                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4561                                                 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4562                                                 int params_args_count = arguments == null ?
4563                                                         0 : arguments.Count - top + 1;
4564
4565                                                 // Fill not provided argument
4566                                                 if (params_args_count <= 0) {
4567                                                         ILGenerator ig = ec.ig;
4568                                                         IntConstant.EmitInt (ig, 0);
4569                                                         ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
4570                                                         continue;
4571                                                 }
4572
4573                                                 //
4574                                                 // Special case if we are passing the same data as the
4575                                                 // params argument, we do not need to recreate an array.
4576                                                 //
4577                                                 a = (Argument) arguments [argument_index];
4578                                                 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
4579                                                         ++argument_index;
4580                                                         a.Emit (ec);
4581                                                         continue;
4582                                                 }
4583
4584                                                 EmitParams (ec, arguments, i, params_args_count);
4585                                                 argument_index += params_args_count;
4586                                                 continue;
4587                                         }
4588                                 }
4589
4590                                 a = (Argument) arguments [argument_index++];
4591                                 a.Emit (ec);
4592                                 if (dup_args) {
4593                                         ec.ig.Emit (OpCodes.Dup);
4594                                         (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4595                                 }
4596                         }
4597                         
4598                         if (dup_args) {
4599                                 if (this_arg != null)
4600                                         this_arg.Emit (ec);
4601                                 
4602                                 for (int i = 0; i < top; i ++) {
4603                                         temps [i].Emit (ec);
4604                                         temps [i].Release (ec);
4605                                 }
4606                         }
4607                 }
4608
4609                 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4610                 {
4611                         ParameterData pd = TypeManager.GetParameterData (mb);
4612
4613                         if (arguments == null)
4614                                 return new Type [0];
4615
4616                         Argument a = (Argument) arguments [pd.Count - 1];
4617                         Arglist list = (Arglist) a.Expr;
4618
4619                         return list.ArgumentTypes;
4620                 }
4621
4622                 /// <summary>
4623                 /// This checks the ConditionalAttribute on the method 
4624                 /// </summary>
4625                 static bool IsMethodExcluded (MethodBase method)
4626                 {
4627                         if (method.IsConstructor)
4628                                 return false;
4629
4630                         IMethodData md = TypeManager.GetMethod (method);
4631                         if (md != null)
4632                                 return md.IsExcluded ();
4633
4634                         // For some methods (generated by delegate class) GetMethod returns null
4635                         // because they are not included in builder_to_method table
4636                         if (method.DeclaringType is TypeBuilder)
4637                                 return false;
4638
4639                         return AttributeTester.IsConditionalMethodExcluded (method);
4640                 }
4641
4642                 /// <remarks>
4643                 ///   is_base tells whether we want to force the use of the `call'
4644                 ///   opcode instead of using callvirt.  Call is required to call
4645                 ///   a specific method, while callvirt will always use the most
4646                 ///   recent method in the vtable.
4647                 ///
4648                 ///   is_static tells whether this is an invocation on a static method
4649                 ///
4650                 ///   instance_expr is an expression that represents the instance
4651                 ///   it must be non-null if is_static is false.
4652                 ///
4653                 ///   method is the method to invoke.
4654                 ///
4655                 ///   Arguments is the list of arguments to pass to the method or constructor.
4656                 /// </remarks>
4657                 public static void EmitCall (EmitContext ec, bool is_base,
4658                                              Expression instance_expr,
4659                                              MethodBase method, ArrayList Arguments, Location loc)
4660                 {
4661                         EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4662                 }
4663                 
4664                 // `dup_args' leaves an extra copy of the arguments on the stack
4665                 // `omit_args' does not leave any arguments at all.
4666                 // So, basically, you could make one call with `dup_args' set to true,
4667                 // and then another with `omit_args' set to true, and the two calls
4668                 // would have the same set of arguments. However, each argument would
4669                 // only have been evaluated once.
4670                 public static void EmitCall (EmitContext ec, bool is_base,
4671                                              Expression instance_expr,
4672                                              MethodBase method, ArrayList Arguments, Location loc,
4673                                              bool dup_args, bool omit_args)
4674                 {
4675                         ILGenerator ig = ec.ig;
4676                         bool struct_call = false;
4677                         bool this_call = false;
4678                         LocalTemporary this_arg = null;
4679
4680                         Type decl_type = method.DeclaringType;
4681
4682                         if (!RootContext.StdLib) {
4683                                 // Replace any calls to the system's System.Array type with calls to
4684                                 // the newly created one.
4685                                 if (method == TypeManager.system_int_array_get_length)
4686                                         method = TypeManager.int_array_get_length;
4687                                 else if (method == TypeManager.system_int_array_get_rank)
4688                                         method = TypeManager.int_array_get_rank;
4689                                 else if (method == TypeManager.system_object_array_clone)
4690                                         method = TypeManager.object_array_clone;
4691                                 else if (method == TypeManager.system_int_array_get_length_int)
4692                                         method = TypeManager.int_array_get_length_int;
4693                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4694                                         method = TypeManager.int_array_get_lower_bound_int;
4695                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4696                                         method = TypeManager.int_array_get_upper_bound_int;
4697                                 else if (method == TypeManager.system_void_array_copyto_array_int)
4698                                         method = TypeManager.void_array_copyto_array_int;
4699                         }
4700
4701                         if (!ec.IsInObsoleteScope) {
4702                                 //
4703                                 // This checks ObsoleteAttribute on the method and on the declaring type
4704                                 //
4705                                 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4706                                 if (oa != null)
4707                                         AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4708
4709                                 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4710                                 if (oa != null) {
4711                                         AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4712                                 }
4713                         }
4714
4715                         if (IsMethodExcluded (method))
4716                                 return;
4717                         
4718                         bool is_static = method.IsStatic;
4719                         if (!is_static){
4720                                 if (instance_expr == EmptyExpression.Null) {
4721                                         SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4722                                         return;
4723                                 }
4724
4725                                 this_call = instance_expr is This;
4726                                 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4727                                         struct_call = true;
4728
4729                                 //
4730                                 // If this is ourselves, push "this"
4731                                 //
4732                                 if (!omit_args) {
4733                                         Type t = null;
4734                                         Type iexpr_type = instance_expr.Type;
4735
4736                                         //
4737                                         // Push the instance expression
4738                                         //
4739                                         if (TypeManager.IsValueType (iexpr_type)) {
4740                                                 //
4741                                                 // Special case: calls to a function declared in a 
4742                                                 // reference-type with a value-type argument need
4743                                                 // to have their value boxed.
4744                                                 if (decl_type.IsValueType ||
4745                                                     TypeManager.IsGenericParameter (iexpr_type)) {
4746                                                         //
4747                                                         // If the expression implements IMemoryLocation, then
4748                                                         // we can optimize and use AddressOf on the
4749                                                         // return.
4750                                                         //
4751                                                         // If not we have to use some temporary storage for
4752                                                         // it.
4753                                                         if (instance_expr is IMemoryLocation) {
4754                                                                 ((IMemoryLocation)instance_expr).
4755                                                                         AddressOf (ec, AddressOp.LoadStore);
4756                                                         } else {
4757                                                                 LocalTemporary temp = new LocalTemporary (iexpr_type);
4758                                                                 instance_expr.Emit (ec);
4759                                                                 temp.Store (ec);
4760                                                                 temp.AddressOf (ec, AddressOp.Load);
4761                                                         }
4762
4763                                                         // avoid the overhead of doing this all the time.
4764                                                         if (dup_args)
4765                                                                 t = TypeManager.GetReferenceType (iexpr_type);
4766                                                 } else {
4767                                                         instance_expr.Emit (ec);
4768                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
4769                                                         t = TypeManager.object_type;
4770                                                 }
4771                                         } else {
4772                                                 instance_expr.Emit (ec);
4773                                                 t = instance_expr.Type;
4774                                         }
4775
4776                                         if (dup_args) {
4777                                                 ig.Emit (OpCodes.Dup);
4778                                                 if (Arguments != null && Arguments.Count != 0) {
4779                                                         this_arg = new LocalTemporary (t);
4780                                                         this_arg.Store (ec);
4781                                                 }
4782                                         }
4783                                 }
4784                         }
4785
4786                         if (!omit_args)
4787                                 EmitArguments (ec, method, Arguments, dup_args, this_arg);
4788
4789 #if GMCS_SOURCE
4790                         if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4791                                 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4792 #endif
4793
4794                         OpCode call_op;
4795                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4796                                 call_op = OpCodes.Call;
4797                         else
4798                                 call_op = OpCodes.Callvirt;
4799
4800                         if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4801                                 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4802                                 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4803                                 return;
4804                         }
4805
4806                         //
4807                         // If you have:
4808                         // this.DoFoo ();
4809                         // and DoFoo is not virtual, you can omit the callvirt,
4810                         // because you don't need the null checking behavior.
4811                         //
4812                         if (method is MethodInfo)
4813                                 ig.Emit (call_op, (MethodInfo) method);
4814                         else
4815                                 ig.Emit (call_op, (ConstructorInfo) method);
4816                 }
4817                 
4818                 public override void Emit (EmitContext ec)
4819                 {
4820                         mg.EmitCall (ec, Arguments);
4821                 }
4822                 
4823                 public override void EmitStatement (EmitContext ec)
4824                 {
4825                         Emit (ec);
4826
4827                         // 
4828                         // Pop the return value if there is one
4829                         //
4830                         if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4831                                 ec.ig.Emit (OpCodes.Pop);
4832                 }
4833
4834                 protected override void CloneTo (CloneContext clonectx, Expression t)
4835                 {
4836                         Invocation target = (Invocation) t;
4837
4838                         if (Arguments != null) {
4839                                 target.Arguments = new ArrayList (Arguments.Count);
4840                                 foreach (Argument a in Arguments)
4841                                         target.Arguments.Add (a.Clone (clonectx));
4842                         }
4843
4844                         target.expr = expr.Clone (clonectx);
4845                 }
4846         }
4847
4848         public class InvocationOrCast : ExpressionStatement
4849         {
4850                 Expression expr;
4851                 Expression argument;
4852
4853                 public InvocationOrCast (Expression expr, Expression argument)
4854                 {
4855                         this.expr = expr;
4856                         this.argument = argument;
4857                         this.loc = expr.Location;
4858                 }
4859
4860                 public override Expression DoResolve (EmitContext ec)
4861                 {
4862                         //
4863                         // First try to resolve it as a cast.
4864                         //
4865                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4866                         if ((te != null) && (te.eclass == ExprClass.Type)) {
4867                                 Cast cast = new Cast (te, argument, loc);
4868                                 return cast.Resolve (ec);
4869                         }
4870
4871                         //
4872                         // This can either be a type or a delegate invocation.
4873                         // Let's just resolve it and see what we'll get.
4874                         //
4875                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4876                         if (expr == null)
4877                                 return null;
4878
4879                         //
4880                         // Ok, so it's a Cast.
4881                         //
4882                         if (expr.eclass == ExprClass.Type) {
4883                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4884                                 return cast.Resolve (ec);
4885                         }
4886
4887                         //
4888                         // It's a delegate invocation.
4889                         //
4890                         if (!TypeManager.IsDelegateType (expr.Type)) {
4891                                 Error (149, "Method name expected");
4892                                 return null;
4893                         }
4894
4895                         ArrayList args = new ArrayList ();
4896                         args.Add (new Argument (argument, Argument.AType.Expression));
4897                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4898                         return invocation.Resolve (ec);
4899                 }
4900
4901                 public override ExpressionStatement ResolveStatement (EmitContext ec)
4902                 {
4903                         //
4904                         // First try to resolve it as a cast.
4905                         //
4906                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4907                         if ((te != null) && (te.eclass == ExprClass.Type)) {
4908                                 Error_InvalidExpressionStatement ();
4909                                 return null;
4910                         }
4911
4912                         //
4913                         // This can either be a type or a delegate invocation.
4914                         // Let's just resolve it and see what we'll get.
4915                         //
4916                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4917                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4918                                 Error_InvalidExpressionStatement ();
4919                                 return null;
4920                         }
4921
4922                         //
4923                         // It's a delegate invocation.
4924                         //
4925                         if (!TypeManager.IsDelegateType (expr.Type)) {
4926                                 Error (149, "Method name expected");
4927                                 return null;
4928                         }
4929
4930                         ArrayList args = new ArrayList ();
4931                         args.Add (new Argument (argument, Argument.AType.Expression));
4932                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4933                         return invocation.ResolveStatement (ec);
4934                 }
4935
4936                 public override void Emit (EmitContext ec)
4937                 {
4938                         throw new Exception ("Cannot happen");
4939                 }
4940
4941                 public override void EmitStatement (EmitContext ec)
4942                 {
4943                         throw new Exception ("Cannot happen");
4944                 }
4945
4946                 protected override void CloneTo (CloneContext clonectx, Expression t)
4947                 {
4948                         InvocationOrCast target = (InvocationOrCast) t;
4949
4950                         target.expr = expr.Clone (clonectx);
4951                         target.argument = argument.Clone (clonectx);
4952                 }
4953         }
4954
4955         //
4956         // This class is used to "disable" the code generation for the
4957         // temporary variable when initializing value types.
4958         //
4959         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4960                 public void AddressOf (EmitContext ec, AddressOp Mode)
4961                 {
4962                         // nothing
4963                 }
4964         }
4965         
4966         /// <summary>
4967         ///    Implements the new expression 
4968         /// </summary>
4969         public class New : ExpressionStatement, IMemoryLocation {
4970                 ArrayList Arguments;
4971
4972                 //
4973                 // During bootstrap, it contains the RequestedType,
4974                 // but if `type' is not null, it *might* contain a NewDelegate
4975                 // (because of field multi-initialization)
4976                 //
4977                 public Expression RequestedType;
4978
4979                 MethodGroupExpr method;
4980
4981                 //
4982                 // If set, the new expression is for a value_target, and
4983                 // we will not leave anything on the stack.
4984                 //
4985                 Expression value_target;
4986                 bool value_target_set = false;
4987                 bool is_type_parameter = false;
4988                 
4989                 public New (Expression requested_type, ArrayList arguments, Location l)
4990                 {
4991                         RequestedType = requested_type;
4992                         Arguments = arguments;
4993                         loc = l;
4994                 }
4995
4996                 public bool SetValueTypeVariable (Expression value)
4997                 {
4998                         value_target = value;
4999                         value_target_set = true;
5000                         if (!(value_target is IMemoryLocation)){
5001                                 Error_UnexpectedKind (null, "variable", loc);
5002                                 return false;
5003                         }
5004                         return true;
5005                 }
5006
5007                 //
5008                 // This function is used to disable the following code sequence for
5009                 // value type initialization:
5010                 //
5011                 // AddressOf (temporary)
5012                 // Construct/Init
5013                 // LoadTemporary
5014                 //
5015                 // Instead the provide will have provided us with the address on the
5016                 // stack to store the results.
5017                 //
5018                 static Expression MyEmptyExpression;
5019                 
5020                 public void DisableTemporaryValueType ()
5021                 {
5022                         if (MyEmptyExpression == null)
5023                                 MyEmptyExpression = new EmptyAddressOf ();
5024
5025                         //
5026                         // To enable this, look into:
5027                         // test-34 and test-89 and self bootstrapping.
5028                         //
5029                         // For instance, we can avoid a copy by using `newobj'
5030                         // instead of Call + Push-temp on value types.
5031 //                      value_target = MyEmptyExpression;
5032                 }
5033
5034
5035                 /// <summary>
5036                 /// Converts complex core type syntax like 'new int ()' to simple constant
5037                 /// </summary>
5038                 public static Constant Constantify (Type t)
5039                 {
5040                         if (t == TypeManager.int32_type)
5041                                 return new IntConstant (0, Location.Null);
5042                         if (t == TypeManager.uint32_type)
5043                                 return new UIntConstant (0, Location.Null);
5044                         if (t == TypeManager.int64_type)
5045                                 return new LongConstant (0, Location.Null);
5046                         if (t == TypeManager.uint64_type)
5047                                 return new ULongConstant (0, Location.Null);
5048                         if (t == TypeManager.float_type)
5049                                 return new FloatConstant (0, Location.Null);
5050                         if (t == TypeManager.double_type)
5051                                 return new DoubleConstant (0, Location.Null);
5052                         if (t == TypeManager.short_type)
5053                                 return new ShortConstant (0, Location.Null);
5054                         if (t == TypeManager.ushort_type)
5055                                 return new UShortConstant (0, Location.Null);
5056                         if (t == TypeManager.sbyte_type)
5057                                 return new SByteConstant (0, Location.Null);
5058                         if (t == TypeManager.byte_type)
5059                                 return new ByteConstant (0, Location.Null);
5060                         if (t == TypeManager.char_type)
5061                                 return new CharConstant ('\0', Location.Null);
5062                         if (t == TypeManager.bool_type)
5063                                 return new BoolConstant (false, Location.Null);
5064                         if (t == TypeManager.decimal_type)
5065                                 return new DecimalConstant (0, Location.Null);
5066                         if (TypeManager.IsEnumType (t))
5067                                 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5068
5069                         return null;
5070                 }
5071
5072                 //
5073                 // Checks whether the type is an interface that has the
5074                 // [ComImport, CoClass] attributes and must be treated
5075                 // specially
5076                 //
5077                 public Expression CheckComImport (EmitContext ec)
5078                 {
5079                         if (!type.IsInterface)
5080                                 return null;
5081
5082                         //
5083                         // Turn the call into:
5084                         // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5085                         //
5086                         Type real_class = AttributeTester.GetCoClassAttribute (type);
5087                         if (real_class == null)
5088                                 return null;
5089
5090                         New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5091                         Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5092                         return cast.Resolve (ec);
5093                 }
5094                 
5095                 public override Expression DoResolve (EmitContext ec)
5096                 {
5097                         //
5098                         // The New DoResolve might be called twice when initializing field
5099                         // expressions (see EmitFieldInitializers, the call to
5100                         // GetInitializerExpression will perform a resolve on the expression,
5101                         // and later the assign will trigger another resolution
5102                         //
5103                         // This leads to bugs (#37014)
5104                         //
5105                         if (type != null){
5106                                 if (RequestedType is NewDelegate)
5107                                         return RequestedType;
5108                                 return this;
5109                         }
5110
5111                         TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5112                         if (texpr == null)
5113                                 return null;
5114
5115                         type = texpr.Type;
5116
5117                         if (type == TypeManager.void_type) {
5118                                 Error_VoidInvalidInTheContext (loc);
5119                                 return null;
5120                         }
5121
5122                         if (Arguments == null) {
5123                                 Expression c = Constantify (type);
5124                                 if (c != null)
5125                                         return c;
5126                         }
5127
5128                         if (TypeManager.IsDelegateType (type)) {
5129                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5130                                 if (RequestedType != null)
5131                                         if (!(RequestedType is DelegateCreation))
5132                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5133                                 return RequestedType;
5134                         }
5135
5136 #if GMCS_SOURCE
5137                         if (type.IsGenericParameter) {
5138                                 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5139
5140                                 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5141                                         Error (304, String.Format (
5142                                                        "Cannot create an instance of the " +
5143                                                        "variable type '{0}' because it " +
5144                                                        "doesn't have the new() constraint",
5145                                                        type));
5146                                         return null;
5147                                 }
5148
5149                                 if ((Arguments != null) && (Arguments.Count != 0)) {
5150                                         Error (417, String.Format (
5151                                                        "`{0}': cannot provide arguments " +
5152                                                        "when creating an instance of a " +
5153                                                        "variable type.", type));
5154                                         return null;
5155                                 }
5156
5157                                 is_type_parameter = true;
5158                                 eclass = ExprClass.Value;
5159                                 return this;
5160                         }
5161 #endif
5162
5163                         if (type.IsAbstract && type.IsSealed) {
5164                                 Report.SymbolRelatedToPreviousError (type);
5165                                 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5166                                 return null;
5167                         }
5168
5169                         if (type.IsInterface || type.IsAbstract){
5170                                 if (!TypeManager.IsGenericType (type)) {
5171                                         RequestedType = CheckComImport (ec);
5172                                         if (RequestedType != null)
5173                                                 return RequestedType;
5174                                 }
5175                                 
5176                                 Report.SymbolRelatedToPreviousError (type);
5177                                 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5178                                 return null;
5179                         }
5180
5181                         bool is_struct = type.IsValueType;
5182                         eclass = ExprClass.Value;
5183
5184                         //
5185                         // SRE returns a match for .ctor () on structs (the object constructor), 
5186                         // so we have to manually ignore it.
5187                         //
5188                         if (is_struct && Arguments == null)
5189                                 return this;
5190
5191                         // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5192                         Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5193                                 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5194
5195                         if (ml == null)
5196                                 return null;
5197
5198                         method = ml as MethodGroupExpr;
5199
5200                         if (method == null) {
5201                                 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5202                                 return null;
5203                         }
5204
5205                         if (Arguments != null){
5206                                 foreach (Argument a in Arguments){
5207                                         if (!a.Resolve (ec, loc))
5208                                                 return null;
5209                                 }
5210                         }
5211                         
5212                         method = method.OverloadResolve (ec, Arguments, false, loc);
5213                         if (method == null) {
5214                                 if (almostMatchedMembers.Count != 0)
5215                                         MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
5216                                 return null;
5217                         }
5218
5219                         return this;
5220                 }
5221
5222                 bool DoEmitTypeParameter (EmitContext ec)
5223                 {
5224 #if GMCS_SOURCE
5225                         ILGenerator ig = ec.ig;
5226 //                      IMemoryLocation ml;
5227
5228                         MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5229                                 new Type [] { type });
5230
5231                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5232                         if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5233                                 ig.Emit (OpCodes.Call, ci);
5234                                 return true;
5235                         }
5236
5237                         // Allow DoEmit() to be called multiple times.
5238                         // We need to create a new LocalTemporary each time since
5239                         // you can't share LocalBuilders among ILGeneators.
5240                         LocalTemporary temp = new LocalTemporary (type);
5241
5242                         Label label_activator = ig.DefineLabel ();
5243                         Label label_end = ig.DefineLabel ();
5244
5245                         temp.AddressOf (ec, AddressOp.Store);
5246                         ig.Emit (OpCodes.Initobj, type);
5247
5248                         temp.Emit (ec);
5249                         ig.Emit (OpCodes.Box, type);
5250                         ig.Emit (OpCodes.Brfalse, label_activator);
5251
5252                         temp.AddressOf (ec, AddressOp.Store);
5253                         ig.Emit (OpCodes.Initobj, type);
5254                         temp.Emit (ec);
5255                         ig.Emit (OpCodes.Br, label_end);
5256
5257                         ig.MarkLabel (label_activator);
5258
5259                         ig.Emit (OpCodes.Call, ci);
5260                         ig.MarkLabel (label_end);
5261                         return true;
5262 #else
5263                         throw new InternalErrorException ();
5264 #endif
5265                 }
5266
5267                 //
5268                 // This DoEmit can be invoked in two contexts:
5269                 //    * As a mechanism that will leave a value on the stack (new object)
5270                 //    * As one that wont (init struct)
5271                 //
5272                 // You can control whether a value is required on the stack by passing
5273                 // need_value_on_stack.  The code *might* leave a value on the stack
5274                 // so it must be popped manually
5275                 //
5276                 // If we are dealing with a ValueType, we have a few
5277                 // situations to deal with:
5278                 //
5279                 //    * The target is a ValueType, and we have been provided
5280                 //      the instance (this is easy, we are being assigned).
5281                 //
5282                 //    * The target of New is being passed as an argument,
5283                 //      to a boxing operation or a function that takes a
5284                 //      ValueType.
5285                 //
5286                 //      In this case, we need to create a temporary variable
5287                 //      that is the argument of New.
5288                 //
5289                 // Returns whether a value is left on the stack
5290                 //
5291                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5292                 {
5293                         bool is_value_type = TypeManager.IsValueType (type);
5294                         ILGenerator ig = ec.ig;
5295
5296                         if (is_value_type){
5297                                 IMemoryLocation ml;
5298
5299                                 // Allow DoEmit() to be called multiple times.
5300                                 // We need to create a new LocalTemporary each time since
5301                                 // you can't share LocalBuilders among ILGeneators.
5302                                 if (!value_target_set)
5303                                         value_target = new LocalTemporary (type);
5304
5305                                 ml = (IMemoryLocation) value_target;
5306                                 ml.AddressOf (ec, AddressOp.Store);
5307                         }
5308
5309                         if (method != null)
5310                                 method.EmitArguments (ec, Arguments);
5311
5312                         if (is_value_type){
5313                                 if (method == null)
5314                                         ig.Emit (OpCodes.Initobj, type);
5315                                 else
5316                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5317                                 if (need_value_on_stack){
5318                                         value_target.Emit (ec);
5319                                         return true;
5320                                 }
5321                                 return false;
5322                         } else {
5323                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5324                                 return true;
5325                         }
5326                 }
5327
5328                 public override void Emit (EmitContext ec)
5329                 {
5330                         if (is_type_parameter)
5331                                 DoEmitTypeParameter (ec);
5332                         else
5333                                 DoEmit (ec, true);
5334                 }
5335                 
5336                 public override void EmitStatement (EmitContext ec)
5337                 {
5338                         bool value_on_stack;
5339
5340                         if (is_type_parameter)
5341                                 value_on_stack = DoEmitTypeParameter (ec);
5342                         else
5343                                 value_on_stack = DoEmit (ec, false);
5344
5345                         if (value_on_stack)
5346                                 ec.ig.Emit (OpCodes.Pop);
5347
5348                 }
5349
5350                 public void AddressOf (EmitContext ec, AddressOp Mode)
5351                 {
5352                         if (is_type_parameter) {
5353                                 LocalTemporary temp = new LocalTemporary (type);
5354                                 DoEmitTypeParameter (ec);
5355                                 temp.Store (ec);
5356                                 temp.AddressOf (ec, Mode);
5357                                 return;
5358                         }
5359
5360                         if (!type.IsValueType){
5361                                 //
5362                                 // We throw an exception.  So far, I believe we only need to support
5363                                 // value types:
5364                                 // foreach (int j in new StructType ())
5365                                 // see bug 42390
5366                                 //
5367                                 throw new Exception ("AddressOf should not be used for classes");
5368                         }
5369
5370                         if (!value_target_set)
5371                                 value_target = new LocalTemporary (type);
5372                         IMemoryLocation ml = (IMemoryLocation) value_target;
5373
5374                         ml.AddressOf (ec, AddressOp.Store);
5375                         if (method == null) {
5376                                 ec.ig.Emit (OpCodes.Initobj, type);
5377                         } else {
5378                                 method.EmitArguments (ec, Arguments);
5379                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5380                         }
5381                         
5382                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5383                 }
5384
5385                 protected override void CloneTo (CloneContext clonectx, Expression t)
5386                 {
5387                         New target = (New) t;
5388
5389                         target.RequestedType = RequestedType.Clone (clonectx);
5390                         if (Arguments != null){
5391                                 target.Arguments = new ArrayList ();
5392                                 foreach (Argument a in Arguments){
5393                                         target.Arguments.Add (a.Clone (clonectx));
5394                                 }
5395                         }
5396                 }
5397         }
5398
5399         /// <summary>
5400         ///   14.5.10.2: Represents an array creation expression.
5401         /// </summary>
5402         ///
5403         /// <remarks>
5404         ///   There are two possible scenarios here: one is an array creation
5405         ///   expression that specifies the dimensions and optionally the
5406         ///   initialization data and the other which does not need dimensions
5407         ///   specified but where initialization data is mandatory.
5408         /// </remarks>
5409         public class ArrayCreation : Expression {
5410                 Expression requested_base_type;
5411                 ArrayList initializers;
5412
5413                 //
5414                 // The list of Argument types.
5415                 // This is used to construct the `newarray' or constructor signature
5416                 //
5417                 protected ArrayList arguments;
5418                 
5419                 protected Type array_element_type;
5420                 bool expect_initializers = false;
5421                 int num_arguments = 0;
5422                 protected int dimensions;
5423                 protected readonly string rank;
5424
5425                 protected ArrayList array_data;
5426
5427                 IDictionary bounds;
5428
5429                 // The number of constants in array initializers
5430                 int const_initializers_count;
5431                 bool only_constant_initializers;
5432                 
5433                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5434                 {
5435                         this.requested_base_type = requested_base_type;
5436                         this.initializers = initializers;
5437                         this.rank = rank;
5438                         loc = l;
5439
5440                         arguments = new ArrayList ();
5441
5442                         foreach (Expression e in exprs) {
5443                                 arguments.Add (new Argument (e, Argument.AType.Expression));
5444                                 num_arguments++;
5445                         }
5446                 }
5447
5448                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5449                 {
5450                         this.requested_base_type = requested_base_type;
5451                         this.initializers = initializers;
5452                         this.rank = rank;
5453                         loc = l;
5454
5455                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5456                         //
5457                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
5458                         //
5459                         //dimensions = tmp.Length - 1;
5460                         expect_initializers = true;
5461                 }
5462
5463                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5464                 {
5465                         StringBuilder sb = new StringBuilder (rank);
5466                         
5467                         sb.Append ("[");
5468                         for (int i = 1; i < idx_count; i++)
5469                                 sb.Append (",");
5470                         
5471                         sb.Append ("]");
5472
5473                         return new ComposedCast (base_type, sb.ToString (), loc);
5474                 }
5475
5476                 void Error_IncorrectArrayInitializer ()
5477                 {
5478                         Error (178, "Invalid rank specifier: expected `,' or `]'");
5479                 }
5480                 
5481                 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5482                 {
5483                         if (specified_dims) { 
5484                                 Argument a = (Argument) arguments [idx];
5485
5486                                 if (!a.Resolve (ec, loc))
5487                                         return false;
5488
5489                                 Constant c = a.Expr as Constant;
5490                                 if (c != null) {
5491                                         c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5492                                 }
5493
5494                                 if (c == null) {
5495                                         Report.Error (150, a.Expr.Location, "A constant value is expected");
5496                                         return false;
5497                                 }
5498
5499                                 int value = (int) c.GetValue ();
5500                                 
5501                                 if (value != probe.Count) {
5502                                         Error_IncorrectArrayInitializer ();
5503                                         return false;
5504                                 }
5505                                 
5506                                 bounds [idx] = value;
5507                         }
5508
5509                         int child_bounds = -1;
5510                         only_constant_initializers = true;
5511                         for (int i = 0; i < probe.Count; ++i) {
5512                                 object o = probe [i];
5513                                 if (o is ArrayList) {
5514                                         ArrayList sub_probe = o as ArrayList;
5515                                         int current_bounds = sub_probe.Count;
5516                                         
5517                                         if (child_bounds == -1) 
5518                                                 child_bounds = current_bounds;
5519
5520                                         else if (child_bounds != current_bounds){
5521                                                 Error_IncorrectArrayInitializer ();
5522                                                 return false;
5523                                         }
5524                                         if (idx + 1 >= dimensions){
5525                                                 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5526                                                 return false;
5527                                         }
5528                                         
5529                                         bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5530                                         if (!ret)
5531                                                 return false;
5532                                 } else {
5533                                         if (child_bounds != -1){
5534                                                 Error_IncorrectArrayInitializer ();
5535                                                 return false;
5536                                         }
5537                                         
5538                                         Expression element = ResolveArrayElement (ec, (Expression) o);
5539                                         if (element == null)
5540                                                 continue;
5541
5542                                         // Initializers with the default values can be ignored
5543                                         Constant c = element as Constant;
5544                                         if (c != null) {
5545                                                 if (c.IsDefaultInitializer (array_element_type)) {
5546                                                         element = null;
5547                                                 }
5548                                                 else {
5549                                                         ++const_initializers_count;
5550                                                 }
5551                                         } else {
5552                                                 only_constant_initializers = false;
5553                                         }
5554                                         
5555                                         array_data.Add (element);
5556                                 }
5557                         }
5558
5559                         return true;
5560                 }
5561                 
5562                 public void UpdateIndices ()
5563                 {
5564                         int i = 0;
5565                         for (ArrayList probe = initializers; probe != null;) {
5566                                 if (probe.Count > 0 && probe [0] is ArrayList) {
5567                                         Expression e = new IntConstant (probe.Count, Location.Null);
5568                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5569
5570                                         bounds [i++] =  probe.Count;
5571                                         
5572                                         probe = (ArrayList) probe [0];
5573                                         
5574                                 } else {
5575                                         Expression e = new IntConstant (probe.Count, Location.Null);
5576                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5577
5578                                         bounds [i++] = probe.Count;
5579                                         return;
5580                                 }
5581                         }
5582
5583                 }
5584
5585                 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5586                 {
5587                         element = element.Resolve (ec);
5588                         if (element == null)
5589                                 return null;
5590
5591                         return Convert.ImplicitConversionRequired (
5592                                 ec, element, array_element_type, loc);
5593                 }
5594
5595                 protected bool ResolveInitializers (EmitContext ec)
5596                 {
5597                         if (initializers == null) {
5598                                 return !expect_initializers;
5599                         }
5600                                                 
5601                         //
5602                         // We use this to store all the date values in the order in which we
5603                         // will need to store them in the byte blob later
5604                         //
5605                         array_data = new ArrayList ();
5606                         bounds = new System.Collections.Specialized.HybridDictionary ();
5607                         
5608                         if (arguments != null)
5609                                 return CheckIndices (ec, initializers, 0, true);
5610
5611                         arguments = new ArrayList ();
5612
5613                         if (!CheckIndices (ec, initializers, 0, false))
5614                                 return false;
5615                                 
5616                         UpdateIndices ();
5617                                 
5618                         return true;
5619                 }
5620
5621                 //
5622                 // Resolved the type of the array
5623                 //
5624                 bool ResolveArrayType (EmitContext ec)
5625                 {
5626                         if (requested_base_type == null) {
5627                                 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5628                                 return false;
5629                         }
5630                         
5631                         StringBuilder array_qualifier = new StringBuilder (rank);
5632
5633                         //
5634                         // `In the first form allocates an array instace of the type that results
5635                         // from deleting each of the individual expression from the expression list'
5636                         //
5637                         if (num_arguments > 0) {
5638                                 array_qualifier.Append ("[");
5639                                 for (int i = num_arguments-1; i > 0; i--)
5640                                         array_qualifier.Append (",");
5641                                 array_qualifier.Append ("]");
5642                         }
5643
5644                         //
5645                         // Lookup the type
5646                         //
5647                         TypeExpr array_type_expr;
5648                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5649                         array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5650                         if (array_type_expr == null)
5651                                 return false;
5652
5653                         type = array_type_expr.Type;
5654                         array_element_type = TypeManager.GetElementType (type);
5655                         dimensions = type.GetArrayRank ();
5656
5657                         return true;
5658                 }
5659
5660                 public override Expression DoResolve (EmitContext ec)
5661                 {
5662                         if (type != null)
5663                                 return this;
5664
5665                         if (!ResolveArrayType (ec))
5666                                 return null;
5667                         
5668                         if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5669                                 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5670                                         TypeManager.CSharpName (array_element_type));
5671                         }
5672
5673                         //
5674                         // First step is to validate the initializers and fill
5675                         // in any missing bits
5676                         //
5677                         if (!ResolveInitializers (ec))
5678                                 return null;
5679
5680                         if (arguments.Count != dimensions) {
5681                                 Error_IncorrectArrayInitializer ();
5682                         }
5683
5684                         foreach (Argument a in arguments){
5685                                 if (!a.Resolve (ec, loc))
5686                                         return null;
5687
5688                                 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5689                                 if (real_arg == null)
5690                                         return null;
5691
5692                                 a.Expr = real_arg;
5693                         }
5694                                                         
5695                         eclass = ExprClass.Value;
5696                         return this;
5697                 }
5698
5699                 MethodInfo GetArrayMethod (int arguments)
5700                 {
5701                         ModuleBuilder mb = CodeGen.Module.Builder;
5702
5703                         Type[] arg_types = new Type[arguments];
5704                         for (int i = 0; i < arguments; i++)
5705                                 arg_types[i] = TypeManager.int32_type;
5706
5707                         MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5708                                                         arg_types);
5709
5710                         if (mi == null) {
5711                                 Report.Error (-6, "New invocation: Can not find a constructor for " +
5712                                                   "this argument list");
5713                                 return null;
5714                         }
5715
5716                         return mi; 
5717                 }
5718
5719                 byte [] MakeByteBlob ()
5720                 {
5721                         int factor;
5722                         byte [] data;
5723                         byte [] element;
5724                         int count = array_data.Count;
5725
5726                         if (array_element_type.IsEnum)
5727                                 array_element_type = TypeManager.EnumToUnderlying (array_element_type);
5728                         
5729                         factor = GetTypeSize (array_element_type);
5730                         if (factor == 0)
5731                                 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5732
5733                         data = new byte [(count * factor + 4) & ~3];
5734                         int idx = 0;
5735
5736                         for (int i = 0; i < count; ++i) {
5737                                 object v = array_data [i];
5738
5739                                 if (v is EnumConstant)
5740                                         v = ((EnumConstant) v).Child;
5741                                 
5742                                 if (v is Constant && !(v is StringConstant))
5743                                         v = ((Constant) v).GetValue ();
5744                                 else {
5745                                         idx += factor;
5746                                         continue;
5747                                 }
5748                                 
5749                                 if (array_element_type == TypeManager.int64_type){
5750                                         if (!(v is Expression)){
5751                                                 long val = (long) v;
5752                                                 
5753                                                 for (int j = 0; j < factor; ++j) {
5754                                                         data [idx + j] = (byte) (val & 0xFF);
5755                                                         val = (val >> 8);
5756                                                 }
5757                                         }
5758                                 } else if (array_element_type == TypeManager.uint64_type){
5759                                         if (!(v is Expression)){
5760                                                 ulong val = (ulong) v;
5761
5762                                                 for (int j = 0; j < factor; ++j) {
5763                                                         data [idx + j] = (byte) (val & 0xFF);
5764                                                         val = (val >> 8);
5765                                                 }
5766                                         }
5767                                 } else if (array_element_type == TypeManager.float_type) {
5768                                         if (!(v is Expression)){
5769                                                 element = BitConverter.GetBytes ((float) v);
5770                                                         
5771                                                 for (int j = 0; j < factor; ++j)
5772                                                         data [idx + j] = element [j];
5773                                                 if (!BitConverter.IsLittleEndian)
5774                                                         System.Array.Reverse (data, idx, 4);
5775                                         }
5776                                 } else if (array_element_type == TypeManager.double_type) {
5777                                         if (!(v is Expression)){
5778                                                 element = BitConverter.GetBytes ((double) v);
5779
5780                                                 for (int j = 0; j < factor; ++j)
5781                                                         data [idx + j] = element [j];
5782
5783                                                 // FIXME: Handle the ARM float format.
5784                                                 if (!BitConverter.IsLittleEndian)
5785                                                         System.Array.Reverse (data, idx, 8);
5786                                         }
5787                                 } else if (array_element_type == TypeManager.char_type){
5788                                         if (!(v is Expression)){
5789                                                 int val = (int) ((char) v);
5790                                                 
5791                                                 data [idx] = (byte) (val & 0xff);
5792                                                 data [idx+1] = (byte) (val >> 8);
5793                                         }
5794                                 } else if (array_element_type == TypeManager.short_type){
5795                                         if (!(v is Expression)){
5796                                                 int val = (int) ((short) v);
5797                                         
5798                                                 data [idx] = (byte) (val & 0xff);
5799                                                 data [idx+1] = (byte) (val >> 8);
5800                                         }
5801                                 } else if (array_element_type == TypeManager.ushort_type){
5802                                         if (!(v is Expression)){
5803                                                 int val = (int) ((ushort) v);
5804                                         
5805                                                 data [idx] = (byte) (val & 0xff);
5806                                                 data [idx+1] = (byte) (val >> 8);
5807                                         }
5808                                 } else if (array_element_type == TypeManager.int32_type) {
5809                                         if (!(v is Expression)){
5810                                                 int val = (int) v;
5811                                         
5812                                                 data [idx]   = (byte) (val & 0xff);
5813                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
5814                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
5815                                                 data [idx+3] = (byte) (val >> 24);
5816                                         }
5817                                 } else if (array_element_type == TypeManager.uint32_type) {
5818                                         if (!(v is Expression)){
5819                                                 uint val = (uint) v;
5820                                         
5821                                                 data [idx]   = (byte) (val & 0xff);
5822                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
5823                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
5824                                                 data [idx+3] = (byte) (val >> 24);
5825                                         }
5826                                 } else if (array_element_type == TypeManager.sbyte_type) {
5827                                         if (!(v is Expression)){
5828                                                 sbyte val = (sbyte) v;
5829                                                 data [idx] = (byte) val;
5830                                         }
5831                                 } else if (array_element_type == TypeManager.byte_type) {
5832                                         if (!(v is Expression)){
5833                                                 byte val = (byte) v;
5834                                                 data [idx] = (byte) val;
5835                                         }
5836                                 } else if (array_element_type == TypeManager.bool_type) {
5837                                         if (!(v is Expression)){
5838                                                 bool val = (bool) v;
5839                                                 data [idx] = (byte) (val ? 1 : 0);
5840                                         }
5841                                 } else if (array_element_type == TypeManager.decimal_type){
5842                                         if (!(v is Expression)){
5843                                                 int [] bits = Decimal.GetBits ((decimal) v);
5844                                                 int p = idx;
5845
5846                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
5847                                                 int [] nbits = new int [4];
5848                                                 nbits [0] = bits [3];
5849                                                 nbits [1] = bits [2];
5850                                                 nbits [2] = bits [0];
5851                                                 nbits [3] = bits [1];
5852                                                 
5853                                                 for (int j = 0; j < 4; j++){
5854                                                         data [p++] = (byte) (nbits [j] & 0xff);
5855                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5856                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5857                                                         data [p++] = (byte) (nbits [j] >> 24);
5858                                                 }
5859                                         }
5860                                 } else
5861                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5862
5863                                 idx += factor;
5864                         }
5865
5866                         return data;
5867                 }
5868
5869                 //
5870                 // Emits the initializers for the array
5871                 //
5872                 void EmitStaticInitializers (EmitContext ec)
5873                 {
5874                         //
5875                         // First, the static data
5876                         //
5877                         FieldBuilder fb;
5878                         ILGenerator ig = ec.ig;
5879                         
5880                         byte [] data = MakeByteBlob ();
5881
5882                         fb = RootContext.MakeStaticData (data);
5883
5884                         ig.Emit (OpCodes.Dup);
5885                         ig.Emit (OpCodes.Ldtoken, fb);
5886                         ig.Emit (OpCodes.Call,
5887                                  TypeManager.void_initializearray_array_fieldhandle);
5888                 }
5889
5890                 //
5891                 // Emits pieces of the array that can not be computed at compile
5892                 // time (variables and string locations).
5893                 //
5894                 // This always expect the top value on the stack to be the array
5895                 //
5896                 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5897                 {
5898                         ILGenerator ig = ec.ig;
5899                         int dims = bounds.Count;
5900                         int [] current_pos = new int [dims];
5901
5902                         MethodInfo set = null;
5903
5904                         if (dims != 1){
5905                                 Type [] args = new Type [dims + 1];
5906
5907                                 for (int j = 0; j < dims; j++)
5908                                         args [j] = TypeManager.int32_type;
5909                                 args [dims] = array_element_type;
5910                                 
5911                                 set = CodeGen.Module.Builder.GetArrayMethod (
5912                                         type, "Set",
5913                                         CallingConventions.HasThis | CallingConventions.Standard,
5914                                         TypeManager.void_type, args);
5915                         }
5916
5917                         for (int i = 0; i < array_data.Count; i++){
5918
5919                                 Expression e = (Expression)array_data [i];
5920
5921                                 // Constant can be initialized via StaticInitializer
5922                                 if (e != null && !(!emitConstants && e is Constant)) {
5923                                         Type etype = e.Type;
5924
5925                                         ig.Emit (OpCodes.Dup);
5926
5927                                         for (int idx = 0; idx < dims; idx++) 
5928                                                 IntConstant.EmitInt (ig, current_pos [idx]);
5929
5930                                         //
5931                                         // If we are dealing with a struct, get the
5932                                         // address of it, so we can store it.
5933                                         //
5934                                         if ((dims == 1) && etype.IsValueType &&
5935                                             (!TypeManager.IsBuiltinOrEnum (etype) ||
5936                                              etype == TypeManager.decimal_type)) {
5937                                                 if (e is New){
5938                                                         New n = (New) e;
5939
5940                                                         //
5941                                                         // Let new know that we are providing
5942                                                         // the address where to store the results
5943                                                         //
5944                                                         n.DisableTemporaryValueType ();
5945                                                 }
5946
5947                                                 ig.Emit (OpCodes.Ldelema, etype);
5948                                         }
5949
5950                                         e.Emit (ec);
5951
5952                                         if (dims == 1) {
5953                                                 bool is_stobj, has_type_arg;
5954                                                 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5955                                                 if (is_stobj)
5956                                                         ig.Emit (OpCodes.Stobj, etype);
5957                                                 else if (has_type_arg)
5958                                                         ig.Emit (op, etype);
5959                                                 else
5960                                                         ig.Emit (op);
5961                                         } else 
5962                                                 ig.Emit (OpCodes.Call, set);
5963
5964                                 }
5965                                 
5966                                 //
5967                                 // Advance counter
5968                                 //
5969                                 for (int j = dims - 1; j >= 0; j--){
5970                                         current_pos [j]++;
5971                                         if (current_pos [j] < (int) bounds [j])
5972                                                 break;
5973                                         current_pos [j] = 0;
5974                                 }
5975                         }
5976                 }
5977
5978                 void EmitArrayArguments (EmitContext ec)
5979                 {
5980                         ILGenerator ig = ec.ig;
5981                         
5982                         foreach (Argument a in arguments) {
5983                                 Type atype = a.Type;
5984                                 a.Emit (ec);
5985
5986                                 if (atype == TypeManager.uint64_type)
5987                                         ig.Emit (OpCodes.Conv_Ovf_U4);
5988                                 else if (atype == TypeManager.int64_type)
5989                                         ig.Emit (OpCodes.Conv_Ovf_I4);
5990                         }
5991                 }
5992                 
5993                 public override void Emit (EmitContext ec)
5994                 {
5995                         ILGenerator ig = ec.ig;
5996                         
5997                         EmitArrayArguments (ec);
5998                         if (arguments.Count == 1)
5999                                 ig.Emit (OpCodes.Newarr, array_element_type);
6000                         else {
6001                                 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
6002                         }
6003                         
6004                         if (initializers == null)
6005                                 return;
6006
6007                         // Emit static initializer for arrays which have contain more than 4 items and
6008                         // the static initializer will initialize at least 25% of array values.
6009                         // NOTE: const_initializers_count does not contain default constant values.
6010                         if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6011                                 TypeManager.IsPrimitiveType (array_element_type)) {
6012                                 EmitStaticInitializers (ec);
6013
6014                                 if (!only_constant_initializers)
6015                                         EmitDynamicInitializers (ec, false);
6016                         } else {
6017                                 EmitDynamicInitializers (ec, true);
6018                         }                               
6019                 }
6020
6021                 public override bool GetAttributableValue (Type valueType, out object value)
6022                 {
6023                         if (arguments.Count != 1) {
6024                                 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6025                                 return base.GetAttributableValue (null, out value);
6026                         }
6027
6028                         if (array_data == null) {
6029                                 Constant c = (Constant)((Argument)arguments [0]).Expr;
6030                                 if (c.IsDefaultValue) {
6031                                         value = Array.CreateInstance (array_element_type, 0);
6032                                         return true;
6033                                 }
6034                                 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6035                                 return base.GetAttributableValue (null, out value);
6036                         }
6037                         
6038                         Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6039                         object element_value;
6040                         for (int i = 0; i < ret.Length; ++i)
6041                         {
6042                                 Expression e = (Expression)array_data [i];
6043
6044                                 // Is null when an initializer is optimized (value == predefined value)
6045                                 if (e == null) 
6046                                         continue;
6047
6048                                 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6049                                         value = null;
6050                                         return false;
6051                                 }
6052                                 ret.SetValue (element_value, i);
6053                         }
6054                         value = ret;
6055                         return true;
6056                 }
6057                 
6058                 protected override void CloneTo (CloneContext clonectx, Expression t)
6059                 {
6060                         ArrayCreation target = (ArrayCreation) t;
6061
6062                         target.requested_base_type = requested_base_type.Clone (clonectx);
6063
6064                         if (arguments != null){
6065                                 target.arguments = new ArrayList (arguments.Count);
6066                                 foreach (Argument a in arguments)
6067                                         target.arguments.Add (a.Clone (clonectx));
6068                         }
6069
6070                         if (initializers != null){
6071                                 target.initializers = new ArrayList (initializers.Count);
6072                                 foreach (Expression initializer in initializers)
6073                                         target.initializers.Add (initializer.Clone (clonectx));
6074                         }
6075                 }
6076         }
6077         
6078         //
6079         // Represents an implicitly typed array epxression
6080         //
6081         public class ImplicitlyTypedArrayCreation : ArrayCreation
6082         {
6083                 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6084                         : base (null, rank, initializers, loc)
6085                 {
6086                         if (rank.Length > 2) {
6087                                 while (rank [++dimensions] == ',');
6088                         } else {
6089                                 dimensions = 1;
6090                         }
6091                 }
6092
6093                 public override Expression DoResolve (EmitContext ec)
6094                 {
6095                         if (type != null)
6096                                 return this;
6097
6098                         if (!ResolveInitializers (ec))
6099                                 return null;
6100
6101                         if (array_element_type == null || array_element_type == TypeManager.null_type ||
6102                                 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6103                                 arguments.Count != dimensions) {
6104                                 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6105                                 return null;
6106                         }
6107
6108                         //
6109                         // At this point we found common base type for all initializer elements
6110                         // but we have to be sure that all static initializer elements are of
6111                         // same type
6112                         //
6113                         UnifyInitializerElement (ec);
6114
6115                         type = TypeManager.GetConstructedType (array_element_type, rank);
6116                         eclass = ExprClass.Value;
6117                         return this;
6118                 }
6119
6120                 //
6121                 // Converts static initializer only
6122                 //
6123                 void UnifyInitializerElement (EmitContext ec)
6124                 {
6125                         for (int i = 0; i < array_data.Count; ++i) {
6126                                 Expression e = (Expression)array_data[i];
6127                                 if (e != null)
6128                                         array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6129                         }
6130                 }
6131
6132                 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6133                 {
6134                         element = element.Resolve (ec);
6135                         if (element == null)
6136                                 return null;
6137                         
6138                         if (array_element_type == null) {
6139                                 array_element_type = element.Type;
6140                                 return element;
6141                         }
6142
6143                         if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6144                                 return element;
6145                         }
6146
6147                         if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6148                                 array_element_type = element.Type;
6149                                 return element;
6150                         }
6151
6152                         element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6153                         return element;
6154                 }
6155         }       
6156         
6157         public sealed class CompilerGeneratedThis : This
6158         {
6159                 public static This Instance = new CompilerGeneratedThis ();
6160
6161                 private CompilerGeneratedThis ()
6162                         : base (Location.Null)
6163                 {
6164                 }
6165
6166                 public override Expression DoResolve (EmitContext ec)
6167                 {
6168                         eclass = ExprClass.Variable;
6169                         type = ec.ContainerType;
6170                         variable = new SimpleThis (type);
6171                         return this;
6172                 }
6173         }
6174         
6175         /// <summary>
6176         ///   Represents the `this' construct
6177         /// </summary>
6178
6179         public class This : VariableReference, IVariable
6180         {
6181                 Block block;
6182                 VariableInfo variable_info;
6183                 protected Variable variable;
6184                 bool is_struct;
6185
6186                 public This (Block block, Location loc)
6187                 {
6188                         this.loc = loc;
6189                         this.block = block;
6190                 }
6191
6192                 public This (Location loc)
6193                 {
6194                         this.loc = loc;
6195                 }
6196
6197                 public VariableInfo VariableInfo {
6198                         get { return variable_info; }
6199                 }
6200
6201                 public bool VerifyFixed ()
6202                 {
6203                         return !TypeManager.IsValueType (Type);
6204                 }
6205
6206                 public override bool IsRef {
6207                         get { return is_struct; }
6208                 }
6209
6210                 public override Variable Variable {
6211                         get { return variable; }
6212                 }
6213
6214                 public bool ResolveBase (EmitContext ec)
6215                 {
6216                         eclass = ExprClass.Variable;
6217
6218                         if (ec.TypeContainer.CurrentType != null)
6219                                 type = ec.TypeContainer.CurrentType;
6220                         else
6221                                 type = ec.ContainerType;
6222
6223                         is_struct = ec.TypeContainer is Struct;
6224
6225                         if (ec.IsStatic) {
6226                                 Error (26, "Keyword `this' is not valid in a static property, " +
6227                                        "static method, or static field initializer");
6228                                 return false;
6229                         }
6230
6231                         if (block != null) {
6232                                 if (block.Toplevel.ThisVariable != null)
6233                                         variable_info = block.Toplevel.ThisVariable.VariableInfo;
6234
6235                                 AnonymousContainer am = ec.CurrentAnonymousMethod;
6236                                 if (is_struct && (am != null) && !am.IsIterator) {
6237                                         Report.Error (1673, loc, "Anonymous methods inside structs " +
6238                                                       "cannot access instance members of `this'. " +
6239                                                       "Consider copying `this' to a local variable " +
6240                                                       "outside the anonymous method and using the " +
6241                                                       "local instead.");
6242                                         return false;
6243                                 }
6244
6245                                 RootScopeInfo host = block.Toplevel.RootScope;
6246                                 if ((host != null) && !ec.IsConstructor &&
6247                                     (!is_struct || host.IsIterator)) {
6248                                         variable = host.CaptureThis ();
6249                                         type = variable.Type;
6250                                         is_struct = false;
6251                                 }
6252                         }
6253
6254                         if (variable == null)
6255                                 variable = new SimpleThis (type);
6256                         
6257                         return true;
6258                 }
6259
6260                 //
6261                 // Called from Invocation to check if the invocation is correct
6262                 //
6263                 public bool CheckThisUsage (EmitContext ec)
6264                 {
6265                         if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6266                             !variable_info.IsAssigned (ec)) {
6267                                 Error (188, "The `this' object cannot be used before all of its " +
6268                                        "fields are assigned to");
6269                                 variable_info.SetAssigned (ec);
6270                                 return false;
6271                         }
6272
6273                         return true;
6274                 }
6275                 
6276                 public override Expression DoResolve (EmitContext ec)
6277                 {
6278                         if (!ResolveBase (ec))
6279                                 return null;
6280
6281
6282                         if (ec.IsFieldInitializer) {
6283                                 Error (27, "Keyword `this' is not available in the current context");
6284                                 return null;
6285                         }
6286
6287                         return this;
6288                 }
6289
6290                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6291                 {
6292                         if (!ResolveBase (ec))
6293                                 return null;
6294
6295                         if (variable_info != null)
6296                                 variable_info.SetAssigned (ec);
6297                         
6298                         if (ec.TypeContainer is Class){
6299                                 Error (1604, "Cannot assign to 'this' because it is read-only");
6300                                 return null;
6301                         }
6302
6303                         return this;
6304                 }
6305                 public override int GetHashCode()
6306                 {
6307                         return block.GetHashCode ();
6308                 }
6309
6310                 public override bool Equals (object obj)
6311                 {
6312                         This t = obj as This;
6313                         if (t == null)
6314                                 return false;
6315
6316                         return block == t.block;
6317                 }
6318
6319                 protected class SimpleThis : Variable
6320                 {
6321                         Type type;
6322
6323                         public SimpleThis (Type type)
6324                         {
6325                                 this.type = type;
6326                         }
6327
6328                         public override Type Type {
6329                                 get { return type; }
6330                         }
6331
6332                         public override bool HasInstance {
6333                                 get { return false; }
6334                         }
6335
6336                         public override bool NeedsTemporary {
6337                                 get { return false; }
6338                         }
6339
6340                         public override void EmitInstance (EmitContext ec)
6341                         {
6342                                 // Do nothing.
6343                         }
6344
6345                         public override void Emit (EmitContext ec)
6346                         {
6347                                 ec.ig.Emit (OpCodes.Ldarg_0);
6348                         }
6349
6350                         public override void EmitAssign (EmitContext ec)
6351                         {
6352                                 throw new InvalidOperationException ();
6353                         }
6354
6355                         public override void EmitAddressOf (EmitContext ec)
6356                         {
6357                                 ec.ig.Emit (OpCodes.Ldarg_0);
6358                         }
6359                 }
6360
6361                 protected override void CloneTo (CloneContext clonectx, Expression t)
6362                 {
6363                         This target = (This) t;
6364
6365                         target.block = clonectx.LookupBlock (block);
6366                 }
6367         }
6368
6369         /// <summary>
6370         ///   Represents the `__arglist' construct
6371         /// </summary>
6372         public class ArglistAccess : Expression
6373         {
6374                 public ArglistAccess (Location loc)
6375                 {
6376                         this.loc = loc;
6377                 }
6378
6379                 public override Expression DoResolve (EmitContext ec)
6380                 {
6381                         eclass = ExprClass.Variable;
6382                         type = TypeManager.runtime_argument_handle_type;
6383
6384                         if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs) 
6385                         {
6386                                 Error (190, "The __arglist construct is valid only within " +
6387                                        "a variable argument method");
6388                                 return null;
6389                         }
6390
6391                         return this;
6392                 }
6393
6394                 public override void Emit (EmitContext ec)
6395                 {
6396                         ec.ig.Emit (OpCodes.Arglist);
6397                 }
6398
6399                 protected override void CloneTo (CloneContext clonectx, Expression target)
6400                 {
6401                         // nothing.
6402                 }
6403         }
6404
6405         /// <summary>
6406         ///   Represents the `__arglist (....)' construct
6407         /// </summary>
6408         public class Arglist : Expression
6409         {
6410                 Argument[] Arguments;
6411
6412                 public Arglist (Location loc)
6413                         : this (Argument.Empty, loc)
6414                 {
6415                 }
6416
6417                 public Arglist (Argument[] args, Location l)
6418                 {
6419                         Arguments = args;
6420                         loc = l;
6421                 }
6422
6423                 public Type[] ArgumentTypes {
6424                         get {
6425                                 Type[] retval = new Type [Arguments.Length];
6426                                 for (int i = 0; i < Arguments.Length; i++)
6427                                         retval [i] = Arguments [i].Type;
6428                                 return retval;
6429                         }
6430                 }
6431
6432                 public override Expression DoResolve (EmitContext ec)
6433                 {
6434                         eclass = ExprClass.Variable;
6435                         type = TypeManager.runtime_argument_handle_type;
6436
6437                         foreach (Argument arg in Arguments) {
6438                                 if (!arg.Resolve (ec, loc))
6439                                         return null;
6440                         }
6441
6442                         return this;
6443                 }
6444
6445                 public override void Emit (EmitContext ec)
6446                 {
6447                         foreach (Argument arg in Arguments)
6448                                 arg.Emit (ec);
6449                 }
6450
6451                 protected override void CloneTo (CloneContext clonectx, Expression t)
6452                 {
6453                         Arglist target = (Arglist) t;
6454
6455                         target.Arguments = new Argument [Arguments.Length];
6456                         for (int i = 0; i < Arguments.Length; i++)
6457                                 target.Arguments [i] = Arguments [i].Clone (clonectx);
6458                 }
6459         }
6460
6461         //
6462         // This produces the value that renders an instance, used by the iterators code
6463         //
6464         public class ProxyInstance : Expression, IMemoryLocation  {
6465                 public override Expression DoResolve (EmitContext ec)
6466                 {
6467                         eclass = ExprClass.Variable;
6468                         type = ec.ContainerType;
6469                         return this;
6470                 }
6471                 
6472                 public override void Emit (EmitContext ec)
6473                 {
6474                         ec.ig.Emit (OpCodes.Ldarg_0);
6475
6476                 }
6477                 
6478                 public void AddressOf (EmitContext ec, AddressOp mode)
6479                 {
6480                         ec.ig.Emit (OpCodes.Ldarg_0);
6481                 }
6482         }
6483
6484         /// <summary>
6485         ///   Implements the typeof operator
6486         /// </summary>
6487         public class TypeOf : Expression {
6488                 Expression QueriedType;
6489                 protected Type typearg;
6490                 
6491                 public TypeOf (Expression queried_type, Location l)
6492                 {
6493                         QueriedType = queried_type;
6494                         loc = l;
6495                 }
6496
6497                 public override Expression DoResolve (EmitContext ec)
6498                 {
6499                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6500                         if (texpr == null)
6501                                 return null;
6502
6503                         typearg = texpr.Type;
6504
6505                         if (typearg == TypeManager.void_type) {
6506                                 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6507                                 return null;
6508                         }
6509
6510                         if (typearg.IsPointer && !ec.InUnsafe){
6511                                 UnsafeError (loc);
6512                                 return null;
6513                         }
6514
6515                         type = TypeManager.type_type;
6516                         // Even though what is returned is a type object, it's treated as a value by the compiler.
6517                         // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6518                         eclass = ExprClass.Value;
6519                         return this;
6520                 }
6521
6522                 public override void Emit (EmitContext ec)
6523                 {
6524                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
6525                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6526                 }
6527
6528                 public override bool GetAttributableValue (Type valueType, out object value)
6529                 {
6530                         if (TypeManager.ContainsGenericParameters (typearg) &&
6531                                 !TypeManager.IsGenericTypeDefinition (typearg)) {
6532                                 Report.SymbolRelatedToPreviousError (typearg);
6533                                 Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
6534                                              TypeManager.CSharpName (typearg));
6535                                 value = null;
6536                                 return false;
6537                         }
6538
6539                         if (valueType == TypeManager.object_type) {
6540                                 value = (object)typearg;
6541                                 return true;
6542                         }
6543                         value = typearg;
6544                         return true;
6545                 }
6546
6547                 public Type TypeArgument
6548                 {
6549                         get
6550                         {
6551                                 return typearg;
6552                         }
6553                 }
6554
6555                 protected override void CloneTo (CloneContext clonectx, Expression t)
6556                 {
6557                         TypeOf target = (TypeOf) t;
6558
6559                         target.QueriedType = QueriedType.Clone (clonectx);
6560                 }
6561         }
6562
6563         /// <summary>
6564         ///   Implements the `typeof (void)' operator
6565         /// </summary>
6566         public class TypeOfVoid : TypeOf {
6567                 public TypeOfVoid (Location l) : base (null, l)
6568                 {
6569                         loc = l;
6570                 }
6571
6572                 public override Expression DoResolve (EmitContext ec)
6573                 {
6574                         type = TypeManager.type_type;
6575                         typearg = TypeManager.void_type;
6576                         // See description in TypeOf.
6577                         eclass = ExprClass.Value;
6578                         return this;
6579                 }
6580         }
6581
6582         /// <summary>
6583         ///   Implements the sizeof expression
6584         /// </summary>
6585         public class SizeOf : Expression {
6586                 readonly Expression QueriedType;
6587                 Type type_queried;
6588                 
6589                 public SizeOf (Expression queried_type, Location l)
6590                 {
6591                         this.QueriedType = queried_type;
6592                         loc = l;
6593                 }
6594
6595                 public override Expression DoResolve (EmitContext ec)
6596                 {
6597                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6598                         if (texpr == null)
6599                                 return null;
6600
6601 #if GMCS_SOURCE
6602                         if (texpr is TypeParameterExpr){
6603                                 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6604                                 return null;
6605                         }
6606 #endif
6607
6608                         type_queried = texpr.Type;
6609                         if (type_queried.IsEnum)
6610                                 type_queried = TypeManager.EnumToUnderlying (type_queried);
6611
6612                         if (type_queried == TypeManager.void_type) {
6613                                 Expression.Error_VoidInvalidInTheContext (loc);
6614                                 return null;
6615                         }
6616
6617                         int size_of = GetTypeSize (type_queried);
6618                         if (size_of > 0) {
6619                                 return new IntConstant (size_of, loc);
6620                         }
6621
6622                         if (!ec.InUnsafe) {
6623                                 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)",
6624                                          TypeManager.CSharpName (type_queried));
6625                                 return null;
6626                         }
6627
6628                         if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6629                                 return null;
6630                         }
6631                         
6632                         type = TypeManager.int32_type;
6633                         eclass = ExprClass.Value;
6634                         return this;
6635                 }
6636
6637                 public override void Emit (EmitContext ec)
6638                 {
6639                         int size = GetTypeSize (type_queried);
6640
6641                         if (size == 0)
6642                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6643                         else
6644                                 IntConstant.EmitInt (ec.ig, size);
6645                 }
6646
6647                 protected override void CloneTo (CloneContext clonectx, Expression t)
6648                 {
6649                 }
6650         }
6651
6652         /// <summary>
6653         ///   Implements the qualified-alias-member (::) expression.
6654         /// </summary>
6655         public class QualifiedAliasMember : Expression
6656         {
6657                 string alias, identifier;
6658
6659                 public QualifiedAliasMember (string alias, string identifier, Location l)
6660                 {
6661                         if (RootContext.Version == LanguageVersion.ISO_1)
6662                                 Report.FeatureIsNotISO1 (l, "namespace alias qualifier");
6663
6664                         this.alias = alias;
6665                         this.identifier = identifier;
6666                         loc = l;
6667                 }
6668
6669                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6670                 {
6671                         if (alias == "global")
6672                                 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6673
6674                         int errors = Report.Errors;
6675                         FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6676                         if (fne == null) {
6677                                 if (errors == Report.Errors)
6678                                         Report.Error (432, loc, "Alias `{0}' not found", alias);
6679                                 return null;
6680                         }
6681                         if (fne.eclass != ExprClass.Namespace) {
6682                                 if (!silent)
6683                                         Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6684                                 return null;
6685                         }
6686                         return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6687                 }
6688
6689                 public override Expression DoResolve (EmitContext ec)
6690                 {
6691                         FullNamedExpression fne;
6692                         if (alias == "global") {
6693                                 fne = RootNamespace.Global;
6694                         } else {
6695                                 int errors = Report.Errors;
6696                                 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6697                                 if (fne == null) {
6698                                         if (errors == Report.Errors)
6699                                                 Report.Error (432, loc, "Alias `{0}' not found", alias);
6700                                         return null;
6701                                 }
6702                         }
6703
6704                         Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6705                         if (retval == null)
6706                                 return null;
6707
6708                         if (!(retval is FullNamedExpression)) {
6709                                 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6710                                 return null;
6711                         }
6712
6713                         // We defer this check till the end to match the behaviour of CSC
6714                         if (fne.eclass != ExprClass.Namespace) {
6715                                 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6716                                 return null;
6717                         }
6718                         return retval;
6719                 }
6720
6721                 public override void Emit (EmitContext ec)
6722                 {
6723                         throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6724                 }
6725
6726
6727                 public override string ToString ()
6728                 {
6729                         return alias + "::" + identifier;
6730                 }
6731
6732                 public override string GetSignatureForError ()
6733                 {
6734                         return ToString ();
6735                 }
6736
6737                 protected override void CloneTo (CloneContext clonectx, Expression t)
6738                 {
6739                         // Nothing 
6740                 }
6741         }
6742
6743         /// <summary>
6744         ///   Implements the member access expression
6745         /// </summary>
6746         public class MemberAccess : Expression {
6747                 public readonly string Identifier;
6748                 Expression expr;
6749                 readonly TypeArguments args;
6750
6751                 public MemberAccess (Expression expr, string id)
6752                         : this (expr, id, expr.Location)
6753                 {
6754                 }
6755
6756                 public MemberAccess (Expression expr, string identifier, Location loc)
6757                 {
6758                         this.expr = expr;
6759                         Identifier = identifier;
6760                         this.loc = loc;
6761                 }
6762
6763                 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6764                         : this (expr, identifier, loc)
6765                 {
6766                         this.args = args;
6767                 }
6768
6769                 protected string LookupIdentifier {
6770                         get { return MemberName.MakeName (Identifier, args); }
6771                 }
6772
6773                 // TODO: this method has very poor performace for Enum fields and
6774                 // probably for other constants as well
6775                 Expression DoResolve (EmitContext ec, Expression right_side)
6776                 {
6777                         if (type != null)
6778                                 throw new Exception ();
6779
6780                         //
6781                         // Resolve the expression with flow analysis turned off, we'll do the definite
6782                         // assignment checks later.  This is because we don't know yet what the expression
6783                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6784                         // definite assignment check on the actual field and not on the whole struct.
6785                         //
6786
6787                         SimpleName original = expr as SimpleName;
6788                         Expression expr_resolved = expr.Resolve (ec,
6789                                 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6790                                 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6791
6792                         if (expr_resolved == null)
6793                                 return null;
6794
6795                         if (expr_resolved is Namespace) {
6796                                 Namespace ns = (Namespace) expr_resolved;
6797                                 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6798 #if GMCS_SOURCE
6799                                 if ((retval != null) && (args != null))
6800                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6801 #endif
6802
6803                                 if (retval == null)
6804                                         ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6805                                 return retval;
6806                         }
6807
6808                         Type expr_type = expr_resolved.Type;
6809                         if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6810                                 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6811                                 return null;
6812                         }
6813                         if (expr_type == TypeManager.anonymous_method_type){
6814                                 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6815                                 return null;
6816                         }
6817
6818                         Constant c = expr_resolved as Constant;
6819                         if (c != null && c.GetValue () == null) {
6820                                 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6821                                         "System.NullReferenceException");
6822                         }
6823
6824                         Expression member_lookup;
6825                         member_lookup = MemberLookup (
6826                                 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6827 #if GMCS_SOURCE
6828                         if ((member_lookup == null) && (args != null)) {
6829                                 member_lookup = MemberLookup (
6830                                         ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6831                         }
6832 #endif
6833                         if (member_lookup == null) {
6834                                 ExtensionMethodGroupExpr ex_method_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
6835                                 if (ex_method_lookup != null) {
6836                                         ex_method_lookup.ExtensionExpression = expr_resolved;
6837                                         return ex_method_lookup.DoResolve (ec);
6838                                 }
6839
6840                                 if (!ec.IsInProbingMode)
6841                                         MemberLookupFailed (
6842                                                 ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
6843                                 return null;
6844                         }
6845
6846                         TypeExpr texpr = member_lookup as TypeExpr;
6847                         if (texpr != null) {
6848                                 if (!(expr_resolved is TypeExpr) && 
6849                                     (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6850                                         Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6851                                                 Identifier, member_lookup.GetSignatureForError ());
6852                                         return null;
6853                                 }
6854
6855                                 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6856                                         Report.SymbolRelatedToPreviousError (member_lookup.Type);
6857                                         ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6858                                         return null;
6859                                 }
6860
6861 #if GMCS_SOURCE
6862                                 ConstructedType ct = expr_resolved as ConstructedType;
6863                                 if (ct != null) {
6864                                         //
6865                                         // When looking up a nested type in a generic instance
6866                                         // via reflection, we always get a generic type definition
6867                                         // and not a generic instance - so we have to do this here.
6868                                         //
6869                                         // See gtest-172-lib.cs and gtest-172.cs for an example.
6870                                         //
6871                                         ct = new ConstructedType (
6872                                                 member_lookup.Type, ct.TypeArguments, loc);
6873
6874                                         return ct.ResolveAsTypeStep (ec, false);
6875                                 }
6876 #endif
6877                                 return member_lookup;
6878                         }
6879
6880                         MemberExpr me = (MemberExpr) member_lookup;
6881                         member_lookup = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
6882                         if (member_lookup == null)
6883                                 return null;
6884
6885                         if (args != null) {
6886                                 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6887                                 if (mg == null)
6888                                         throw new InternalErrorException ();
6889
6890                                 return mg.ResolveGeneric (ec, args);
6891                         }
6892
6893                         if (original != null && !TypeManager.IsValueType (expr_type)) {
6894                                 me = member_lookup as MemberExpr;
6895                                 if (me != null && me.IsInstance) {
6896                                         LocalVariableReference var = expr_resolved as LocalVariableReference;
6897                                         if (var != null && !var.VerifyAssigned (ec))
6898                                                 return null;
6899                                 }
6900                         }
6901
6902                         // The following DoResolve/DoResolveLValue will do the definite assignment
6903                         // check.
6904
6905                         if (right_side != null)
6906                                 return member_lookup.DoResolveLValue (ec, right_side);
6907                         else
6908                                 return member_lookup.DoResolve (ec);
6909                 }
6910
6911                 public override Expression DoResolve (EmitContext ec)
6912                 {
6913                         return DoResolve (ec, null);
6914                 }
6915
6916                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6917                 {
6918                         return DoResolve (ec, right_side);
6919                 }
6920
6921                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6922                 {
6923                         return ResolveNamespaceOrType (ec, silent);
6924                 }
6925
6926                 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6927                 {
6928                         FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6929
6930                         if (new_expr == null)
6931                                 return null;
6932
6933                         if (new_expr is Namespace) {
6934                                 Namespace ns = (Namespace) new_expr;
6935                                 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6936 #if GMCS_SOURCE
6937                                 if ((retval != null) && (args != null))
6938                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6939 #endif
6940                                 if (!silent && retval == null)
6941                                         ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6942                                 return retval;
6943                         }
6944
6945                         TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6946                         if (tnew_expr == null)
6947                                 return null;
6948
6949                         Type expr_type = tnew_expr.Type;
6950
6951                         if (expr_type.IsPointer){
6952                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
6953                                        TypeManager.CSharpName (expr_type) + ")");
6954                                 return null;
6955                         }
6956
6957                         Expression member_lookup = MemberLookup (
6958                                 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6959                                 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6960                         if (member_lookup == null) {
6961                                 if (silent)
6962                                         return null;
6963
6964                                 member_lookup = MemberLookup(
6965                                     rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6966                                         MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6967
6968                                 if (member_lookup == null) {
6969                                         Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6970                                                       Identifier, new_expr.GetSignatureForError ());
6971                                 } else {
6972                                 // TODO: Report.SymbolRelatedToPreviousError
6973                                     member_lookup.Error_UnexpectedKind (null, "type", loc);
6974                                 }
6975                                 return null;
6976                         }
6977
6978                         TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6979                         if (texpr == null)
6980                                 return null;
6981
6982 #if GMCS_SOURCE
6983                         TypeArguments the_args = args;
6984                         if (TypeManager.HasGenericArguments (expr_type)) {
6985                                 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
6986
6987                                 TypeArguments new_args = new TypeArguments (loc);
6988                                 foreach (Type decl in decl_args)
6989                                         new_args.Add (new TypeExpression (decl, loc));
6990
6991                                 if (args != null)
6992                                         new_args.Add (args);
6993
6994                                 the_args = new_args;
6995                         }
6996
6997                         if (the_args != null) {
6998                                 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
6999                                 return ctype.ResolveAsTypeStep (rc, false);
7000                         }
7001 #endif
7002
7003                         return texpr;
7004                 }
7005
7006                 public override void Emit (EmitContext ec)
7007                 {
7008                         throw new Exception ("Should not happen");
7009                 }
7010
7011                 public override string ToString ()
7012                 {
7013                         return expr + "." + MemberName.MakeName (Identifier, args);
7014                 }
7015
7016                 public override string GetSignatureForError ()
7017                 {
7018                         return expr.GetSignatureForError () + "." + Identifier;
7019                 }
7020
7021                 protected override void CloneTo (CloneContext clonectx, Expression t)
7022                 {
7023                         MemberAccess target = (MemberAccess) t;
7024
7025                         target.expr = expr.Clone (clonectx);
7026                 }
7027         }
7028
7029         /// <summary>
7030         ///   Implements checked expressions
7031         /// </summary>
7032         public class CheckedExpr : Expression {
7033
7034                 public Expression Expr;
7035
7036                 public CheckedExpr (Expression e, Location l)
7037                 {
7038                         Expr = e;
7039                         loc = l;
7040                 }
7041
7042                 public override Expression DoResolve (EmitContext ec)
7043                 {
7044                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7045                                 Expr = Expr.Resolve (ec);
7046                         
7047                         if (Expr == null)
7048                                 return null;
7049
7050                         if (Expr is Constant)
7051                                 return Expr;
7052                         
7053                         eclass = Expr.eclass;
7054                         type = Expr.Type;
7055                         return this;
7056                 }
7057
7058                 public override void Emit (EmitContext ec)
7059                 {
7060                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7061                                 Expr.Emit (ec);
7062                 }
7063
7064                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7065                 {
7066                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7067                                 Expr.EmitBranchable (ec, target, onTrue);
7068                 }
7069
7070                 protected override void CloneTo (CloneContext clonectx, Expression t)
7071                 {
7072                         CheckedExpr target = (CheckedExpr) t;
7073
7074                         target.Expr = Expr.Clone (clonectx);
7075                 }
7076         }
7077
7078         /// <summary>
7079         ///   Implements the unchecked expression
7080         /// </summary>
7081         public class UnCheckedExpr : Expression {
7082
7083                 public Expression Expr;
7084
7085                 public UnCheckedExpr (Expression e, Location l)
7086                 {
7087                         Expr = e;
7088                         loc = l;
7089                 }
7090
7091                 public override Expression DoResolve (EmitContext ec)
7092                 {
7093                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7094                                 Expr = Expr.Resolve (ec);
7095
7096                         if (Expr == null)
7097                                 return null;
7098
7099                         if (Expr is Constant)
7100                                 return Expr;
7101                         
7102                         eclass = Expr.eclass;
7103                         type = Expr.Type;
7104                         return this;
7105                 }
7106
7107                 public override void Emit (EmitContext ec)
7108                 {
7109                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7110                                 Expr.Emit (ec);
7111                 }
7112                 
7113                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7114                 {
7115                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7116                                 Expr.EmitBranchable (ec, target, onTrue);
7117                 }
7118
7119                 protected override void CloneTo (CloneContext clonectx, Expression t)
7120                 {
7121                         UnCheckedExpr target = (UnCheckedExpr) t;
7122
7123                         target.Expr = Expr.Clone (clonectx);
7124                 }
7125         }
7126
7127         /// <summary>
7128         ///   An Element Access expression.
7129         ///
7130         ///   During semantic analysis these are transformed into 
7131         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7132         /// </summary>
7133         public class ElementAccess : Expression {
7134                 public ArrayList  Arguments;
7135                 public Expression Expr;
7136                 
7137                 public ElementAccess (Expression e, ArrayList e_list)
7138                 {
7139                         Expr = e;
7140
7141                         loc  = e.Location;
7142                         
7143                         if (e_list == null)
7144                                 return;
7145                         
7146                         Arguments = new ArrayList ();
7147                         foreach (Expression tmp in e_list)
7148                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7149                         
7150                 }
7151
7152                 bool CommonResolve (EmitContext ec)
7153                 {
7154                         Expr = Expr.Resolve (ec);
7155
7156                         if (Arguments == null)
7157                                 return false;
7158
7159                         foreach (Argument a in Arguments){
7160                                 if (!a.Resolve (ec, loc))
7161                                         return false;
7162                         }
7163
7164                         return Expr != null;
7165                 }
7166
7167                 Expression MakePointerAccess (EmitContext ec, Type t)
7168                 {
7169                         if (t == TypeManager.void_ptr_type){
7170                                 Error (242, "The array index operation is not valid on void pointers");
7171                                 return null;
7172                         }
7173                         if (Arguments.Count != 1){
7174                                 Error (196, "A pointer must be indexed by only one value");
7175                                 return null;
7176                         }
7177                         Expression p;
7178
7179                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7180                         if (p == null)
7181                                 return null;
7182                         return new Indirection (p, loc).Resolve (ec);
7183                 }
7184                 
7185                 public override Expression DoResolve (EmitContext ec)
7186                 {
7187                         if (!CommonResolve (ec))
7188                                 return null;
7189
7190                         //
7191                         // We perform some simple tests, and then to "split" the emit and store
7192                         // code we create an instance of a different class, and return that.
7193                         //
7194                         // I am experimenting with this pattern.
7195                         //
7196                         Type t = Expr.Type;
7197
7198                         if (t == TypeManager.array_type){
7199                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7200                                 return null;
7201                         }
7202                         
7203                         if (t.IsArray)
7204                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7205                         if (t.IsPointer)
7206                                 return MakePointerAccess (ec, t);
7207
7208                         FieldExpr fe = Expr as FieldExpr;
7209                         if (fe != null) {
7210                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7211                                 if (ff != null) {
7212                                         return MakePointerAccess (ec, ff.ElementType);
7213                                 }
7214                         }
7215                         return (new IndexerAccess (this, loc)).Resolve (ec);
7216                 }
7217
7218                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7219                 {
7220                         if (!CommonResolve (ec))
7221                                 return null;
7222
7223                         Type t = Expr.Type;
7224                         if (t.IsArray)
7225                                 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7226
7227                         if (t.IsPointer)
7228                                 return MakePointerAccess (ec, t);
7229
7230                         return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7231                 }
7232                 
7233                 public override void Emit (EmitContext ec)
7234                 {
7235                         throw new Exception ("Should never be reached");
7236                 }
7237
7238                 protected override void CloneTo (CloneContext clonectx, Expression t)
7239                 {
7240                         ElementAccess target = (ElementAccess) t;
7241
7242                         target.Expr = Expr.Clone (clonectx);
7243                         target.Arguments = new ArrayList (Arguments.Count);
7244                         foreach (Argument a in Arguments)
7245                                 target.Arguments.Add (a.Clone (clonectx));
7246                 }
7247         }
7248
7249         /// <summary>
7250         ///   Implements array access 
7251         /// </summary>
7252         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7253                 //
7254                 // Points to our "data" repository
7255                 //
7256                 ElementAccess ea;
7257
7258                 LocalTemporary temp;
7259                 bool prepared;
7260                 
7261                 public ArrayAccess (ElementAccess ea_data, Location l)
7262                 {
7263                         ea = ea_data;
7264                         eclass = ExprClass.Variable;
7265                         loc = l;
7266                 }
7267
7268                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7269                 {
7270                         return DoResolve (ec);
7271                 }
7272
7273                 public override Expression DoResolve (EmitContext ec)
7274                 {
7275 #if false
7276                         ExprClass eclass = ea.Expr.eclass;
7277
7278                         // As long as the type is valid
7279                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7280                               eclass == ExprClass.Value)) {
7281                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7282                                 return null;
7283                         }
7284 #endif
7285
7286                         Type t = ea.Expr.Type;
7287                         if (t.GetArrayRank () != ea.Arguments.Count){
7288                                 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7289                                           ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7290                                 return null;
7291                         }
7292
7293                         type = TypeManager.GetElementType (t);
7294                         if (type.IsPointer && !ec.InUnsafe){
7295                                 UnsafeError (ea.Location);
7296                                 return null;
7297                         }
7298
7299                         foreach (Argument a in ea.Arguments){
7300                                 Type argtype = a.Type;
7301
7302                                 if (argtype == TypeManager.int32_type ||
7303                                     argtype == TypeManager.uint32_type ||
7304                                     argtype == TypeManager.int64_type ||
7305                                     argtype == TypeManager.uint64_type) {
7306                                         Constant c = a.Expr as Constant;
7307                                         if (c != null && c.IsNegative) {
7308                                                 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7309                                         }
7310                                         continue;
7311                                 }
7312
7313                                 //
7314                                 // Mhm.  This is strage, because the Argument.Type is not the same as
7315                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7316                                 //
7317                                 // Wonder if I will run into trouble for this.
7318                                 //
7319                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7320                                 if (a.Expr == null)
7321                                         return null;
7322                         }
7323                         
7324                         eclass = ExprClass.Variable;
7325
7326                         return this;
7327                 }
7328
7329                 /// <summary>
7330                 ///    Emits the right opcode to load an object of Type `t'
7331                 ///    from an array of T
7332                 /// </summary>
7333                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7334                 {
7335                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7336                                 ig.Emit (OpCodes.Ldelem_U1);
7337                         else if (type == TypeManager.sbyte_type)
7338                                 ig.Emit (OpCodes.Ldelem_I1);
7339                         else if (type == TypeManager.short_type)
7340                                 ig.Emit (OpCodes.Ldelem_I2);
7341                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7342                                 ig.Emit (OpCodes.Ldelem_U2);
7343                         else if (type == TypeManager.int32_type)
7344                                 ig.Emit (OpCodes.Ldelem_I4);
7345                         else if (type == TypeManager.uint32_type)
7346                                 ig.Emit (OpCodes.Ldelem_U4);
7347                         else if (type == TypeManager.uint64_type)
7348                                 ig.Emit (OpCodes.Ldelem_I8);
7349                         else if (type == TypeManager.int64_type)
7350                                 ig.Emit (OpCodes.Ldelem_I8);
7351                         else if (type == TypeManager.float_type)
7352                                 ig.Emit (OpCodes.Ldelem_R4);
7353                         else if (type == TypeManager.double_type)
7354                                 ig.Emit (OpCodes.Ldelem_R8);
7355                         else if (type == TypeManager.intptr_type)
7356                                 ig.Emit (OpCodes.Ldelem_I);
7357                         else if (TypeManager.IsEnumType (type)){
7358                                 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7359                         } else if (type.IsValueType){
7360                                 ig.Emit (OpCodes.Ldelema, type);
7361                                 ig.Emit (OpCodes.Ldobj, type);
7362 #if GMCS_SOURCE
7363                         } else if (type.IsGenericParameter) {
7364                                 ig.Emit (OpCodes.Ldelem, type);
7365 #endif
7366                         } else if (type.IsPointer)
7367                                 ig.Emit (OpCodes.Ldelem_I);
7368                         else
7369                                 ig.Emit (OpCodes.Ldelem_Ref);
7370                 }
7371
7372                 /// <summary>
7373                 ///    Returns the right opcode to store an object of Type `t'
7374                 ///    from an array of T.  
7375                 /// </summary>
7376                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7377                 {
7378                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
7379                         has_type_arg = false; is_stobj = false;
7380                         t = TypeManager.TypeToCoreType (t);
7381                         if (TypeManager.IsEnumType (t))
7382                                 t = TypeManager.EnumToUnderlying (t);
7383                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7384                             t == TypeManager.bool_type)
7385                                 return OpCodes.Stelem_I1;
7386                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7387                                  t == TypeManager.char_type)
7388                                 return OpCodes.Stelem_I2;
7389                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7390                                 return OpCodes.Stelem_I4;
7391                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7392                                 return OpCodes.Stelem_I8;
7393                         else if (t == TypeManager.float_type)
7394                                 return OpCodes.Stelem_R4;
7395                         else if (t == TypeManager.double_type)
7396                                 return OpCodes.Stelem_R8;
7397                         else if (t == TypeManager.intptr_type) {
7398                                 has_type_arg = true;
7399                                 is_stobj = true;
7400                                 return OpCodes.Stobj;
7401                         } else if (t.IsValueType) {
7402                                 has_type_arg = true;
7403                                 is_stobj = true;
7404                                 return OpCodes.Stobj;
7405 #if GMCS_SOURCE
7406                         } else if (t.IsGenericParameter) {
7407                                 has_type_arg = true;
7408                                 return OpCodes.Stelem;
7409 #endif
7410
7411                         } else if (t.IsPointer)
7412                                 return OpCodes.Stelem_I;
7413                         else
7414                                 return OpCodes.Stelem_Ref;
7415                 }
7416
7417                 MethodInfo FetchGetMethod ()
7418                 {
7419                         ModuleBuilder mb = CodeGen.Module.Builder;
7420                         int arg_count = ea.Arguments.Count;
7421                         Type [] args = new Type [arg_count];
7422                         MethodInfo get;
7423                         
7424                         for (int i = 0; i < arg_count; i++){
7425                                 //args [i++] = a.Type;
7426                                 args [i] = TypeManager.int32_type;
7427                         }
7428                         
7429                         get = mb.GetArrayMethod (
7430                                 ea.Expr.Type, "Get",
7431                                 CallingConventions.HasThis |
7432                                 CallingConventions.Standard,
7433                                 type, args);
7434                         return get;
7435                 }
7436                                 
7437
7438                 MethodInfo FetchAddressMethod ()
7439                 {
7440                         ModuleBuilder mb = CodeGen.Module.Builder;
7441                         int arg_count = ea.Arguments.Count;
7442                         Type [] args = new Type [arg_count];
7443                         MethodInfo address;
7444                         Type ret_type;
7445                         
7446                         ret_type = TypeManager.GetReferenceType (type);
7447                         
7448                         for (int i = 0; i < arg_count; i++){
7449                                 //args [i++] = a.Type;
7450                                 args [i] = TypeManager.int32_type;
7451                         }
7452                         
7453                         address = mb.GetArrayMethod (
7454                                 ea.Expr.Type, "Address",
7455                                 CallingConventions.HasThis |
7456                                 CallingConventions.Standard,
7457                                 ret_type, args);
7458
7459                         return address;
7460                 }
7461
7462                 //
7463                 // Load the array arguments into the stack.
7464                 //
7465                 // If we have been requested to cache the values (cached_locations array
7466                 // initialized), then load the arguments the first time and store them
7467                 // in locals.  otherwise load from local variables.
7468                 //
7469                 void LoadArrayAndArguments (EmitContext ec)
7470                 {
7471                         ILGenerator ig = ec.ig;
7472                         
7473                         ea.Expr.Emit (ec);
7474                         foreach (Argument a in ea.Arguments){
7475                                 Type argtype = a.Expr.Type;
7476                                 
7477                                 a.Expr.Emit (ec);
7478                                 
7479                                 if (argtype == TypeManager.int64_type)
7480                                         ig.Emit (OpCodes.Conv_Ovf_I);
7481                                 else if (argtype == TypeManager.uint64_type)
7482                                         ig.Emit (OpCodes.Conv_Ovf_I_Un);
7483                         }
7484                 }
7485
7486                 public void Emit (EmitContext ec, bool leave_copy)
7487                 {
7488                         int rank = ea.Expr.Type.GetArrayRank ();
7489                         ILGenerator ig = ec.ig;
7490
7491                         if (!prepared) {
7492                                 LoadArrayAndArguments (ec);
7493                                 
7494                                 if (rank == 1)
7495                                         EmitLoadOpcode (ig, type);
7496                                 else {
7497                                         MethodInfo method;
7498                                         
7499                                         method = FetchGetMethod ();
7500                                         ig.Emit (OpCodes.Call, method);
7501                                 }
7502                         } else
7503                                 LoadFromPtr (ec.ig, this.type);
7504                         
7505                         if (leave_copy) {
7506                                 ec.ig.Emit (OpCodes.Dup);
7507                                 temp = new LocalTemporary (this.type);
7508                                 temp.Store (ec);
7509                         }
7510                 }
7511                 
7512                 public override void Emit (EmitContext ec)
7513                 {
7514                         Emit (ec, false);
7515                 }
7516
7517                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7518                 {
7519                         int rank = ea.Expr.Type.GetArrayRank ();
7520                         ILGenerator ig = ec.ig;
7521                         Type t = source.Type;
7522                         prepared = prepare_for_load;
7523
7524                         if (prepare_for_load) {
7525                                 AddressOf (ec, AddressOp.LoadStore);
7526                                 ec.ig.Emit (OpCodes.Dup);
7527                                 source.Emit (ec);
7528                                 if (leave_copy) {
7529                                         ec.ig.Emit (OpCodes.Dup);
7530                                         temp = new LocalTemporary (this.type);
7531                                         temp.Store (ec);
7532                                 }
7533                                 StoreFromPtr (ec.ig, t);
7534                                 
7535                                 if (temp != null) {
7536                                         temp.Emit (ec);
7537                                         temp.Release (ec);
7538                                 }
7539                                 
7540                                 return;
7541                         }
7542                         
7543                         LoadArrayAndArguments (ec);
7544
7545                         if (rank == 1) {
7546                                 bool is_stobj, has_type_arg;
7547                                 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7548                                 //
7549                                 // The stobj opcode used by value types will need
7550                                 // an address on the stack, not really an array/array
7551                                 // pair
7552                                 //
7553                                 if (is_stobj)
7554                                         ig.Emit (OpCodes.Ldelema, t);
7555                                 
7556                                 source.Emit (ec);
7557                                 if (leave_copy) {
7558                                         ec.ig.Emit (OpCodes.Dup);
7559                                         temp = new LocalTemporary (this.type);
7560                                         temp.Store (ec);
7561                                 }
7562                                 
7563                                 if (is_stobj)
7564                                         ig.Emit (OpCodes.Stobj, t);
7565                                 else if (has_type_arg)
7566                                         ig.Emit (op, t);
7567                                 else
7568                                         ig.Emit (op);
7569                         } else {
7570                                 ModuleBuilder mb = CodeGen.Module.Builder;
7571                                 int arg_count = ea.Arguments.Count;
7572                                 Type [] args = new Type [arg_count + 1];
7573                                 MethodInfo set;
7574                                 
7575                                 source.Emit (ec);
7576                                 if (leave_copy) {
7577                                         ec.ig.Emit (OpCodes.Dup);
7578                                         temp = new LocalTemporary (this.type);
7579                                         temp.Store (ec);
7580                                 }
7581                                 
7582                                 for (int i = 0; i < arg_count; i++){
7583                                         //args [i++] = a.Type;
7584                                         args [i] = TypeManager.int32_type;
7585                                 }
7586
7587                                 args [arg_count] = type;
7588                                 
7589                                 set = mb.GetArrayMethod (
7590                                         ea.Expr.Type, "Set",
7591                                         CallingConventions.HasThis |
7592                                         CallingConventions.Standard,
7593                                         TypeManager.void_type, args);
7594                                 
7595                                 ig.Emit (OpCodes.Call, set);
7596                         }
7597                         
7598                         if (temp != null) {
7599                                 temp.Emit (ec);
7600                                 temp.Release (ec);
7601                         }
7602                 }
7603
7604                 public void AddressOf (EmitContext ec, AddressOp mode)
7605                 {
7606                         int rank = ea.Expr.Type.GetArrayRank ();
7607                         ILGenerator ig = ec.ig;
7608
7609                         LoadArrayAndArguments (ec);
7610
7611                         if (rank == 1){
7612                                 ig.Emit (OpCodes.Ldelema, type);
7613                         } else {
7614                                 MethodInfo address = FetchAddressMethod ();
7615                                 ig.Emit (OpCodes.Call, address);
7616                         }
7617                 }
7618
7619                 public void EmitGetLength (EmitContext ec, int dim)
7620                 {
7621                         int rank = ea.Expr.Type.GetArrayRank ();
7622                         ILGenerator ig = ec.ig;
7623
7624                         ea.Expr.Emit (ec);
7625                         if (rank == 1) {
7626                                 ig.Emit (OpCodes.Ldlen);
7627                                 ig.Emit (OpCodes.Conv_I4);
7628                         } else {
7629                                 IntLiteral.EmitInt (ig, dim);
7630                                 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7631                         }
7632                 }
7633         }
7634         
7635         class Indexers {
7636                 // note that the ArrayList itself in mutable.  We just can't assign to 'Properties' again.
7637                 public readonly ArrayList Properties;
7638                 static Indexers empty;
7639
7640                 public struct Indexer {
7641                         public readonly PropertyInfo PropertyInfo;
7642                         public readonly MethodInfo Getter, Setter;
7643
7644                         public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7645                         {
7646                                 this.PropertyInfo = property_info;
7647                                 this.Getter = get;
7648                                 this.Setter = set;
7649                         }
7650                 }
7651
7652                 static Indexers ()
7653                 {
7654                         empty = new Indexers (null);
7655                 }
7656
7657                 Indexers (ArrayList array)
7658                 {
7659                         Properties = array;
7660                 }
7661
7662                 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
7663                 {
7664                         bool dummy;
7665                         if (mi == null)
7666                                 return;
7667                         foreach (PropertyInfo property in mi){
7668                                 MethodInfo get, set;
7669                                 
7670                                 get = property.GetGetMethod (true);
7671                                 set = property.GetSetMethod (true);
7672                                 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
7673                                         get = null;
7674                                 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
7675                                         set = null;
7676                                 if (get != null || set != null) {
7677                                         if (ix == empty)
7678                                                 ix = new Indexers (new ArrayList ());
7679                                         ix.Properties.Add (new Indexer (property, get, set));
7680                                 }
7681                         }
7682                 }
7683
7684                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7685                 {
7686                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
7687
7688                         return TypeManager.MemberLookup (
7689                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
7690                                 BindingFlags.Public | BindingFlags.Instance |
7691                                 BindingFlags.DeclaredOnly, p_name, null);
7692                 }
7693                 
7694                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type) 
7695                 {
7696                         Indexers ix = empty;
7697
7698 #if GMCS_SOURCE
7699                         if (lookup_type.IsGenericParameter) {
7700                                 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7701                                 if (gc == null)
7702                                         return empty;
7703
7704                                 if (gc.HasClassConstraint)
7705                                         Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7706
7707                                 Type[] ifaces = gc.InterfaceConstraints;
7708                                 foreach (Type itype in ifaces)
7709                                         Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7710
7711                                 return ix;
7712                         }
7713 #endif
7714
7715                         Type copy = lookup_type;
7716                         while (copy != TypeManager.object_type && copy != null){
7717                                 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7718                                 copy = copy.BaseType;
7719                         }
7720
7721                         if (lookup_type.IsInterface) {
7722                                 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7723                                 if (ifaces != null) {
7724                                         foreach (Type itype in ifaces)
7725                                                 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7726                                 }
7727                         }
7728
7729                         return ix;
7730                 }
7731         }
7732
7733         /// <summary>
7734         ///   Expressions that represent an indexer call.
7735         /// </summary>
7736         public class IndexerAccess : Expression, IAssignMethod {
7737                 //
7738                 // Points to our "data" repository
7739                 //
7740                 MethodInfo get, set;
7741                 ArrayList set_arguments;
7742                 bool is_base_indexer;
7743
7744                 protected Type indexer_type;
7745                 protected Type current_type;
7746                 protected Expression instance_expr;
7747                 protected ArrayList arguments;
7748                 
7749                 public IndexerAccess (ElementAccess ea, Location loc)
7750                         : this (ea.Expr, false, loc)
7751                 {
7752                         this.arguments = ea.Arguments;
7753                 }
7754
7755                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7756                                          Location loc)
7757                 {
7758                         this.instance_expr = instance_expr;
7759                         this.is_base_indexer = is_base_indexer;
7760                         this.eclass = ExprClass.Value;
7761                         this.loc = loc;
7762                 }
7763
7764                 protected virtual bool CommonResolve (EmitContext ec)
7765                 {
7766                         indexer_type = instance_expr.Type;
7767                         current_type = ec.ContainerType;
7768
7769                         return true;
7770                 }
7771
7772                 public override Expression DoResolve (EmitContext ec)
7773                 {
7774                         if (!CommonResolve (ec))
7775                                 return null;
7776
7777                         //
7778                         // Step 1: Query for all `Item' *properties*.  Notice
7779                         // that the actual methods are pointed from here.
7780                         //
7781                         // This is a group of properties, piles of them.  
7782
7783                         ArrayList AllGetters = null;
7784
7785                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7786                         if (ilist.Properties != null) {
7787                                 AllGetters = new ArrayList(ilist.Properties.Count);
7788                                 foreach (Indexers.Indexer ix in ilist.Properties) {
7789                                         if (ix.Getter != null)
7790                                                 AllGetters.Add (ix.Getter);
7791                                 }
7792                         }
7793
7794                         if (AllGetters == null) {
7795                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7796                                         TypeManager.CSharpName (indexer_type));
7797                                 return null;
7798                         }
7799
7800                         if (AllGetters.Count == 0) {
7801                                 // FIXME: we cannot simply select first one as the error message is missleading when
7802                                 // multiple indexers exist
7803                                 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
7804                                 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7805                                         TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
7806                                 return null;
7807                         }
7808
7809                         get = (MethodInfo)new MethodGroupExpr (AllGetters, loc).OverloadResolve (ec,
7810                                         arguments, false, loc);
7811
7812                         if (get == null) {
7813                                 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7814                                 return null;
7815                         }
7816
7817                         //
7818                         // Only base will allow this invocation to happen.
7819                         //
7820                         if (get.IsAbstract && this is BaseIndexerAccess){
7821                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
7822                                 return null;
7823                         }
7824
7825                         type = get.ReturnType;
7826                         if (type.IsPointer && !ec.InUnsafe){
7827                                 UnsafeError (loc);
7828                                 return null;
7829                         }
7830
7831                         instance_expr.CheckMarshalByRefAccess ();
7832                         
7833                         eclass = ExprClass.IndexerAccess;
7834                         return this;
7835                 }
7836
7837                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7838                 {
7839                         if (right_side == EmptyExpression.OutAccess) {
7840                                 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7841                                               GetSignatureForError ());
7842                                 return null;
7843                         }
7844
7845                         // if the indexer returns a value type, and we try to set a field in it
7846                         if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7847                                 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7848                                               GetSignatureForError ());
7849                                 return null;
7850                         }
7851
7852                         ArrayList AllSetters = new ArrayList();
7853                         if (!CommonResolve (ec))
7854                                 return null;
7855
7856                         bool found_any = false, found_any_setters = false;
7857
7858                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7859                         if (ilist.Properties != null) {
7860                                 found_any = true;
7861                                 foreach (Indexers.Indexer ix in ilist.Properties) {
7862                                         if (ix.Setter != null)
7863                                                 AllSetters.Add (ix.Setter);
7864                                 }
7865                         }
7866                         if (AllSetters.Count > 0) {
7867                                 found_any_setters = true;
7868                                 set_arguments = (ArrayList) arguments.Clone ();
7869                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7870                                 set = (MethodInfo)(new MethodGroupExpr (AllSetters, loc)).OverloadResolve (
7871                                         ec,
7872                                         set_arguments, false, loc);
7873                         }
7874
7875                         if (!found_any) {
7876                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7877                                               TypeManager.CSharpName (indexer_type));
7878                                 return null;
7879                         }
7880
7881                         if (!found_any_setters) {
7882                                 Error (154, "indexer can not be used in this context, because " +
7883                                        "it lacks a `set' accessor");
7884                                 return null;
7885                         }
7886
7887                         if (set == null) {
7888                                 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7889                                 return null;
7890                         }
7891
7892                         //
7893                         // Only base will allow this invocation to happen.
7894                         //
7895                         if (set.IsAbstract && this is BaseIndexerAccess){
7896                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
7897                                 return null;
7898                         }
7899
7900                         //
7901                         // Now look for the actual match in the list of indexers to set our "return" type
7902                         //
7903                         type = TypeManager.void_type;   // default value
7904                         foreach (Indexers.Indexer ix in ilist.Properties){
7905                                 if (ix.Setter == set){
7906                                         type = ix.PropertyInfo.PropertyType;
7907                                         break;
7908                                 }
7909                         }
7910
7911                         instance_expr.CheckMarshalByRefAccess ();
7912
7913                         eclass = ExprClass.IndexerAccess;
7914                         return this;
7915                 }
7916                 
7917                 bool prepared = false;
7918                 LocalTemporary temp;
7919                 
7920                 public void Emit (EmitContext ec, bool leave_copy)
7921                 {
7922                         Invocation.EmitCall (ec, is_base_indexer, instance_expr, get, arguments, loc, prepared, false);
7923                         if (leave_copy) {
7924                                 ec.ig.Emit (OpCodes.Dup);
7925                                 temp = new LocalTemporary (Type);
7926                                 temp.Store (ec);
7927                         }
7928                 }
7929                 
7930                 //
7931                 // source is ignored, because we already have a copy of it from the
7932                 // LValue resolution and we have already constructed a pre-cached
7933                 // version of the arguments (ea.set_arguments);
7934                 //
7935                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7936                 {
7937                         prepared = prepare_for_load;
7938                         Argument a = (Argument) set_arguments [set_arguments.Count - 1];
7939                         
7940                         if (prepared) {
7941                                 source.Emit (ec);
7942                                 if (leave_copy) {
7943                                         ec.ig.Emit (OpCodes.Dup);
7944                                         temp = new LocalTemporary (Type);
7945                                         temp.Store (ec);
7946                                 }
7947                         } else if (leave_copy) {
7948                                 temp = new LocalTemporary (Type);
7949                                 source.Emit (ec);
7950                                 temp.Store (ec);
7951                                 a.Expr = temp;
7952                         }
7953                         
7954                         Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, set_arguments, loc, false, prepared);
7955                         
7956                         if (temp != null) {
7957                                 temp.Emit (ec);
7958                                 temp.Release (ec);
7959                         }
7960                 }
7961                 
7962                 
7963                 public override void Emit (EmitContext ec)
7964                 {
7965                         Emit (ec, false);
7966                 }
7967
7968                 public override string GetSignatureForError ()
7969                 {
7970                         // FIXME: print the argument list of the indexer
7971                         return instance_expr.GetSignatureForError () + ".this[...]";
7972                 }
7973
7974                 protected override void CloneTo (CloneContext clonectx, Expression t)
7975                 {
7976                         IndexerAccess target = (IndexerAccess) t;
7977
7978                         if (arguments != null){
7979                                 target.arguments = new ArrayList ();
7980                                 foreach (Argument a in arguments)
7981                                         target.arguments.Add (a.Clone (clonectx));
7982                         }
7983                         if (instance_expr != null)
7984                                 target.instance_expr = instance_expr.Clone (clonectx);
7985                 }
7986         }
7987
7988         /// <summary>
7989         ///   The base operator for method names
7990         /// </summary>
7991         public class BaseAccess : Expression {
7992                 public readonly string Identifier;
7993                 TypeArguments args;
7994
7995                 public BaseAccess (string member, Location l)
7996                 {
7997                         this.Identifier = member;
7998                         loc = l;
7999                 }
8000
8001                 public BaseAccess (string member, TypeArguments args, Location l)
8002                         : this (member, l)
8003                 {
8004                         this.args = args;
8005                 }
8006
8007                 public override Expression DoResolve (EmitContext ec)
8008                 {
8009                         Expression c = CommonResolve (ec);
8010
8011                         if (c == null)
8012                                 return null;
8013
8014                         //
8015                         // MethodGroups use this opportunity to flag an error on lacking ()
8016                         //
8017                         if (!(c is MethodGroupExpr))
8018                                 return c.Resolve (ec);
8019                         return c;
8020                 }
8021
8022                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8023                 {
8024                         Expression c = CommonResolve (ec);
8025
8026                         if (c == null)
8027                                 return null;
8028
8029                         //
8030                         // MethodGroups use this opportunity to flag an error on lacking ()
8031                         //
8032                         if (! (c is MethodGroupExpr))
8033                                 return c.DoResolveLValue (ec, right_side);
8034
8035                         return c;
8036                 }
8037
8038                 Expression CommonResolve (EmitContext ec)
8039                 {
8040                         Expression member_lookup;
8041                         Type current_type = ec.ContainerType;
8042                         Type base_type = current_type.BaseType;
8043
8044                         if (ec.IsStatic){
8045                                 Error (1511, "Keyword `base' is not available in a static method");
8046                                 return null;
8047                         }
8048
8049                         if (ec.IsFieldInitializer){
8050                                 Error (1512, "Keyword `base' is not available in the current context");
8051                                 return null;
8052                         }
8053                         
8054                         member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8055                                                       AllMemberTypes, AllBindingFlags, loc);
8056                         if (member_lookup == null) {
8057                                 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8058                                 return null;
8059                         }
8060
8061                         Expression left;
8062                         
8063                         if (ec.IsStatic)
8064                                 left = new TypeExpression (base_type, loc);
8065                         else
8066                                 left = ec.GetThis (loc);
8067
8068                         MemberExpr me = (MemberExpr) member_lookup;
8069                         
8070                         Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8071
8072                         if (e is PropertyExpr) {
8073                                 PropertyExpr pe = (PropertyExpr) e;
8074                                 pe.IsBase = true;
8075                         } else if (e is EventExpr) {
8076                                 EventExpr ee = (EventExpr) e;
8077                                 ee.IsBase = true;
8078                         }
8079
8080                         MethodGroupExpr mg = e as MethodGroupExpr;
8081                         if (mg != null)
8082                                 mg.IsBase = true;
8083
8084                         if (args != null) {
8085                                 if (mg != null)
8086                                         return mg.ResolveGeneric (ec, args);
8087
8088                                 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8089                                               Identifier);
8090                                 return null;
8091                         }
8092
8093                         return e;
8094                 }
8095
8096                 public override void Emit (EmitContext ec)
8097                 {
8098                         throw new Exception ("Should never be called"); 
8099                 }
8100
8101                 protected override void CloneTo (CloneContext clonectx, Expression t)
8102                 {
8103                         BaseAccess target = (BaseAccess) t;
8104
8105                         target.args = args.Clone ();
8106                 }
8107         }
8108
8109         /// <summary>
8110         ///   The base indexer operator
8111         /// </summary>
8112         public class BaseIndexerAccess : IndexerAccess {
8113                 public BaseIndexerAccess (ArrayList args, Location loc)
8114                         : base (null, true, loc)
8115                 {
8116                         arguments = new ArrayList ();
8117                         foreach (Expression tmp in args)
8118                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8119                 }
8120
8121                 protected override bool CommonResolve (EmitContext ec)
8122                 {
8123                         instance_expr = ec.GetThis (loc);
8124
8125                         current_type = ec.ContainerType.BaseType;
8126                         indexer_type = current_type;
8127
8128                         foreach (Argument a in arguments){
8129                                 if (!a.Resolve (ec, loc))
8130                                         return false;
8131                         }
8132
8133                         return true;
8134                 }
8135         }
8136         
8137         /// <summary>
8138         ///   This class exists solely to pass the Type around and to be a dummy
8139         ///   that can be passed to the conversion functions (this is used by
8140         ///   foreach implementation to typecast the object return value from
8141         ///   get_Current into the proper type.  All code has been generated and
8142         ///   we only care about the side effect conversions to be performed
8143         ///
8144         ///   This is also now used as a placeholder where a no-action expression
8145         ///   is needed (the `New' class).
8146         /// </summary>
8147         public class EmptyExpression : Expression {
8148                 public static readonly EmptyExpression Null = new EmptyExpression ();
8149
8150                 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8151                 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8152                 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8153
8154                 static EmptyExpression temp = new EmptyExpression ();
8155                 public static EmptyExpression Grab ()
8156                 {
8157                         EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8158                         temp = null;
8159                         return retval;
8160                 }
8161
8162                 public static void Release (EmptyExpression e)
8163                 {
8164                         temp = e;
8165                 }
8166
8167                 // TODO: should be protected
8168                 public EmptyExpression ()
8169                 {
8170                         type = TypeManager.object_type;
8171                         eclass = ExprClass.Value;
8172                         loc = Location.Null;
8173                 }
8174
8175                 public EmptyExpression (Type t)
8176                 {
8177                         type = t;
8178                         eclass = ExprClass.Value;
8179                         loc = Location.Null;
8180                 }
8181                 
8182                 public override Expression DoResolve (EmitContext ec)
8183                 {
8184                         return this;
8185                 }
8186
8187                 public override void Emit (EmitContext ec)
8188                 {
8189                         // nothing, as we only exist to not do anything.
8190                 }
8191
8192                 //
8193                 // This is just because we might want to reuse this bad boy
8194                 // instead of creating gazillions of EmptyExpressions.
8195                 // (CanImplicitConversion uses it)
8196                 //
8197                 public void SetType (Type t)
8198                 {
8199                         type = t;
8200                 }
8201         }
8202
8203         public class UserCast : Expression {
8204                 MethodBase method;
8205                 Expression source;
8206                 
8207                 public UserCast (MethodInfo method, Expression source, Location l)
8208                 {
8209                         this.method = method;
8210                         this.source = source;
8211                         type = method.ReturnType;
8212                         eclass = ExprClass.Value;
8213                         loc = l;
8214                 }
8215
8216                 public Expression Source {
8217                         get {
8218                                 return source;
8219                         }
8220                 }
8221                         
8222                 public override Expression DoResolve (EmitContext ec)
8223                 {
8224                         //
8225                         // We are born fully resolved
8226                         //
8227                         return this;
8228                 }
8229
8230                 public override void Emit (EmitContext ec)
8231                 {
8232                         ILGenerator ig = ec.ig;
8233
8234                         source.Emit (ec);
8235                         
8236                         if (method is MethodInfo)
8237                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8238                         else
8239                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8240
8241                 }
8242         }
8243
8244         // <summary>
8245         //   This class is used to "construct" the type during a typecast
8246         //   operation.  Since the Type.GetType class in .NET can parse
8247         //   the type specification, we just use this to construct the type
8248         //   one bit at a time.
8249         // </summary>
8250         public class ComposedCast : TypeExpr {
8251                 Expression left;
8252                 string dim;
8253                 
8254                 public ComposedCast (Expression left, string dim)
8255                         : this (left, dim, left.Location)
8256                 {
8257                 }
8258
8259                 public ComposedCast (Expression left, string dim, Location l)
8260                 {
8261                         this.left = left;
8262                         this.dim = dim;
8263                         loc = l;
8264                 }
8265
8266 #if GMCS_SOURCE
8267                 public Expression RemoveNullable ()
8268                 {
8269                         if (dim.EndsWith ("?")) {
8270                                 dim = dim.Substring (0, dim.Length - 1);
8271                                 if (dim == "")
8272                                         return left;
8273                         }
8274
8275                         return this;
8276                 }
8277 #endif
8278
8279                 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8280                 {
8281                         TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8282                         if (lexpr == null)
8283                                 return null;
8284
8285                         Type ltype = lexpr.Type;
8286                         if ((ltype == TypeManager.void_type) && (dim != "*")) {
8287                                 Error_VoidInvalidInTheContext (loc);
8288                                 return null;
8289                         }
8290
8291 #if GMCS_SOURCE
8292                         if ((dim.Length > 0) && (dim [0] == '?')) {
8293                                 TypeExpr nullable = new NullableType (left, loc);
8294                                 if (dim.Length > 1)
8295                                         nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8296                                 return nullable.ResolveAsTypeTerminal (ec, false);
8297                         }
8298 #endif
8299
8300                         if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8301                                 return null;
8302
8303                         if (dim != "" && dim [0] == '[' &&
8304                             (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8305                                 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8306                                 return null;
8307                         }
8308
8309                         if (dim != "")
8310                                 type = TypeManager.GetConstructedType (ltype, dim);
8311                         else
8312                                 type = ltype;
8313
8314                         if (type == null)
8315                                 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8316
8317                         if (type.IsPointer && !ec.IsInUnsafeScope){
8318                                 UnsafeError (loc);
8319                                 return null;
8320                         }
8321
8322                         eclass = ExprClass.Type;
8323                         return this;
8324                 }
8325
8326                 public override string Name {
8327                         get { return left + dim; }
8328                 }
8329
8330                 public override string FullName {
8331                         get { return type.FullName; }
8332                 }
8333
8334                 public override string GetSignatureForError ()
8335                 {
8336                         return left.GetSignatureForError () + dim;
8337                 }
8338
8339                 protected override void CloneTo (CloneContext clonectx, Expression t)
8340                 {
8341                         ComposedCast target = (ComposedCast) t;
8342
8343                         target.left = left.Clone (clonectx);
8344                 }
8345         }
8346
8347         public class FixedBufferPtr : Expression {
8348                 Expression array;
8349
8350                 public FixedBufferPtr (Expression array, Type array_type, Location l)
8351                 {
8352                         this.array = array;
8353                         this.loc = l;
8354
8355                         type = TypeManager.GetPointerType (array_type);
8356                         eclass = ExprClass.Value;
8357                 }
8358
8359                 public override void Emit(EmitContext ec)
8360                 {
8361                         array.Emit (ec);
8362                 }
8363
8364                 public override Expression DoResolve (EmitContext ec)
8365                 {
8366                         //
8367                         // We are born fully resolved
8368                         //
8369                         return this;
8370                 }
8371         }
8372
8373
8374         //
8375         // This class is used to represent the address of an array, used
8376         // only by the Fixed statement, this generates "&a [0]" construct
8377         // for fixed (char *pa = a)
8378         //
8379         public class ArrayPtr : FixedBufferPtr {
8380                 Type array_type;
8381                 
8382                 public ArrayPtr (Expression array, Type array_type, Location l):
8383                         base (array, array_type, l)
8384                 {
8385                         this.array_type = array_type;
8386                 }
8387
8388                 public override void Emit (EmitContext ec)
8389                 {
8390                         base.Emit (ec);
8391                         
8392                         ILGenerator ig = ec.ig;
8393                         IntLiteral.EmitInt (ig, 0);
8394                         ig.Emit (OpCodes.Ldelema, array_type);
8395                 }
8396         }
8397
8398         //
8399         // Used by the fixed statement
8400         //
8401         public class StringPtr : Expression {
8402                 LocalBuilder b;
8403                 
8404                 public StringPtr (LocalBuilder b, Location l)
8405                 {
8406                         this.b = b;
8407                         eclass = ExprClass.Value;
8408                         type = TypeManager.char_ptr_type;
8409                         loc = l;
8410                 }
8411
8412                 public override Expression DoResolve (EmitContext ec)
8413                 {
8414                         // This should never be invoked, we are born in fully
8415                         // initialized state.
8416
8417                         return this;
8418                 }
8419
8420                 public override void Emit (EmitContext ec)
8421                 {
8422                         ILGenerator ig = ec.ig;
8423
8424                         ig.Emit (OpCodes.Ldloc, b);
8425                         ig.Emit (OpCodes.Conv_I);
8426                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8427                         ig.Emit (OpCodes.Add);
8428                 }
8429         }
8430         
8431         //
8432         // Implements the `stackalloc' keyword
8433         //
8434         public class StackAlloc : Expression {
8435                 Type otype;
8436                 Expression t;
8437                 Expression count;
8438                 
8439                 public StackAlloc (Expression type, Expression count, Location l)
8440                 {
8441                         t = type;
8442                         this.count = count;
8443                         loc = l;
8444                 }
8445
8446                 public override Expression DoResolve (EmitContext ec)
8447                 {
8448                         count = count.Resolve (ec);
8449                         if (count == null)
8450                                 return null;
8451                         
8452                         if (count.Type != TypeManager.int32_type){
8453                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8454                                 if (count == null)
8455                                         return null;
8456                         }
8457
8458                         Constant c = count as Constant;
8459                         if (c != null && c.IsNegative) {
8460                                 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8461                                 return null;
8462                         }
8463
8464                         if (ec.InCatch || ec.InFinally) {
8465                                 Error (255, "Cannot use stackalloc in finally or catch");
8466                                 return null;
8467                         }
8468
8469                         TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8470                         if (texpr == null)
8471                                 return null;
8472
8473                         otype = texpr.Type;
8474
8475                         if (!TypeManager.VerifyUnManaged (otype, loc))
8476                                 return null;
8477
8478                         type = TypeManager.GetPointerType (otype);
8479                         eclass = ExprClass.Value;
8480
8481                         return this;
8482                 }
8483
8484                 public override void Emit (EmitContext ec)
8485                 {
8486                         int size = GetTypeSize (otype);
8487                         ILGenerator ig = ec.ig;
8488                                 
8489                         if (size == 0)
8490                                 ig.Emit (OpCodes.Sizeof, otype);
8491                         else
8492                                 IntConstant.EmitInt (ig, size);
8493                         count.Emit (ec);
8494                         ig.Emit (OpCodes.Mul);
8495                         ig.Emit (OpCodes.Localloc);
8496                 }
8497
8498                 protected override void CloneTo (CloneContext clonectx, Expression t)
8499                 {
8500                         StackAlloc target = (StackAlloc) t;
8501                         target.count = count.Clone (clonectx);
8502                         target.t = t.Clone (clonectx);
8503                 }
8504         }
8505         
8506         public interface IInitializable
8507         {
8508                 bool Initialize (EmitContext ec, Expression target);
8509         }
8510         
8511         public class Initializer
8512         {
8513                 public readonly string Name;
8514                 public readonly object Value;
8515
8516                 public Initializer (string name, Expression value)
8517                 {
8518                         Name = name;
8519                         Value = value;
8520                 }
8521
8522                 public Initializer (string name, IInitializable value)
8523                 {
8524                         Name = name;
8525                         Value = value;
8526                 }
8527         }
8528         
8529         public class ObjectInitializer : IInitializable
8530         {
8531                 readonly ArrayList initializers;
8532                 public ObjectInitializer (ArrayList initializers)
8533                 {
8534                         this.initializers = initializers;
8535                 }
8536                 
8537                 public bool Initialize (EmitContext ec, Expression target)
8538                 {
8539                         ArrayList initialized = new ArrayList (initializers.Count);
8540                         for (int i = initializers.Count - 1; i >= 0; i--) {
8541                                 Initializer initializer = initializers[i] as Initializer;
8542                                 if (initialized.Contains (initializer.Name)) {
8543                                         //FIXME proper error
8544                                         Console.WriteLine ("Object member can only be initialized once");
8545                                         return false;
8546                                 }
8547                                 
8548                                 MemberAccess ma = new MemberAccess (target, initializer.Name);
8549                                 Expression expr = initializer.Value as Expression;
8550                                 // If it's an expresison, append the assign.
8551                                 if (expr != null) {
8552                                         Assign a = new Assign (ma, expr);
8553                                         ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (a));
8554                                 }
8555                                 // If it's another initializer (object or collection), initialize it.
8556                                 else if (!((IInitializable)initializer.Value).Initialize (ec, ma))
8557                                                         return false;
8558                                 
8559                                 initialized.Add (initializer.Name);
8560                         }
8561                         return true;
8562                 }
8563         }
8564         
8565         public class CollectionInitializer : IInitializable
8566         {
8567                 readonly ArrayList items;
8568                 public CollectionInitializer (ArrayList items)
8569                 {
8570                         this.items = items;
8571                 }
8572                 
8573                 bool CheckCollection (EmitContext ec, Expression e)
8574                 {
8575                         if (e == null || e.Type == null)
8576                                 return false;
8577                         bool is_ienumerable = false;
8578                         foreach (Type t in TypeManager.GetInterfaces (e.Type))
8579                                 if (t == typeof (IEnumerable)) {
8580                                         is_ienumerable = true;
8581                                         break;
8582                                 }
8583                         
8584                         if (!is_ienumerable)
8585                                 return false;
8586                         
8587                         MethodGroupExpr mg = Expression.MemberLookup (
8588                                 ec.ContainerType, e.Type, "Add", MemberTypes.Method,
8589                                 Expression.AllBindingFlags, Location.Null) as MethodGroupExpr;
8590
8591                         if (mg == null)
8592                                         return false;
8593                         
8594                         foreach (MethodInfo mi in mg.Methods) {
8595                                 if (TypeManager.GetParameterData (mi).Count != 1)
8596                                         continue;
8597                                 if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
8598                                         continue;
8599                                 return true;
8600                         }
8601                         return false;
8602                 }
8603                 
8604                 public bool Initialize (EmitContext ec, Expression target)
8605                 {
8606                         if (!CheckCollection (ec, target.Resolve (ec))) {
8607                                 // FIXME throw proper error
8608                                 Console.WriteLine ("Error: This is not a collection");
8609                                 return false;
8610                         }
8611                         
8612                         for (int i = items.Count - 1; i >= 0; i--) {
8613                                 MemberAccess ma = new MemberAccess (target, "Add");
8614                                 ArrayList array = new ArrayList ();
8615                                 array.Add (new Argument ((Expression)items[i]));
8616                                 Invocation invoke = new Invocation (ma, array);
8617                                 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (invoke));
8618                         }
8619                         return true;
8620                 }
8621         }
8622         
8623         public class NewInitialize : New, IInitializable
8624         {
8625                 IInitializable initializer;
8626
8627                 public bool Initialize (EmitContext ec, Expression target)
8628                 {
8629                         return initializer.Initialize (ec, target);
8630                 }
8631
8632                 public NewInitialize (Expression requested_type, ArrayList arguments, IInitializable initializer, Location l)
8633                         : base (requested_type, arguments, l)
8634                 {
8635                         this.initializer = initializer;
8636                 }
8637         }
8638
8639         public class AnonymousTypeDeclaration : Expression
8640         {
8641                 readonly ArrayList parameters;
8642                 readonly TypeContainer parent;
8643
8644                 public AnonymousTypeDeclaration (ArrayList parameters, TypeContainer parent, Location loc)
8645                 {
8646                         this.parameters = parameters;
8647                         this.parent = parent;
8648                         this.loc = loc;
8649                 }
8650
8651                 AnonymousTypeClass CreateAnonymousType ()
8652                 {
8653                         AnonymousTypeClass type = AnonymousTypeClass.Create (parent, parameters, loc);
8654                         if (type == null)
8655                                 return null;
8656
8657                         type.DefineType ();
8658                         type.DefineMembers ();
8659                         type.Define ();
8660                         type.EmitType ();
8661
8662                         RootContext.ToplevelTypes.AddAnonymousType (type);
8663                         return type;
8664                 }
8665
8666                 public override Expression DoResolve (EmitContext ec)
8667                 {
8668                         bool error = false;
8669                         ArrayList arguments = new ArrayList (parameters.Count);
8670                         TypeExpression [] t_args = new TypeExpression [parameters.Count];
8671                         for (int i = 0; i < parameters.Count; ++i) {
8672                                 Expression e = ((AnonymousTypeParameter)parameters [i]).Resolve (ec);
8673                                 if (e == null) {
8674                                         error = true;
8675                                         continue;
8676                                 }
8677
8678                                 arguments.Add (new Argument (e));
8679                                 t_args [i] = new TypeExpression (e.Type, e.Location);
8680                         }
8681
8682                         if (error)
8683                                 return null;
8684
8685                         AnonymousTypeClass anonymous_type = RootContext.ToplevelTypes.GetAnonymousType (parameters);
8686                         if (anonymous_type == null) {
8687                                 anonymous_type = CreateAnonymousType ();
8688                                 if (anonymous_type == null)
8689                                         return null;
8690                         }
8691
8692                         ConstructedType te = new ConstructedType (anonymous_type.TypeBuilder,
8693                                 new TypeArguments (loc, t_args), loc);
8694
8695                         return new New (te, arguments, loc).Resolve (ec); 
8696                 }
8697
8698                 public override void Emit (EmitContext ec)
8699                 {
8700                         throw new InternalErrorException ("Should not be reached");
8701                 }
8702         }
8703
8704         public class AnonymousTypeParameter : Expression
8705         {
8706                 public readonly string Name;
8707                 readonly Expression initializer;
8708
8709                 public AnonymousTypeParameter (Expression initializer, string name, Location loc)
8710                 {
8711                         this.Name = name;
8712                         this.loc = loc;
8713                         this.initializer = initializer;
8714                 }
8715
8716                 public override bool Equals (object o)
8717                 {
8718                         AnonymousTypeParameter other = o as AnonymousTypeParameter;
8719                         return other != null && Name == other.Name;
8720                 }
8721
8722                 public override int GetHashCode ()
8723                 {
8724                         return Name.GetHashCode ();
8725                 }
8726
8727                 public override Expression DoResolve (EmitContext ec)
8728                 {
8729                         Expression e = initializer.Resolve (ec);
8730                         if (e == null)
8731                                 return null;
8732
8733                         type = e.Type;
8734                         if (type == TypeManager.void_type || type == TypeManager.null_type ||
8735                                 type == TypeManager.anonymous_method_type || type.IsPointer) {
8736                                 Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
8737                                         Name, e.GetSignatureForError ());
8738                                 return null;
8739                         }
8740
8741                         return e;
8742                 }
8743
8744                 public override void Emit (EmitContext ec)
8745                 {
8746                         throw new InternalErrorException ("Should not be reached");
8747                 }
8748         }
8749 }