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