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