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