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