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