* Form.cs: Make the fix for #80775 windows-only (fixes #81957).
[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
4235                                 if (TypeManager.IsEqual (pt, a.Type))
4236                                         continue;
4237
4238                                 if (a_mod != Parameter.Modifier.NONE)
4239                                         return false;
4240
4241                                 // FIXME: Kill this abomination (EmitContext.TempEc)
4242                                 EmitContext prevec = EmitContext.TempEc;
4243                                 EmitContext.TempEc = ec;
4244                                 try {
4245                                         if (!Convert.ImplicitConversionExists (ec, a.Expr, pt))
4246                                                 return false;
4247                                 } finally {
4248                                         EmitContext.TempEc = prevec;
4249                                 }
4250                         }
4251
4252                         return true;
4253                 }
4254
4255                 public static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4256                 {
4257                         Report.Error (1501, loc, "No overload for method `{0}' takes `{1}' arguments",
4258                                 name, arg_count.ToString ());
4259                 }
4260                         
4261                 static void Error_InvalidArguments (Location loc, int idx, MethodBase method,
4262                                                     Type delegate_type, Argument a, ParameterData expected_par)
4263                 {
4264                         if (delegate_type == null) 
4265                                 Report.Error (1502, loc, "The best overloaded method match for `{0}' has some invalid arguments",
4266                                               TypeManager.CSharpSignature (method));
4267                         else
4268                                 Report.Error (1594, loc, "Delegate `{0}' has some invalid arguments",
4269                                         TypeManager.CSharpName (delegate_type));
4270
4271                         Parameter.Modifier mod = expected_par.ParameterModifier (idx);
4272
4273                         string index = (idx + 1).ToString ();
4274                         if (mod != Parameter.Modifier.ARGLIST && mod != a.Modifier) {
4275                                 if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) == 0)
4276                                         Report.Error (1615, loc, "Argument `{0}' should not be passed with the `{1}' keyword",
4277                                                 index, Parameter.GetModifierSignature (a.Modifier));
4278                                 else
4279                                         Report.Error (1620, loc, "Argument `{0}' must be passed with the `{1}' keyword",
4280                                                 index, Parameter.GetModifierSignature (mod));
4281                         } else {
4282                                 string p1 = Argument.FullDesc (a);
4283                                 string p2 = TypeManager.CSharpName (expected_par.ParameterType (idx));
4284
4285                                 if (p1 == p2) {
4286                                         Report.ExtraInformation (loc, "(equally named types possibly from different assemblies in previous ");
4287                                         Report.SymbolRelatedToPreviousError (a.Expr.Type);
4288                                         Report.SymbolRelatedToPreviousError (expected_par.ParameterType (idx));
4289                                 }
4290                                 Report.Error (1503, loc, "Argument {0}: Cannot convert type `{1}' to `{2}'", index, p1, p2);
4291                         }
4292                 }
4293                 
4294                 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4295                                                           int arg_count, MethodBase method, 
4296                                                           bool chose_params_expanded,
4297                                                           Type delegate_type, bool may_fail,
4298                                                           Location loc)
4299                 {
4300                         ParameterData pd = TypeManager.GetParameterData (method);
4301                         int j;
4302                         int a_idx = 0;
4303                         Argument a = null;
4304                         for (j = 0; j < pd.Count; j++) {
4305                                 Type parameter_type = pd.ParameterType (j);
4306                                 Parameter.Modifier pm = pd.ParameterModifier (j);
4307
4308                                 if (pm == Parameter.Modifier.ARGLIST) {
4309                                         a = (Argument) Arguments [a_idx];
4310                                         if (!(a.Expr is Arglist))
4311                                                 break;
4312                                         ++a_idx;
4313                                         continue;
4314                                 }
4315
4316                                 int params_arg_count = 1;
4317                                 if (pm == Parameter.Modifier.PARAMS) {
4318                                         pm = Parameter.Modifier.NONE;
4319                                         params_arg_count = arg_count - pd.Count + 1;
4320                                         if (chose_params_expanded)
4321                                                 parameter_type = TypeManager.GetElementType (parameter_type);
4322                                 }
4323
4324                                 while (params_arg_count > 0) {
4325                                         a = (Argument) Arguments [a_idx];
4326                                         if (pm != a.Modifier)
4327                                                 break;
4328
4329                                         if (!TypeManager.IsEqual (a.Type, parameter_type)) {
4330                                                 if (pm == Parameter.Modifier.OUT || pm == Parameter.Modifier.REF)
4331                                                         break;
4332
4333                                                 Expression conv = Convert.ImplicitConversion (ec, a.Expr, parameter_type, loc);
4334                                                 if (conv == null)
4335                                                         break;
4336
4337                                                 // Update the argument with the implicit conversion
4338                                                 if (a.Expr != conv)
4339                                                         a.Expr = conv;
4340                                         }
4341
4342                                         --params_arg_count;
4343                                         ++a_idx;
4344                                 }
4345                                 if (params_arg_count > 0)
4346                                         break;
4347
4348                                 if (parameter_type.IsPointer && !ec.InUnsafe) {
4349                                         if (!may_fail)
4350                                                 UnsafeError (loc);
4351                                         return false;
4352                                 }
4353                         }
4354
4355                         if (a_idx == arg_count)
4356                                 return true;
4357
4358                         if (!may_fail)
4359                                 Error_InvalidArguments (loc, a_idx, method, delegate_type, a, pd);
4360                         return false;
4361                 }
4362
4363                 public override Expression DoResolve (EmitContext ec)
4364                 {
4365                         Expression expr_resolved = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
4366                         if (expr_resolved == null)
4367                                 return null;
4368
4369                         mg = expr_resolved as MethodGroupExpr;
4370                         if (mg == null) {
4371                                 Type expr_type = expr_resolved.Type;
4372
4373                                 if (expr_type != null && TypeManager.IsDelegateType (expr_type)){
4374                                         return (new DelegateInvocation (
4375                                                 expr_resolved, Arguments, loc)).Resolve (ec);
4376                                 }
4377                                 expr.Error_UnexpectedKind (ResolveFlags.MethodGroup, loc);
4378                                 return null;
4379                         }
4380
4381                         //
4382                         // Next, evaluate all the expressions in the argument list
4383                         //
4384                         if (Arguments != null){
4385                                 foreach (Argument a in Arguments){
4386                                         if (!a.Resolve (ec, loc))
4387                                                 return null;
4388                                 }
4389                         }
4390
4391                         mg = mg.OverloadResolve (ec, Arguments, false, loc);
4392                         if (mg == null)
4393                                 return null;
4394
4395                         MethodInfo method = (MethodInfo)mg;
4396                         if (method != null) {
4397                                 type = TypeManager.TypeToCoreType (method.ReturnType);
4398                                 Expression iexpr = mg.InstanceExpression;
4399                                 if (method.IsStatic) {
4400                                         if (iexpr == null || 
4401                                             iexpr is This || iexpr is EmptyExpression ||
4402                                             mg.IdenticalTypeName) {
4403                                                 mg.InstanceExpression = null;
4404                                         } else {
4405                                                 MemberExpr.error176 (loc, mg.GetSignatureForError ());
4406                                                 return null;
4407                                         }
4408                                 } else {
4409                                         if (iexpr == null || iexpr is EmptyExpression) {
4410                                                 SimpleName.Error_ObjectRefRequired (ec, loc, mg.GetSignatureForError ());
4411                                                 return null;
4412                                         }
4413                                 }
4414                         }
4415
4416                         if (type.IsPointer){
4417                                 if (!ec.InUnsafe){
4418                                         UnsafeError (loc);
4419                                         return null;
4420                                 }
4421                         }
4422                         
4423                         //
4424                         // Only base will allow this invocation to happen.
4425                         //
4426                         if (mg.IsBase && method.IsAbstract){
4427                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (method));
4428                                 return null;
4429                         }
4430
4431                         if (Arguments == null && method.Name == "Finalize") {
4432                                 if (mg.IsBase)
4433                                         Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
4434                                 else
4435                                         Report.Error (245, loc, "Destructors and object.Finalize cannot be called directly. Consider calling IDisposable.Dispose if available");
4436                                 return null;
4437                         }
4438
4439                         if (IsSpecialMethodInvocation (method)) {
4440                                 return null;
4441                         }
4442                         
4443                         if (mg.InstanceExpression != null){
4444                                 mg.InstanceExpression.CheckMarshalByRefAccess ();
4445
4446                                 //
4447                                 // This is used to check that no methods are called in struct
4448                                 // constructors before all the fields on the struct have been
4449                                 // initialized.
4450                                 //
4451                                 if (!method.IsStatic){
4452                                         This mgthis = mg.InstanceExpression as This;
4453                                         if (mgthis != null){
4454                                                 if (!mgthis.CheckThisUsage (ec))
4455                                                         return  null;
4456                                         }
4457                                 }
4458                         }
4459
4460                         eclass = ExprClass.Value;
4461                         return this;
4462                 }
4463
4464                 bool IsSpecialMethodInvocation (MethodBase method)
4465                 {
4466                         if (!TypeManager.IsSpecialMethod (method))
4467                                 return false;
4468
4469                         Report.SymbolRelatedToPreviousError (method);
4470                         Report.Error (571, loc, "`{0}': cannot explicitly call operator or accessor",
4471                                 TypeManager.CSharpSignature (method, true));
4472         
4473                         return true;
4474                 }
4475
4476                 // <summary>
4477                 //   Emits the list of arguments as an array
4478                 // </summary>
4479                 static void EmitParams (EmitContext ec, ArrayList arguments, int idx, int count)
4480                 {
4481                         ILGenerator ig = ec.ig;
4482                         Type t = null;
4483                         for (int j = 0; j < count; j++){
4484                                 Argument a = (Argument) arguments [j + idx];
4485                                 if (j == 0) {
4486                                         t = a.Expr.Type;
4487                                         IntConstant.EmitInt (ig, count);
4488                                         ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4489                                 }
4490                                 
4491                                 ig.Emit (OpCodes.Dup);
4492                                 IntConstant.EmitInt (ig, j);
4493
4494                                 bool is_stobj, has_type_arg;
4495                                 OpCode op = ArrayAccess.GetStoreOpcode (t, out is_stobj, out has_type_arg);
4496                                 if (is_stobj)
4497                                         ig.Emit (OpCodes.Ldelema, t);
4498
4499                                 a.Emit (ec);
4500
4501                                 if (has_type_arg)
4502                                         ig.Emit (op, t);
4503                                 else
4504                                         ig.Emit (op);
4505                         }
4506                 }
4507                 
4508                 /// <summary>
4509                 ///   Emits a list of resolved Arguments that are in the arguments
4510                 ///   ArrayList.
4511                 /// 
4512                 ///   The MethodBase argument might be null if the
4513                 ///   emission of the arguments is known not to contain
4514                 ///   a `params' field (for example in constructors or other routines
4515                 ///   that keep their arguments in this structure)
4516                 ///   
4517                 ///   if `dup_args' is true, a copy of the arguments will be left
4518                 ///   on the stack. If `dup_args' is true, you can specify `this_arg'
4519                 ///   which will be duplicated before any other args. Only EmitCall
4520                 ///   should be using this interface.
4521                 /// </summary>
4522                 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg)
4523                 {
4524                         ParameterData pd = mb == null ? null : TypeManager.GetParameterData (mb);
4525                         int top = pd.Count;
4526                         LocalTemporary [] temps = null;
4527                         
4528                         if (dup_args && top != 0)
4529                                 temps = new LocalTemporary [top];
4530
4531                         int argument_index = 0;
4532                         Argument a;
4533                         for (int i = 0; i < top; i++){
4534                                 if (pd != null){
4535                                         if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4536                                                 //Type element_type = TypeManager.GetElementType (pd.ParameterType (i));
4537                                                 int params_args_count = arguments == null ?
4538                                                         0 : arguments.Count - top + 1;
4539
4540                                                 // Fill not provided argument
4541                                                 if (params_args_count <= 0) {
4542                                                         ILGenerator ig = ec.ig;
4543                                                         IntConstant.EmitInt (ig, 0);
4544                                                         ig.Emit (OpCodes.Newarr, TypeManager.GetElementType (pd.ParameterType (i)));
4545                                                         continue;
4546                                                 }
4547
4548                                                 //
4549                                                 // Special case if we are passing the same data as the
4550                                                 // params argument, we do not need to recreate an array.
4551                                                 //
4552                                                 a = (Argument) arguments [argument_index];
4553                                                 if (params_args_count == 1 && pd.ParameterType (i) == a.Type) {
4554                                                         ++argument_index;
4555                                                         a.Emit (ec);
4556                                                         continue;
4557                                                 }
4558
4559                                                 EmitParams (ec, arguments, i, params_args_count);
4560                                                 argument_index += params_args_count;
4561                                                 continue;
4562                                         }
4563                                 }
4564
4565                                 a = (Argument) arguments [argument_index++];
4566                                 a.Emit (ec);
4567                                 if (dup_args) {
4568                                         ec.ig.Emit (OpCodes.Dup);
4569                                         (temps [i] = new LocalTemporary (a.Type)).Store (ec);
4570                                 }
4571                         }
4572                         
4573                         if (dup_args) {
4574                                 if (this_arg != null)
4575                                         this_arg.Emit (ec);
4576                                 
4577                                 for (int i = 0; i < top; i ++) {
4578                                         temps [i].Emit (ec);
4579                                         temps [i].Release (ec);
4580                                 }
4581                         }
4582                 }
4583
4584                 static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
4585                 {
4586                         ParameterData pd = TypeManager.GetParameterData (mb);
4587
4588                         if (arguments == null)
4589                                 return new Type [0];
4590
4591                         Argument a = (Argument) arguments [pd.Count - 1];
4592                         Arglist list = (Arglist) a.Expr;
4593
4594                         return list.ArgumentTypes;
4595                 }
4596
4597                 /// <summary>
4598                 /// This checks the ConditionalAttribute on the method 
4599                 /// </summary>
4600                 static bool IsMethodExcluded (MethodBase method)
4601                 {
4602                         if (method.IsConstructor)
4603                                 return false;
4604
4605                         IMethodData md = TypeManager.GetMethod (method);
4606                         if (md != null)
4607                                 return md.IsExcluded ();
4608
4609                         // For some methods (generated by delegate class) GetMethod returns null
4610                         // because they are not included in builder_to_method table
4611                         if (method.DeclaringType is TypeBuilder)
4612                                 return false;
4613
4614                         return AttributeTester.IsConditionalMethodExcluded (method);
4615                 }
4616
4617                 /// <remarks>
4618                 ///   is_base tells whether we want to force the use of the `call'
4619                 ///   opcode instead of using callvirt.  Call is required to call
4620                 ///   a specific method, while callvirt will always use the most
4621                 ///   recent method in the vtable.
4622                 ///
4623                 ///   is_static tells whether this is an invocation on a static method
4624                 ///
4625                 ///   instance_expr is an expression that represents the instance
4626                 ///   it must be non-null if is_static is false.
4627                 ///
4628                 ///   method is the method to invoke.
4629                 ///
4630                 ///   Arguments is the list of arguments to pass to the method or constructor.
4631                 /// </remarks>
4632                 public static void EmitCall (EmitContext ec, bool is_base,
4633                                              Expression instance_expr,
4634                                              MethodBase method, ArrayList Arguments, Location loc)
4635                 {
4636                         EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
4637                 }
4638                 
4639                 // `dup_args' leaves an extra copy of the arguments on the stack
4640                 // `omit_args' does not leave any arguments at all.
4641                 // So, basically, you could make one call with `dup_args' set to true,
4642                 // and then another with `omit_args' set to true, and the two calls
4643                 // would have the same set of arguments. However, each argument would
4644                 // only have been evaluated once.
4645                 public static void EmitCall (EmitContext ec, bool is_base,
4646                                              Expression instance_expr,
4647                                              MethodBase method, ArrayList Arguments, Location loc,
4648                                              bool dup_args, bool omit_args)
4649                 {
4650                         ILGenerator ig = ec.ig;
4651                         bool struct_call = false;
4652                         bool this_call = false;
4653                         LocalTemporary this_arg = null;
4654
4655                         Type decl_type = method.DeclaringType;
4656
4657                         if (!RootContext.StdLib) {
4658                                 // Replace any calls to the system's System.Array type with calls to
4659                                 // the newly created one.
4660                                 if (method == TypeManager.system_int_array_get_length)
4661                                         method = TypeManager.int_array_get_length;
4662                                 else if (method == TypeManager.system_int_array_get_rank)
4663                                         method = TypeManager.int_array_get_rank;
4664                                 else if (method == TypeManager.system_object_array_clone)
4665                                         method = TypeManager.object_array_clone;
4666                                 else if (method == TypeManager.system_int_array_get_length_int)
4667                                         method = TypeManager.int_array_get_length_int;
4668                                 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4669                                         method = TypeManager.int_array_get_lower_bound_int;
4670                                 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4671                                         method = TypeManager.int_array_get_upper_bound_int;
4672                                 else if (method == TypeManager.system_void_array_copyto_array_int)
4673                                         method = TypeManager.void_array_copyto_array_int;
4674                         }
4675
4676                         if (!ec.IsInObsoleteScope) {
4677                                 //
4678                                 // This checks ObsoleteAttribute on the method and on the declaring type
4679                                 //
4680                                 ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (method);
4681                                 if (oa != null)
4682                                         AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (method), loc);
4683
4684                                 oa = AttributeTester.GetObsoleteAttribute (method.DeclaringType);
4685                                 if (oa != null) {
4686                                         AttributeTester.Report_ObsoleteMessage (oa, method.DeclaringType.FullName, loc);
4687                                 }
4688                         }
4689
4690                         if (IsMethodExcluded (method))
4691                                 return;
4692                         
4693                         bool is_static = method.IsStatic;
4694                         if (!is_static){
4695                                 if (instance_expr == EmptyExpression.Null) {
4696                                         SimpleName.Error_ObjectRefRequired (ec, loc, TypeManager.CSharpSignature (method));
4697                                         return;
4698                                 }
4699
4700                                 this_call = instance_expr is This;
4701                                 if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType))
4702                                         struct_call = true;
4703
4704                                 //
4705                                 // If this is ourselves, push "this"
4706                                 //
4707                                 if (!omit_args) {
4708                                         Type t = null;
4709                                         Type iexpr_type = instance_expr.Type;
4710
4711                                         //
4712                                         // Push the instance expression
4713                                         //
4714                                         if (TypeManager.IsValueType (iexpr_type)) {
4715                                                 //
4716                                                 // Special case: calls to a function declared in a 
4717                                                 // reference-type with a value-type argument need
4718                                                 // to have their value boxed.
4719                                                 if (decl_type.IsValueType ||
4720                                                     TypeManager.IsGenericParameter (iexpr_type)) {
4721                                                         //
4722                                                         // If the expression implements IMemoryLocation, then
4723                                                         // we can optimize and use AddressOf on the
4724                                                         // return.
4725                                                         //
4726                                                         // If not we have to use some temporary storage for
4727                                                         // it.
4728                                                         if (instance_expr is IMemoryLocation) {
4729                                                                 ((IMemoryLocation)instance_expr).
4730                                                                         AddressOf (ec, AddressOp.LoadStore);
4731                                                         } else {
4732                                                                 LocalTemporary temp = new LocalTemporary (iexpr_type);
4733                                                                 instance_expr.Emit (ec);
4734                                                                 temp.Store (ec);
4735                                                                 temp.AddressOf (ec, AddressOp.Load);
4736                                                         }
4737
4738                                                         // avoid the overhead of doing this all the time.
4739                                                         if (dup_args)
4740                                                                 t = TypeManager.GetReferenceType (iexpr_type);
4741                                                 } else {
4742                                                         instance_expr.Emit (ec);
4743                                                         ig.Emit (OpCodes.Box, instance_expr.Type);
4744                                                         t = TypeManager.object_type;
4745                                                 }
4746                                         } else {
4747                                                 instance_expr.Emit (ec);
4748                                                 t = instance_expr.Type;
4749                                         }
4750
4751                                         if (dup_args) {
4752                                                 ig.Emit (OpCodes.Dup);
4753                                                 if (Arguments != null && Arguments.Count != 0) {
4754                                                         this_arg = new LocalTemporary (t);
4755                                                         this_arg.Store (ec);
4756                                                 }
4757                                         }
4758                                 }
4759                         }
4760
4761                         if (!omit_args)
4762                                 EmitArguments (ec, method, Arguments, dup_args, this_arg);
4763
4764 #if GMCS_SOURCE
4765                         if ((instance_expr != null) && (instance_expr.Type.IsGenericParameter))
4766                                 ig.Emit (OpCodes.Constrained, instance_expr.Type);
4767 #endif
4768
4769                         OpCode call_op;
4770                         if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
4771                                 call_op = OpCodes.Call;
4772                         else
4773                                 call_op = OpCodes.Callvirt;
4774
4775                         if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
4776                                 Type[] varargs_types = GetVarargsTypes (method, Arguments);
4777                                 ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
4778                                 return;
4779                         }
4780
4781                         //
4782                         // If you have:
4783                         // this.DoFoo ();
4784                         // and DoFoo is not virtual, you can omit the callvirt,
4785                         // because you don't need the null checking behavior.
4786                         //
4787                         if (method is MethodInfo)
4788                                 ig.Emit (call_op, (MethodInfo) method);
4789                         else
4790                                 ig.Emit (call_op, (ConstructorInfo) method);
4791                 }
4792                 
4793                 public override void Emit (EmitContext ec)
4794                 {
4795                         mg.EmitCall (ec, Arguments);
4796                 }
4797                 
4798                 public override void EmitStatement (EmitContext ec)
4799                 {
4800                         Emit (ec);
4801
4802                         // 
4803                         // Pop the return value if there is one
4804                         //
4805                         if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
4806                                 ec.ig.Emit (OpCodes.Pop);
4807                 }
4808
4809                 protected override void CloneTo (CloneContext clonectx, Expression t)
4810                 {
4811                         Invocation target = (Invocation) t;
4812
4813                         if (Arguments != null){
4814                                 target.Arguments = new ArrayList ();
4815                                 foreach (Argument a in Arguments)
4816                                         target.Arguments.Add (a.Clone (clonectx));
4817                         }
4818
4819                         expr = expr.Clone (clonectx);
4820                 }
4821         }
4822
4823         public class InvocationOrCast : ExpressionStatement
4824         {
4825                 Expression expr;
4826                 Expression argument;
4827
4828                 public InvocationOrCast (Expression expr, Expression argument)
4829                 {
4830                         this.expr = expr;
4831                         this.argument = argument;
4832                         this.loc = expr.Location;
4833                 }
4834
4835                 public override Expression DoResolve (EmitContext ec)
4836                 {
4837                         //
4838                         // First try to resolve it as a cast.
4839                         //
4840                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4841                         if ((te != null) && (te.eclass == ExprClass.Type)) {
4842                                 Cast cast = new Cast (te, argument, loc);
4843                                 return cast.Resolve (ec);
4844                         }
4845
4846                         //
4847                         // This can either be a type or a delegate invocation.
4848                         // Let's just resolve it and see what we'll get.
4849                         //
4850                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4851                         if (expr == null)
4852                                 return null;
4853
4854                         //
4855                         // Ok, so it's a Cast.
4856                         //
4857                         if (expr.eclass == ExprClass.Type) {
4858                                 Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
4859                                 return cast.Resolve (ec);
4860                         }
4861
4862                         //
4863                         // It's a delegate invocation.
4864                         //
4865                         if (!TypeManager.IsDelegateType (expr.Type)) {
4866                                 Error (149, "Method name expected");
4867                                 return null;
4868                         }
4869
4870                         ArrayList args = new ArrayList ();
4871                         args.Add (new Argument (argument, Argument.AType.Expression));
4872                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4873                         return invocation.Resolve (ec);
4874                 }
4875
4876                 public override ExpressionStatement ResolveStatement (EmitContext ec)
4877                 {
4878                         //
4879                         // First try to resolve it as a cast.
4880                         //
4881                         TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
4882                         if ((te != null) && (te.eclass == ExprClass.Type)) {
4883                                 Error_InvalidExpressionStatement ();
4884                                 return null;
4885                         }
4886
4887                         //
4888                         // This can either be a type or a delegate invocation.
4889                         // Let's just resolve it and see what we'll get.
4890                         //
4891                         expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
4892                         if ((expr == null) || (expr.eclass == ExprClass.Type)) {
4893                                 Error_InvalidExpressionStatement ();
4894                                 return null;
4895                         }
4896
4897                         //
4898                         // It's a delegate invocation.
4899                         //
4900                         if (!TypeManager.IsDelegateType (expr.Type)) {
4901                                 Error (149, "Method name expected");
4902                                 return null;
4903                         }
4904
4905                         ArrayList args = new ArrayList ();
4906                         args.Add (new Argument (argument, Argument.AType.Expression));
4907                         DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
4908                         return invocation.ResolveStatement (ec);
4909                 }
4910
4911                 public override void Emit (EmitContext ec)
4912                 {
4913                         throw new Exception ("Cannot happen");
4914                 }
4915
4916                 public override void EmitStatement (EmitContext ec)
4917                 {
4918                         throw new Exception ("Cannot happen");
4919                 }
4920
4921                 protected override void CloneTo (CloneContext clonectx, Expression t)
4922                 {
4923                         InvocationOrCast target = (InvocationOrCast) t;
4924
4925                         target.expr = expr.Clone (clonectx);
4926                         target.argument = argument.Clone (clonectx);
4927                 }
4928         }
4929
4930         //
4931         // This class is used to "disable" the code generation for the
4932         // temporary variable when initializing value types.
4933         //
4934         class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4935                 public void AddressOf (EmitContext ec, AddressOp Mode)
4936                 {
4937                         // nothing
4938                 }
4939         }
4940         
4941         /// <summary>
4942         ///    Implements the new expression 
4943         /// </summary>
4944         public class New : ExpressionStatement, IMemoryLocation {
4945                 ArrayList Arguments;
4946
4947                 //
4948                 // During bootstrap, it contains the RequestedType,
4949                 // but if `type' is not null, it *might* contain a NewDelegate
4950                 // (because of field multi-initialization)
4951                 //
4952                 public Expression RequestedType;
4953
4954                 MethodGroupExpr method;
4955
4956                 //
4957                 // If set, the new expression is for a value_target, and
4958                 // we will not leave anything on the stack.
4959                 //
4960                 Expression value_target;
4961                 bool value_target_set = false;
4962                 bool is_type_parameter = false;
4963                 
4964                 public New (Expression requested_type, ArrayList arguments, Location l)
4965                 {
4966                         RequestedType = requested_type;
4967                         Arguments = arguments;
4968                         loc = l;
4969                 }
4970
4971                 public bool SetValueTypeVariable (Expression value)
4972                 {
4973                         value_target = value;
4974                         value_target_set = true;
4975                         if (!(value_target is IMemoryLocation)){
4976                                 Error_UnexpectedKind (null, "variable", loc);
4977                                 return false;
4978                         }
4979                         return true;
4980                 }
4981
4982                 //
4983                 // This function is used to disable the following code sequence for
4984                 // value type initialization:
4985                 //
4986                 // AddressOf (temporary)
4987                 // Construct/Init
4988                 // LoadTemporary
4989                 //
4990                 // Instead the provide will have provided us with the address on the
4991                 // stack to store the results.
4992                 //
4993                 static Expression MyEmptyExpression;
4994                 
4995                 public void DisableTemporaryValueType ()
4996                 {
4997                         if (MyEmptyExpression == null)
4998                                 MyEmptyExpression = new EmptyAddressOf ();
4999
5000                         //
5001                         // To enable this, look into:
5002                         // test-34 and test-89 and self bootstrapping.
5003                         //
5004                         // For instance, we can avoid a copy by using `newobj'
5005                         // instead of Call + Push-temp on value types.
5006 //                      value_target = MyEmptyExpression;
5007                 }
5008
5009
5010                 /// <summary>
5011                 /// Converts complex core type syntax like 'new int ()' to simple constant
5012                 /// </summary>
5013                 public static Constant Constantify (Type t)
5014                 {
5015                         if (t == TypeManager.int32_type)
5016                                 return new IntConstant (0, Location.Null);
5017                         if (t == TypeManager.uint32_type)
5018                                 return new UIntConstant (0, Location.Null);
5019                         if (t == TypeManager.int64_type)
5020                                 return new LongConstant (0, Location.Null);
5021                         if (t == TypeManager.uint64_type)
5022                                 return new ULongConstant (0, Location.Null);
5023                         if (t == TypeManager.float_type)
5024                                 return new FloatConstant (0, Location.Null);
5025                         if (t == TypeManager.double_type)
5026                                 return new DoubleConstant (0, Location.Null);
5027                         if (t == TypeManager.short_type)
5028                                 return new ShortConstant (0, Location.Null);
5029                         if (t == TypeManager.ushort_type)
5030                                 return new UShortConstant (0, Location.Null);
5031                         if (t == TypeManager.sbyte_type)
5032                                 return new SByteConstant (0, Location.Null);
5033                         if (t == TypeManager.byte_type)
5034                                 return new ByteConstant (0, Location.Null);
5035                         if (t == TypeManager.char_type)
5036                                 return new CharConstant ('\0', Location.Null);
5037                         if (t == TypeManager.bool_type)
5038                                 return new BoolConstant (false, Location.Null);
5039                         if (t == TypeManager.decimal_type)
5040                                 return new DecimalConstant (0, Location.Null);
5041                         if (TypeManager.IsEnumType (t))
5042                                 return new EnumConstant (Constantify (TypeManager.EnumToUnderlying (t)), t);
5043
5044                         return null;
5045                 }
5046
5047                 //
5048                 // Checks whether the type is an interface that has the
5049                 // [ComImport, CoClass] attributes and must be treated
5050                 // specially
5051                 //
5052                 public Expression CheckComImport (EmitContext ec)
5053                 {
5054                         if (!type.IsInterface)
5055                                 return null;
5056
5057                         //
5058                         // Turn the call into:
5059                         // (the-interface-stated) (new class-referenced-in-coclassattribute ())
5060                         //
5061                         Type real_class = AttributeTester.GetCoClassAttribute (type);
5062                         if (real_class == null)
5063                                 return null;
5064
5065                         New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
5066                         Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
5067                         return cast.Resolve (ec);
5068                 }
5069                 
5070                 public override Expression DoResolve (EmitContext ec)
5071                 {
5072                         //
5073                         // The New DoResolve might be called twice when initializing field
5074                         // expressions (see EmitFieldInitializers, the call to
5075                         // GetInitializerExpression will perform a resolve on the expression,
5076                         // and later the assign will trigger another resolution
5077                         //
5078                         // This leads to bugs (#37014)
5079                         //
5080                         if (type != null){
5081                                 if (RequestedType is NewDelegate)
5082                                         return RequestedType;
5083                                 return this;
5084                         }
5085
5086                         TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
5087                         if (texpr == null)
5088                                 return null;
5089
5090                         type = texpr.Type;
5091
5092                         if (type == TypeManager.void_type) {
5093                                 Error_VoidInvalidInTheContext (loc);
5094                                 return null;
5095                         }
5096
5097                         if (Arguments == null) {
5098                                 Expression c = Constantify (type);
5099                                 if (c != null)
5100                                         return c;
5101                         }
5102
5103                         if (TypeManager.IsDelegateType (type)) {
5104                                 RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5105                                 if (RequestedType != null)
5106                                         if (!(RequestedType is DelegateCreation))
5107                                                 throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
5108                                 return RequestedType;
5109                         }
5110
5111 #if GMCS_SOURCE
5112                         if (type.IsGenericParameter) {
5113                                 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5114
5115                                 if ((gc == null) || (!gc.HasConstructorConstraint && !gc.IsValueType)) {
5116                                         Error (304, String.Format (
5117                                                        "Cannot create an instance of the " +
5118                                                        "variable type '{0}' because it " +
5119                                                        "doesn't have the new() constraint",
5120                                                        type));
5121                                         return null;
5122                                 }
5123
5124                                 if ((Arguments != null) && (Arguments.Count != 0)) {
5125                                         Error (417, String.Format (
5126                                                        "`{0}': cannot provide arguments " +
5127                                                        "when creating an instance of a " +
5128                                                        "variable type.", type));
5129                                         return null;
5130                                 }
5131
5132                                 is_type_parameter = true;
5133                                 eclass = ExprClass.Value;
5134                                 return this;
5135                         }
5136 #endif
5137
5138                         if (type.IsAbstract && type.IsSealed) {
5139                                 Report.SymbolRelatedToPreviousError (type);
5140                                 Report.Error (712, loc, "Cannot create an instance of the static class `{0}'", TypeManager.CSharpName (type));
5141                                 return null;
5142                         }
5143
5144                         if (type.IsInterface || type.IsAbstract){
5145                                 if (!TypeManager.IsGenericType (type)) {
5146                                         RequestedType = CheckComImport (ec);
5147                                         if (RequestedType != null)
5148                                                 return RequestedType;
5149                                 }
5150                                 
5151                                 Report.SymbolRelatedToPreviousError (type);
5152                                 Report.Error (144, loc, "Cannot create an instance of the abstract class or interface `{0}'", TypeManager.CSharpName (type));
5153                                 return null;
5154                         }
5155
5156                         bool is_struct = type.IsValueType;
5157                         eclass = ExprClass.Value;
5158
5159                         //
5160                         // SRE returns a match for .ctor () on structs (the object constructor), 
5161                         // so we have to manually ignore it.
5162                         //
5163                         if (is_struct && Arguments == null)
5164                                 return this;
5165
5166                         // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
5167                         Expression ml = MemberLookupFinal (ec, type, type, ".ctor",
5168                                 MemberTypes.Constructor, AllBindingFlags | BindingFlags.DeclaredOnly, loc);
5169
5170                         if (ml == null)
5171                                 return null;
5172
5173                         method = ml as MethodGroupExpr;
5174
5175                         if (method == null) {
5176                                 ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5177                                 return null;
5178                         }
5179
5180                         if (Arguments != null){
5181                                 foreach (Argument a in Arguments){
5182                                         if (!a.Resolve (ec, loc))
5183                                                 return null;
5184                                 }
5185                         }
5186                         
5187                         method = method.OverloadResolve (ec, Arguments, false, loc);
5188                         if (method == null) {
5189                                 if (almostMatchedMembers.Count != 0)
5190                                         MemberLookupFailed (ec.ContainerType, type, type, ".ctor", null, true, loc);
5191                                 return null;
5192                         }
5193
5194                         return this;
5195                 }
5196
5197                 bool DoEmitTypeParameter (EmitContext ec)
5198                 {
5199 #if GMCS_SOURCE
5200                         ILGenerator ig = ec.ig;
5201 //                      IMemoryLocation ml;
5202
5203                         MethodInfo ci = TypeManager.activator_create_instance.MakeGenericMethod (
5204                                 new Type [] { type });
5205
5206                         GenericConstraints gc = TypeManager.GetTypeParameterConstraints (type);
5207                         if (gc.HasReferenceTypeConstraint || gc.HasClassConstraint) {
5208                                 ig.Emit (OpCodes.Call, ci);
5209                                 return true;
5210                         }
5211
5212                         // Allow DoEmit() to be called multiple times.
5213                         // We need to create a new LocalTemporary each time since
5214                         // you can't share LocalBuilders among ILGeneators.
5215                         LocalTemporary temp = new LocalTemporary (type);
5216
5217                         Label label_activator = ig.DefineLabel ();
5218                         Label label_end = ig.DefineLabel ();
5219
5220                         temp.AddressOf (ec, AddressOp.Store);
5221                         ig.Emit (OpCodes.Initobj, type);
5222
5223                         temp.Emit (ec);
5224                         ig.Emit (OpCodes.Box, type);
5225                         ig.Emit (OpCodes.Brfalse, label_activator);
5226
5227                         temp.AddressOf (ec, AddressOp.Store);
5228                         ig.Emit (OpCodes.Initobj, type);
5229                         temp.Emit (ec);
5230                         ig.Emit (OpCodes.Br, label_end);
5231
5232                         ig.MarkLabel (label_activator);
5233
5234                         ig.Emit (OpCodes.Call, ci);
5235                         ig.MarkLabel (label_end);
5236                         return true;
5237 #else
5238                         throw new InternalErrorException ();
5239 #endif
5240                 }
5241
5242                 //
5243                 // This DoEmit can be invoked in two contexts:
5244                 //    * As a mechanism that will leave a value on the stack (new object)
5245                 //    * As one that wont (init struct)
5246                 //
5247                 // You can control whether a value is required on the stack by passing
5248                 // need_value_on_stack.  The code *might* leave a value on the stack
5249                 // so it must be popped manually
5250                 //
5251                 // If we are dealing with a ValueType, we have a few
5252                 // situations to deal with:
5253                 //
5254                 //    * The target is a ValueType, and we have been provided
5255                 //      the instance (this is easy, we are being assigned).
5256                 //
5257                 //    * The target of New is being passed as an argument,
5258                 //      to a boxing operation or a function that takes a
5259                 //      ValueType.
5260                 //
5261                 //      In this case, we need to create a temporary variable
5262                 //      that is the argument of New.
5263                 //
5264                 // Returns whether a value is left on the stack
5265                 //
5266                 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5267                 {
5268                         bool is_value_type = TypeManager.IsValueType (type);
5269                         ILGenerator ig = ec.ig;
5270
5271                         if (is_value_type){
5272                                 IMemoryLocation ml;
5273
5274                                 // Allow DoEmit() to be called multiple times.
5275                                 // We need to create a new LocalTemporary each time since
5276                                 // you can't share LocalBuilders among ILGeneators.
5277                                 if (!value_target_set)
5278                                         value_target = new LocalTemporary (type);
5279
5280                                 ml = (IMemoryLocation) value_target;
5281                                 ml.AddressOf (ec, AddressOp.Store);
5282                         }
5283
5284                         if (method != null)
5285                                 method.EmitArguments (ec, Arguments);
5286
5287                         if (is_value_type){
5288                                 if (method == null)
5289                                         ig.Emit (OpCodes.Initobj, type);
5290                                 else
5291                                         ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5292                                 if (need_value_on_stack){
5293                                         value_target.Emit (ec);
5294                                         return true;
5295                                 }
5296                                 return false;
5297                         } else {
5298                                 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5299                                 return true;
5300                         }
5301                 }
5302
5303                 public override void Emit (EmitContext ec)
5304                 {
5305                         if (is_type_parameter)
5306                                 DoEmitTypeParameter (ec);
5307                         else
5308                                 DoEmit (ec, true);
5309                 }
5310                 
5311                 public override void EmitStatement (EmitContext ec)
5312                 {
5313                         bool value_on_stack;
5314
5315                         if (is_type_parameter)
5316                                 value_on_stack = DoEmitTypeParameter (ec);
5317                         else
5318                                 value_on_stack = DoEmit (ec, false);
5319
5320                         if (value_on_stack)
5321                                 ec.ig.Emit (OpCodes.Pop);
5322
5323                 }
5324
5325                 public void AddressOf (EmitContext ec, AddressOp Mode)
5326                 {
5327                         if (is_type_parameter) {
5328                                 LocalTemporary temp = new LocalTemporary (type);
5329                                 DoEmitTypeParameter (ec);
5330                                 temp.Store (ec);
5331                                 temp.AddressOf (ec, Mode);
5332                                 return;
5333                         }
5334
5335                         if (!type.IsValueType){
5336                                 //
5337                                 // We throw an exception.  So far, I believe we only need to support
5338                                 // value types:
5339                                 // foreach (int j in new StructType ())
5340                                 // see bug 42390
5341                                 //
5342                                 throw new Exception ("AddressOf should not be used for classes");
5343                         }
5344
5345                         if (!value_target_set)
5346                                 value_target = new LocalTemporary (type);
5347                         IMemoryLocation ml = (IMemoryLocation) value_target;
5348
5349                         ml.AddressOf (ec, AddressOp.Store);
5350                         if (method == null) {
5351                                 ec.ig.Emit (OpCodes.Initobj, type);
5352                         } else {
5353                                 method.EmitArguments (ec, Arguments);
5354                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5355                         }
5356                         
5357                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5358                 }
5359
5360                 protected override void CloneTo (CloneContext clonectx, Expression t)
5361                 {
5362                         New target = (New) t;
5363
5364                         target.RequestedType = RequestedType.Clone (clonectx);
5365                         if (Arguments != null){
5366                                 target.Arguments = new ArrayList ();
5367                                 foreach (Argument a in Arguments){
5368                                         target.Arguments.Add (a.Clone (clonectx));
5369                                 }
5370                         }
5371                 }
5372         }
5373
5374         /// <summary>
5375         ///   14.5.10.2: Represents an array creation expression.
5376         /// </summary>
5377         ///
5378         /// <remarks>
5379         ///   There are two possible scenarios here: one is an array creation
5380         ///   expression that specifies the dimensions and optionally the
5381         ///   initialization data and the other which does not need dimensions
5382         ///   specified but where initialization data is mandatory.
5383         /// </remarks>
5384         public class ArrayCreation : Expression {
5385                 Expression requested_base_type;
5386                 ArrayList initializers;
5387
5388                 //
5389                 // The list of Argument types.
5390                 // This is used to construct the `newarray' or constructor signature
5391                 //
5392                 protected ArrayList arguments;
5393                 
5394                 protected Type array_element_type;
5395                 bool expect_initializers = false;
5396                 int num_arguments = 0;
5397                 protected int dimensions;
5398                 protected readonly string rank;
5399
5400                 protected ArrayList array_data;
5401
5402                 IDictionary bounds;
5403
5404                 // The number of constants in array initializers
5405                 int const_initializers_count;
5406                 bool only_constant_initializers;
5407                 
5408                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5409                 {
5410                         this.requested_base_type = requested_base_type;
5411                         this.initializers = initializers;
5412                         this.rank = rank;
5413                         loc = l;
5414
5415                         arguments = new ArrayList ();
5416
5417                         foreach (Expression e in exprs) {
5418                                 arguments.Add (new Argument (e, Argument.AType.Expression));
5419                                 num_arguments++;
5420                         }
5421                 }
5422
5423                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5424                 {
5425                         this.requested_base_type = requested_base_type;
5426                         this.initializers = initializers;
5427                         this.rank = rank;
5428                         loc = l;
5429
5430                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5431                         //
5432                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
5433                         //
5434                         //dimensions = tmp.Length - 1;
5435                         expect_initializers = true;
5436                 }
5437
5438                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5439                 {
5440                         StringBuilder sb = new StringBuilder (rank);
5441                         
5442                         sb.Append ("[");
5443                         for (int i = 1; i < idx_count; i++)
5444                                 sb.Append (",");
5445                         
5446                         sb.Append ("]");
5447
5448                         return new ComposedCast (base_type, sb.ToString (), loc);
5449                 }
5450
5451                 void Error_IncorrectArrayInitializer ()
5452                 {
5453                         Error (178, "Invalid rank specifier: expected `,' or `]'");
5454                 }
5455                 
5456                 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5457                 {
5458                         if (specified_dims) { 
5459                                 Argument a = (Argument) arguments [idx];
5460
5461                                 if (!a.Resolve (ec, loc))
5462                                         return false;
5463
5464                                 Constant c = a.Expr as Constant;
5465                                 if (c != null) {
5466                                         c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5467                                 }
5468
5469                                 if (c == null) {
5470                                         Report.Error (150, a.Expr.Location, "A constant value is expected");
5471                                         return false;
5472                                 }
5473
5474                                 int value = (int) c.GetValue ();
5475                                 
5476                                 if (value != probe.Count) {
5477                                         Error_IncorrectArrayInitializer ();
5478                                         return false;
5479                                 }
5480                                 
5481                                 bounds [idx] = value;
5482                         }
5483
5484                         int child_bounds = -1;
5485                         only_constant_initializers = true;
5486                         for (int i = 0; i < probe.Count; ++i) {
5487                                 object o = probe [i];
5488                                 if (o is ArrayList) {
5489                                         ArrayList sub_probe = o as ArrayList;
5490                                         int current_bounds = sub_probe.Count;
5491                                         
5492                                         if (child_bounds == -1) 
5493                                                 child_bounds = current_bounds;
5494
5495                                         else if (child_bounds != current_bounds){
5496                                                 Error_IncorrectArrayInitializer ();
5497                                                 return false;
5498                                         }
5499                                         if (idx + 1 >= dimensions){
5500                                                 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5501                                                 return false;
5502                                         }
5503                                         
5504                                         bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5505                                         if (!ret)
5506                                                 return false;
5507                                 } else {
5508                                         if (child_bounds != -1){
5509                                                 Error_IncorrectArrayInitializer ();
5510                                                 return false;
5511                                         }
5512                                         
5513                                         Expression element = ResolveArrayElement (ec, (Expression) o);
5514                                         if (element == null)
5515                                                 continue;
5516
5517                                         // Initializers with the default values can be ignored
5518                                         Constant c = element as Constant;
5519                                         if (c != null) {
5520                                                 if (c.IsDefaultInitializer (array_element_type)) {
5521                                                         element = null;
5522                                                 }
5523                                                 else {
5524                                                         ++const_initializers_count;
5525                                                 }
5526                                         } else {
5527                                                 only_constant_initializers = false;
5528                                         }
5529                                         
5530                                         array_data.Add (element);
5531                                 }
5532                         }
5533
5534                         return true;
5535                 }
5536                 
5537                 public void UpdateIndices ()
5538                 {
5539                         int i = 0;
5540                         for (ArrayList probe = initializers; probe != null;) {
5541                                 if (probe.Count > 0 && probe [0] is ArrayList) {
5542                                         Expression e = new IntConstant (probe.Count, Location.Null);
5543                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5544
5545                                         bounds [i++] =  probe.Count;
5546                                         
5547                                         probe = (ArrayList) probe [0];
5548                                         
5549                                 } else {
5550                                         Expression e = new IntConstant (probe.Count, Location.Null);
5551                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5552
5553                                         bounds [i++] = probe.Count;
5554                                         return;
5555                                 }
5556                         }
5557
5558                 }
5559
5560                 protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
5561                 {
5562                         element = element.Resolve (ec);
5563                         if (element == null)
5564                                 return null;
5565
5566                         return Convert.ImplicitConversionRequired (
5567                                 ec, element, array_element_type, loc);
5568                 }
5569
5570                 protected bool ResolveInitializers (EmitContext ec)
5571                 {
5572                         if (initializers == null) {
5573                                 return !expect_initializers;
5574                         }
5575                                                 
5576                         //
5577                         // We use this to store all the date values in the order in which we
5578                         // will need to store them in the byte blob later
5579                         //
5580                         array_data = new ArrayList ();
5581                         bounds = new System.Collections.Specialized.HybridDictionary ();
5582                         
5583                         if (arguments != null)
5584                                 return CheckIndices (ec, initializers, 0, true);
5585
5586                         arguments = new ArrayList ();
5587
5588                         if (!CheckIndices (ec, initializers, 0, false))
5589                                 return false;
5590                                 
5591                         UpdateIndices ();
5592                                 
5593                         return true;
5594                 }
5595
5596                 //
5597                 // Resolved the type of the array
5598                 //
5599                 bool ResolveArrayType (EmitContext ec)
5600                 {
5601                         if (requested_base_type == null) {
5602                                 Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
5603                                 return false;
5604                         }
5605                         
5606                         StringBuilder array_qualifier = new StringBuilder (rank);
5607
5608                         //
5609                         // `In the first form allocates an array instace of the type that results
5610                         // from deleting each of the individual expression from the expression list'
5611                         //
5612                         if (num_arguments > 0) {
5613                                 array_qualifier.Append ("[");
5614                                 for (int i = num_arguments-1; i > 0; i--)
5615                                         array_qualifier.Append (",");
5616                                 array_qualifier.Append ("]");
5617                         }
5618
5619                         //
5620                         // Lookup the type
5621                         //
5622                         TypeExpr array_type_expr;
5623                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5624                         array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5625                         if (array_type_expr == null)
5626                                 return false;
5627
5628                         type = array_type_expr.Type;
5629                         array_element_type = TypeManager.GetElementType (type);
5630                         dimensions = type.GetArrayRank ();
5631
5632                         return true;
5633                 }
5634
5635                 public override Expression DoResolve (EmitContext ec)
5636                 {
5637                         if (type != null)
5638                                 return this;
5639
5640                         if (!ResolveArrayType (ec))
5641                                 return null;
5642                         
5643                         if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
5644                                 Report.Error (719, loc, "`{0}': array elements cannot be of static type",
5645                                         TypeManager.CSharpName (array_element_type));
5646                         }
5647
5648                         //
5649                         // First step is to validate the initializers and fill
5650                         // in any missing bits
5651                         //
5652                         if (!ResolveInitializers (ec))
5653                                 return null;
5654
5655                         if (arguments.Count != dimensions) {
5656                                 Error_IncorrectArrayInitializer ();
5657                         }
5658
5659                         foreach (Argument a in arguments){
5660                                 if (!a.Resolve (ec, loc))
5661                                         return null;
5662
5663                                 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5664                                 if (real_arg == null)
5665                                         return null;
5666
5667                                 a.Expr = real_arg;
5668                         }
5669                                                         
5670                         eclass = ExprClass.Value;
5671                         return this;
5672                 }
5673
5674                 MethodInfo GetArrayMethod (int arguments)
5675                 {
5676                         ModuleBuilder mb = CodeGen.Module.Builder;
5677
5678                         Type[] arg_types = new Type[arguments];
5679                         for (int i = 0; i < arguments; i++)
5680                                 arg_types[i] = TypeManager.int32_type;
5681
5682                         MethodInfo mi = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5683                                                         arg_types);
5684
5685                         if (mi == null) {
5686                                 Report.Error (-6, "New invocation: Can not find a constructor for " +
5687                                                   "this argument list");
5688                                 return null;
5689                         }
5690
5691                         return mi; 
5692                 }
5693
5694                 byte [] MakeByteBlob ()
5695                 {
5696                         int factor;
5697                         byte [] data;
5698                         byte [] element;
5699                         int count = array_data.Count;
5700
5701                         if (array_element_type.IsEnum)
5702                                 array_element_type = TypeManager.EnumToUnderlying (array_element_type);
5703                         
5704                         factor = GetTypeSize (array_element_type);
5705                         if (factor == 0)
5706                                 throw new Exception ("unrecognized type in MakeByteBlob: " + array_element_type);
5707
5708                         data = new byte [(count * factor + 4) & ~3];
5709                         int idx = 0;
5710
5711                         for (int i = 0; i < count; ++i) {
5712                                 object v = array_data [i];
5713
5714                                 if (v is EnumConstant)
5715                                         v = ((EnumConstant) v).Child;
5716                                 
5717                                 if (v is Constant && !(v is StringConstant))
5718                                         v = ((Constant) v).GetValue ();
5719                                 else {
5720                                         idx += factor;
5721                                         continue;
5722                                 }
5723                                 
5724                                 if (array_element_type == TypeManager.int64_type){
5725                                         if (!(v is Expression)){
5726                                                 long val = (long) v;
5727                                                 
5728                                                 for (int j = 0; j < factor; ++j) {
5729                                                         data [idx + j] = (byte) (val & 0xFF);
5730                                                         val = (val >> 8);
5731                                                 }
5732                                         }
5733                                 } else if (array_element_type == TypeManager.uint64_type){
5734                                         if (!(v is Expression)){
5735                                                 ulong val = (ulong) v;
5736
5737                                                 for (int j = 0; j < factor; ++j) {
5738                                                         data [idx + j] = (byte) (val & 0xFF);
5739                                                         val = (val >> 8);
5740                                                 }
5741                                         }
5742                                 } else if (array_element_type == TypeManager.float_type) {
5743                                         if (!(v is Expression)){
5744                                                 element = BitConverter.GetBytes ((float) v);
5745                                                         
5746                                                 for (int j = 0; j < factor; ++j)
5747                                                         data [idx + j] = element [j];
5748                                                 if (!BitConverter.IsLittleEndian)
5749                                                         System.Array.Reverse (data, idx, 4);
5750                                         }
5751                                 } else if (array_element_type == TypeManager.double_type) {
5752                                         if (!(v is Expression)){
5753                                                 element = BitConverter.GetBytes ((double) v);
5754
5755                                                 for (int j = 0; j < factor; ++j)
5756                                                         data [idx + j] = element [j];
5757
5758                                                 // FIXME: Handle the ARM float format.
5759                                                 if (!BitConverter.IsLittleEndian)
5760                                                         System.Array.Reverse (data, idx, 8);
5761                                         }
5762                                 } else if (array_element_type == TypeManager.char_type){
5763                                         if (!(v is Expression)){
5764                                                 int val = (int) ((char) v);
5765                                                 
5766                                                 data [idx] = (byte) (val & 0xff);
5767                                                 data [idx+1] = (byte) (val >> 8);
5768                                         }
5769                                 } else if (array_element_type == TypeManager.short_type){
5770                                         if (!(v is Expression)){
5771                                                 int val = (int) ((short) v);
5772                                         
5773                                                 data [idx] = (byte) (val & 0xff);
5774                                                 data [idx+1] = (byte) (val >> 8);
5775                                         }
5776                                 } else if (array_element_type == TypeManager.ushort_type){
5777                                         if (!(v is Expression)){
5778                                                 int val = (int) ((ushort) v);
5779                                         
5780                                                 data [idx] = (byte) (val & 0xff);
5781                                                 data [idx+1] = (byte) (val >> 8);
5782                                         }
5783                                 } else if (array_element_type == TypeManager.int32_type) {
5784                                         if (!(v is Expression)){
5785                                                 int val = (int) v;
5786                                         
5787                                                 data [idx]   = (byte) (val & 0xff);
5788                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
5789                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
5790                                                 data [idx+3] = (byte) (val >> 24);
5791                                         }
5792                                 } else if (array_element_type == TypeManager.uint32_type) {
5793                                         if (!(v is Expression)){
5794                                                 uint val = (uint) v;
5795                                         
5796                                                 data [idx]   = (byte) (val & 0xff);
5797                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
5798                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
5799                                                 data [idx+3] = (byte) (val >> 24);
5800                                         }
5801                                 } else if (array_element_type == TypeManager.sbyte_type) {
5802                                         if (!(v is Expression)){
5803                                                 sbyte val = (sbyte) v;
5804                                                 data [idx] = (byte) val;
5805                                         }
5806                                 } else if (array_element_type == TypeManager.byte_type) {
5807                                         if (!(v is Expression)){
5808                                                 byte val = (byte) v;
5809                                                 data [idx] = (byte) val;
5810                                         }
5811                                 } else if (array_element_type == TypeManager.bool_type) {
5812                                         if (!(v is Expression)){
5813                                                 bool val = (bool) v;
5814                                                 data [idx] = (byte) (val ? 1 : 0);
5815                                         }
5816                                 } else if (array_element_type == TypeManager.decimal_type){
5817                                         if (!(v is Expression)){
5818                                                 int [] bits = Decimal.GetBits ((decimal) v);
5819                                                 int p = idx;
5820
5821                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
5822                                                 int [] nbits = new int [4];
5823                                                 nbits [0] = bits [3];
5824                                                 nbits [1] = bits [2];
5825                                                 nbits [2] = bits [0];
5826                                                 nbits [3] = bits [1];
5827                                                 
5828                                                 for (int j = 0; j < 4; j++){
5829                                                         data [p++] = (byte) (nbits [j] & 0xff);
5830                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5831                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5832                                                         data [p++] = (byte) (nbits [j] >> 24);
5833                                                 }
5834                                         }
5835                                 } else
5836                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + array_element_type);
5837
5838                                 idx += factor;
5839                         }
5840
5841                         return data;
5842                 }
5843
5844                 //
5845                 // Emits the initializers for the array
5846                 //
5847                 void EmitStaticInitializers (EmitContext ec)
5848                 {
5849                         //
5850                         // First, the static data
5851                         //
5852                         FieldBuilder fb;
5853                         ILGenerator ig = ec.ig;
5854                         
5855                         byte [] data = MakeByteBlob ();
5856
5857                         fb = RootContext.MakeStaticData (data);
5858
5859                         ig.Emit (OpCodes.Dup);
5860                         ig.Emit (OpCodes.Ldtoken, fb);
5861                         ig.Emit (OpCodes.Call,
5862                                  TypeManager.void_initializearray_array_fieldhandle);
5863                 }
5864
5865                 //
5866                 // Emits pieces of the array that can not be computed at compile
5867                 // time (variables and string locations).
5868                 //
5869                 // This always expect the top value on the stack to be the array
5870                 //
5871                 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5872                 {
5873                         ILGenerator ig = ec.ig;
5874                         int dims = bounds.Count;
5875                         int [] current_pos = new int [dims];
5876
5877                         MethodInfo set = null;
5878
5879                         if (dims != 1){
5880                                 Type [] args = new Type [dims + 1];
5881
5882                                 for (int j = 0; j < dims; j++)
5883                                         args [j] = TypeManager.int32_type;
5884                                 args [dims] = array_element_type;
5885                                 
5886                                 set = CodeGen.Module.Builder.GetArrayMethod (
5887                                         type, "Set",
5888                                         CallingConventions.HasThis | CallingConventions.Standard,
5889                                         TypeManager.void_type, args);
5890                         }
5891
5892                         for (int i = 0; i < array_data.Count; i++){
5893
5894                                 Expression e = (Expression)array_data [i];
5895
5896                                 // Constant can be initialized via StaticInitializer
5897                                 if (e != null && !(!emitConstants && e is Constant)) {
5898                                         Type etype = e.Type;
5899
5900                                         ig.Emit (OpCodes.Dup);
5901
5902                                         for (int idx = 0; idx < dims; idx++) 
5903                                                 IntConstant.EmitInt (ig, current_pos [idx]);
5904
5905                                         //
5906                                         // If we are dealing with a struct, get the
5907                                         // address of it, so we can store it.
5908                                         //
5909                                         if ((dims == 1) && etype.IsValueType &&
5910                                             (!TypeManager.IsBuiltinOrEnum (etype) ||
5911                                              etype == TypeManager.decimal_type)) {
5912                                                 if (e is New){
5913                                                         New n = (New) e;
5914
5915                                                         //
5916                                                         // Let new know that we are providing
5917                                                         // the address where to store the results
5918                                                         //
5919                                                         n.DisableTemporaryValueType ();
5920                                                 }
5921
5922                                                 ig.Emit (OpCodes.Ldelema, etype);
5923                                         }
5924
5925                                         e.Emit (ec);
5926
5927                                         if (dims == 1) {
5928                                                 bool is_stobj, has_type_arg;
5929                                                 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5930                                                 if (is_stobj)
5931                                                         ig.Emit (OpCodes.Stobj, etype);
5932                                                 else if (has_type_arg)
5933                                                         ig.Emit (op, etype);
5934                                                 else
5935                                                         ig.Emit (op);
5936                                         } else 
5937                                                 ig.Emit (OpCodes.Call, set);
5938
5939                                 }
5940                                 
5941                                 //
5942                                 // Advance counter
5943                                 //
5944                                 for (int j = dims - 1; j >= 0; j--){
5945                                         current_pos [j]++;
5946                                         if (current_pos [j] < (int) bounds [j])
5947                                                 break;
5948                                         current_pos [j] = 0;
5949                                 }
5950                         }
5951                 }
5952
5953                 void EmitArrayArguments (EmitContext ec)
5954                 {
5955                         ILGenerator ig = ec.ig;
5956                         
5957                         foreach (Argument a in arguments) {
5958                                 Type atype = a.Type;
5959                                 a.Emit (ec);
5960
5961                                 if (atype == TypeManager.uint64_type)
5962                                         ig.Emit (OpCodes.Conv_Ovf_U4);
5963                                 else if (atype == TypeManager.int64_type)
5964                                         ig.Emit (OpCodes.Conv_Ovf_I4);
5965                         }
5966                 }
5967                 
5968                 public override void Emit (EmitContext ec)
5969                 {
5970                         ILGenerator ig = ec.ig;
5971                         
5972                         EmitArrayArguments (ec);
5973                         if (arguments.Count == 1)
5974                                 ig.Emit (OpCodes.Newarr, array_element_type);
5975                         else {
5976                                 ig.Emit (OpCodes.Newobj, GetArrayMethod (arguments.Count));
5977                         }
5978                         
5979                         if (initializers == null)
5980                                 return;
5981
5982                         // Emit static initializer for arrays which have contain more than 4 items and
5983                         // the static initializer will initialize at least 25% of array values.
5984                         // NOTE: const_initializers_count does not contain default constant values.
5985                         if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
5986                                 TypeManager.IsPrimitiveType (array_element_type)) {
5987                                 EmitStaticInitializers (ec);
5988
5989                                 if (!only_constant_initializers)
5990                                         EmitDynamicInitializers (ec, false);
5991                         } else {
5992                                 EmitDynamicInitializers (ec, true);
5993                         }                               
5994                 }
5995
5996                 public override bool GetAttributableValue (Type valueType, out object value)
5997                 {
5998                         if (arguments.Count != 1) {
5999                                 // Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6000                                 return base.GetAttributableValue (null, out value);
6001                         }
6002
6003                         if (array_data == null) {
6004                                 Constant c = (Constant)((Argument)arguments [0]).Expr;
6005                                 if (c.IsDefaultValue) {
6006                                         value = Array.CreateInstance (array_element_type, 0);
6007                                         return true;
6008                                 }
6009                                 // Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6010                                 return base.GetAttributableValue (null, out value);
6011                         }
6012                         
6013                         Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6014                         object element_value;
6015                         for (int i = 0; i < ret.Length; ++i)
6016                         {
6017                                 Expression e = (Expression)array_data [i];
6018
6019                                 // Is null when an initializer is optimized (value == predefined value)
6020                                 if (e == null) 
6021                                         continue;
6022
6023                                 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6024                                         value = null;
6025                                         return false;
6026                                 }
6027                                 ret.SetValue (element_value, i);
6028                         }
6029                         value = ret;
6030                         return true;
6031                 }
6032                 
6033                 protected override void CloneTo (CloneContext clonectx, Expression t)
6034                 {
6035                         ArrayCreation target = (ArrayCreation) t;
6036
6037                         target.requested_base_type = requested_base_type.Clone (clonectx);
6038                         target.arguments = new ArrayList ();
6039                         foreach (Argument a in arguments)
6040                                 target.arguments.Add (a.Clone (clonectx));
6041
6042                         if (initializers != null){
6043                                 target.initializers = new ArrayList ();
6044                                 foreach (Expression initializer in initializers)
6045                                         target.initializers.Add (initializer.Clone (clonectx));
6046                         }
6047                 }
6048         }
6049         
6050         //
6051         // Represents an implicitly typed array epxression
6052         //
6053         public class ImplicitlyTypedArrayCreation : ArrayCreation
6054         {
6055                 public ImplicitlyTypedArrayCreation (string rank, ArrayList initializers, Location loc)
6056                         : base (null, rank, initializers, loc)
6057                 {
6058                         if (rank.Length > 2) {
6059                                 while (rank [++dimensions] == ',');
6060                         } else {
6061                                 dimensions = 1;
6062                         }
6063                 }
6064
6065                 public override Expression DoResolve (EmitContext ec)
6066                 {
6067                         if (type != null)
6068                                 return this;
6069
6070                         if (!ResolveInitializers (ec))
6071                                 return null;
6072
6073                         if (array_element_type == null || array_element_type == TypeManager.null_type ||
6074                                 array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
6075                                 arguments.Count != dimensions) {
6076                                 Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
6077                                 return null;
6078                         }
6079
6080                         //
6081                         // At this point we found common base type for all initializer elements
6082                         // but we have to be sure that all static initializer elements are of
6083                         // same type
6084                         //
6085                         UnifyInitializerElement (ec);
6086
6087                         type = TypeManager.GetConstructedType (array_element_type, rank);
6088                         eclass = ExprClass.Value;
6089                         return this;
6090                 }
6091
6092                 //
6093                 // Converts static initializer only
6094                 //
6095                 void UnifyInitializerElement (EmitContext ec)
6096                 {
6097                         for (int i = 0; i < array_data.Count; ++i) {
6098                                 Expression e = (Expression)array_data[i];
6099                                 if (e != null)
6100                                         array_data [i] = Convert.ImplicitConversionStandard (ec, e, array_element_type, Location.Null);
6101                         }
6102                 }
6103
6104                 protected override Expression ResolveArrayElement (EmitContext ec, Expression element)
6105                 {
6106                         element = element.Resolve (ec);
6107                         if (element == null)
6108                                 return null;
6109                         
6110                         if (array_element_type == null) {
6111                                 array_element_type = element.Type;
6112                                 return element;
6113                         }
6114
6115                         if (Convert.ImplicitStandardConversionExists (element, array_element_type)) {
6116                                 return element;
6117                         }
6118
6119                         if (Convert.ImplicitStandardConversionExists (new TypeExpression (array_element_type, loc), element.Type)) {
6120                                 array_element_type = element.Type;
6121                                 return element;
6122                         }
6123
6124                         element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
6125                         return element;
6126                 }
6127         }       
6128         
6129         public sealed class CompilerGeneratedThis : This
6130         {
6131                 public static This Instance = new CompilerGeneratedThis ();
6132
6133                 private CompilerGeneratedThis ()
6134                         : base (Location.Null)
6135                 {
6136                 }
6137
6138                 public override Expression DoResolve (EmitContext ec)
6139                 {
6140                         eclass = ExprClass.Variable;
6141                         type = ec.ContainerType;
6142                         variable = new SimpleThis (type);
6143                         return this;
6144                 }
6145         }
6146         
6147         /// <summary>
6148         ///   Represents the `this' construct
6149         /// </summary>
6150
6151         public class This : VariableReference, IVariable
6152         {
6153                 Block block;
6154                 VariableInfo variable_info;
6155                 protected Variable variable;
6156                 bool is_struct;
6157
6158                 public This (Block block, Location loc)
6159                 {
6160                         this.loc = loc;
6161                         this.block = block;
6162                 }
6163
6164                 public This (Location loc)
6165                 {
6166                         this.loc = loc;
6167                 }
6168
6169                 public VariableInfo VariableInfo {
6170                         get { return variable_info; }
6171                 }
6172
6173                 public bool VerifyFixed ()
6174                 {
6175                         return !TypeManager.IsValueType (Type);
6176                 }
6177
6178                 public override bool IsRef {
6179                         get { return is_struct; }
6180                 }
6181
6182                 public override Variable Variable {
6183                         get { return variable; }
6184                 }
6185
6186                 public bool ResolveBase (EmitContext ec)
6187                 {
6188                         eclass = ExprClass.Variable;
6189
6190                         if (ec.TypeContainer.CurrentType != null)
6191                                 type = ec.TypeContainer.CurrentType;
6192                         else
6193                                 type = ec.ContainerType;
6194
6195                         is_struct = ec.TypeContainer is Struct;
6196
6197                         if (ec.IsStatic) {
6198                                 Error (26, "Keyword `this' is not valid in a static property, " +
6199                                        "static method, or static field initializer");
6200                                 return false;
6201                         }
6202
6203                         if (block != null) {
6204                                 if (block.Toplevel.ThisVariable != null)
6205                                         variable_info = block.Toplevel.ThisVariable.VariableInfo;
6206
6207                                 AnonymousContainer am = ec.CurrentAnonymousMethod;
6208                                 if (is_struct && (am != null) && !am.IsIterator) {
6209                                         Report.Error (1673, loc, "Anonymous methods inside structs " +
6210                                                       "cannot access instance members of `this'. " +
6211                                                       "Consider copying `this' to a local variable " +
6212                                                       "outside the anonymous method and using the " +
6213                                                       "local instead.");
6214                                         return false;
6215                                 }
6216
6217                                 RootScopeInfo host = block.Toplevel.RootScope;
6218                                 if ((host != null) && !ec.IsConstructor &&
6219                                     (!is_struct || host.IsIterator)) {
6220                                         variable = host.CaptureThis ();
6221                                         type = variable.Type;
6222                                         is_struct = false;
6223                                 }
6224                         }
6225
6226                         if (variable == null)
6227                                 variable = new SimpleThis (type);
6228                         
6229                         return true;
6230                 }
6231
6232                 //
6233                 // Called from Invocation to check if the invocation is correct
6234                 //
6235                 public bool CheckThisUsage (EmitContext ec)
6236                 {
6237                         if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6238                             !variable_info.IsAssigned (ec)) {
6239                                 Error (188, "The `this' object cannot be used before all of its " +
6240                                        "fields are assigned to");
6241                                 variable_info.SetAssigned (ec);
6242                                 return false;
6243                         }
6244
6245                         return true;
6246                 }
6247                 
6248                 public override Expression DoResolve (EmitContext ec)
6249                 {
6250                         if (!ResolveBase (ec))
6251                                 return null;
6252
6253
6254                         if (ec.IsFieldInitializer) {
6255                                 Error (27, "Keyword `this' is not available in the current context");
6256                                 return null;
6257                         }
6258
6259                         return this;
6260                 }
6261
6262                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6263                 {
6264                         if (!ResolveBase (ec))
6265                                 return null;
6266
6267                         if (variable_info != null)
6268                                 variable_info.SetAssigned (ec);
6269                         
6270                         if (ec.TypeContainer is Class){
6271                                 Error (1604, "Cannot assign to 'this' because it is read-only");
6272                                 return null;
6273                         }
6274
6275                         return this;
6276                 }
6277                 public override int GetHashCode()
6278                 {
6279                         return block.GetHashCode ();
6280                 }
6281
6282                 public override bool Equals (object obj)
6283                 {
6284                         This t = obj as This;
6285                         if (t == null)
6286                                 return false;
6287
6288                         return block == t.block;
6289                 }
6290
6291                 protected class SimpleThis : Variable
6292                 {
6293                         Type type;
6294
6295                         public SimpleThis (Type type)
6296                         {
6297                                 this.type = type;
6298                         }
6299
6300                         public override Type Type {
6301                                 get { return type; }
6302                         }
6303
6304                         public override bool HasInstance {
6305                                 get { return false; }
6306                         }
6307
6308                         public override bool NeedsTemporary {
6309                                 get { return false; }
6310                         }
6311
6312                         public override void EmitInstance (EmitContext ec)
6313                         {
6314                                 // Do nothing.
6315                         }
6316
6317                         public override void Emit (EmitContext ec)
6318                         {
6319                                 ec.ig.Emit (OpCodes.Ldarg_0);
6320                         }
6321
6322                         public override void EmitAssign (EmitContext ec)
6323                         {
6324                                 throw new InvalidOperationException ();
6325                         }
6326
6327                         public override void EmitAddressOf (EmitContext ec)
6328                         {
6329                                 ec.ig.Emit (OpCodes.Ldarg_0);
6330                         }
6331                 }
6332
6333                 protected override void CloneTo (CloneContext clonectx, Expression t)
6334                 {
6335                         This target = (This) t;
6336
6337                         target.block = clonectx.LookupBlock (block);
6338                 }
6339         }
6340
6341         /// <summary>
6342         ///   Represents the `__arglist' construct
6343         /// </summary>
6344         public class ArglistAccess : Expression
6345         {
6346                 public ArglistAccess (Location loc)
6347                 {
6348                         this.loc = loc;
6349                 }
6350
6351                 public override Expression DoResolve (EmitContext ec)
6352                 {
6353                         eclass = ExprClass.Variable;
6354                         type = TypeManager.runtime_argument_handle_type;
6355
6356                         if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs) 
6357                         {
6358                                 Error (190, "The __arglist construct is valid only within " +
6359                                        "a variable argument method");
6360                                 return null;
6361                         }
6362
6363                         return this;
6364                 }
6365
6366                 public override void Emit (EmitContext ec)
6367                 {
6368                         ec.ig.Emit (OpCodes.Arglist);
6369                 }
6370
6371                 protected override void CloneTo (CloneContext clonectx, Expression target)
6372                 {
6373                         // nothing.
6374                 }
6375         }
6376
6377         /// <summary>
6378         ///   Represents the `__arglist (....)' construct
6379         /// </summary>
6380         public class Arglist : Expression
6381         {
6382                 public Argument[] Arguments;
6383
6384                 public Arglist (Location loc)
6385                         : this (Argument.Empty, loc)
6386                 {
6387                 }
6388
6389                 public Arglist (Argument[] args, Location l)
6390                 {
6391                         Arguments = args;
6392                         loc = l;
6393                 }
6394
6395                 public Type[] ArgumentTypes {
6396                         get {
6397                                 Type[] retval = new Type [Arguments.Length];
6398                                 for (int i = 0; i < Arguments.Length; i++)
6399                                         retval [i] = Arguments [i].Type;
6400                                 return retval;
6401                         }
6402                 }
6403
6404                 public override Expression DoResolve (EmitContext ec)
6405                 {
6406                         eclass = ExprClass.Variable;
6407                         type = TypeManager.runtime_argument_handle_type;
6408
6409                         foreach (Argument arg in Arguments) {
6410                                 if (!arg.Resolve (ec, loc))
6411                                         return null;
6412                         }
6413
6414                         return this;
6415                 }
6416
6417                 public override void Emit (EmitContext ec)
6418                 {
6419                         foreach (Argument arg in Arguments)
6420                                 arg.Emit (ec);
6421                 }
6422
6423                 protected override void CloneTo (CloneContext clonectx, Expression t)
6424                 {
6425                         Arglist target = (Arglist) t;
6426
6427                         target.Arguments = new Argument [Arguments.Length];
6428                         for (int i = 0; i < Arguments.Length; i++)
6429                                 target.Arguments [i] = Arguments [i].Clone (clonectx);
6430                 }
6431         }
6432
6433         //
6434         // This produces the value that renders an instance, used by the iterators code
6435         //
6436         public class ProxyInstance : Expression, IMemoryLocation  {
6437                 public override Expression DoResolve (EmitContext ec)
6438                 {
6439                         eclass = ExprClass.Variable;
6440                         type = ec.ContainerType;
6441                         return this;
6442                 }
6443                 
6444                 public override void Emit (EmitContext ec)
6445                 {
6446                         ec.ig.Emit (OpCodes.Ldarg_0);
6447
6448                 }
6449                 
6450                 public void AddressOf (EmitContext ec, AddressOp mode)
6451                 {
6452                         ec.ig.Emit (OpCodes.Ldarg_0);
6453                 }
6454         }
6455
6456         /// <summary>
6457         ///   Implements the typeof operator
6458         /// </summary>
6459         public class TypeOf : Expression {
6460                 Expression QueriedType;
6461                 protected Type typearg;
6462                 
6463                 public TypeOf (Expression queried_type, Location l)
6464                 {
6465                         QueriedType = queried_type;
6466                         loc = l;
6467                 }
6468
6469                 public override Expression DoResolve (EmitContext ec)
6470                 {
6471                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6472                         if (texpr == null)
6473                                 return null;
6474
6475                         typearg = texpr.Type;
6476
6477                         if (typearg == TypeManager.void_type) {
6478                                 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6479                                 return null;
6480                         }
6481
6482                         if (typearg.IsPointer && !ec.InUnsafe){
6483                                 UnsafeError (loc);
6484                                 return null;
6485                         }
6486
6487                         type = TypeManager.type_type;
6488                         // Even though what is returned is a type object, it's treated as a value by the compiler.
6489                         // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6490                         eclass = ExprClass.Value;
6491                         return this;
6492                 }
6493
6494                 public override void Emit (EmitContext ec)
6495                 {
6496                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
6497                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6498                 }
6499
6500                 public override bool GetAttributableValue (Type valueType, out object value)
6501                 {
6502                         if (TypeManager.ContainsGenericParameters (typearg)) {
6503                                 Report.SymbolRelatedToPreviousError(typearg);
6504                                 Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters",
6505                                              TypeManager.CSharpName(typearg));
6506                                 value = null;
6507                                 return false;
6508                         }
6509
6510                         if (valueType == TypeManager.object_type) {
6511                                 value = (object)typearg;
6512                                 return true;
6513                         }
6514                         value = typearg;
6515                         return true;
6516                 }
6517
6518                 public Type TypeArgument
6519                 {
6520                         get
6521                         {
6522                                 return typearg;
6523                         }
6524                 }
6525
6526                 protected override void CloneTo (CloneContext clonectx, Expression t)
6527                 {
6528                         TypeOf target = (TypeOf) t;
6529
6530                         target.QueriedType = QueriedType.Clone (clonectx);
6531                 }
6532         }
6533
6534         /// <summary>
6535         ///   Implements the `typeof (void)' operator
6536         /// </summary>
6537         public class TypeOfVoid : TypeOf {
6538                 public TypeOfVoid (Location l) : base (null, l)
6539                 {
6540                         loc = l;
6541                 }
6542
6543                 public override Expression DoResolve (EmitContext ec)
6544                 {
6545                         type = TypeManager.type_type;
6546                         typearg = TypeManager.void_type;
6547                         // See description in TypeOf.
6548                         eclass = ExprClass.Value;
6549                         return this;
6550                 }
6551         }
6552
6553         /// <summary>
6554         ///   Implements the sizeof expression
6555         /// </summary>
6556         public class SizeOf : Expression {
6557                 public Expression QueriedType;
6558                 Type type_queried;
6559                 
6560                 public SizeOf (Expression queried_type, Location l)
6561                 {
6562                         this.QueriedType = queried_type;
6563                         loc = l;
6564                 }
6565
6566                 public override Expression DoResolve (EmitContext ec)
6567                 {
6568                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6569                         if (texpr == null)
6570                                 return null;
6571
6572 #if GMCS_SOURCE
6573                         if (texpr is TypeParameterExpr){
6574                                 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6575                                 return null;
6576                         }
6577 #endif
6578
6579                         type_queried = texpr.Type;
6580                         if (type_queried.IsEnum)
6581                                 type_queried = TypeManager.EnumToUnderlying (type_queried);
6582
6583                         if (type_queried == TypeManager.void_type) {
6584                                 Expression.Error_VoidInvalidInTheContext (loc);
6585                                 return null;
6586                         }
6587
6588                         int size_of = GetTypeSize (type_queried);
6589                         if (size_of > 0) {
6590                                 return new IntConstant (size_of, loc);
6591                         }
6592
6593                         if (!ec.InUnsafe) {
6594                                 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)",
6595                                          TypeManager.CSharpName (type_queried));
6596                                 return null;
6597                         }
6598
6599                         if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6600                                 return null;
6601                         }
6602                         
6603                         type = TypeManager.int32_type;
6604                         eclass = ExprClass.Value;
6605                         return this;
6606                 }
6607
6608                 public override void Emit (EmitContext ec)
6609                 {
6610                         int size = GetTypeSize (type_queried);
6611
6612                         if (size == 0)
6613                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6614                         else
6615                                 IntConstant.EmitInt (ec.ig, size);
6616                 }
6617
6618                 protected override void CloneTo (CloneContext clonectx, Expression t)
6619                 {
6620                         SizeOf target = (SizeOf) t;
6621
6622                         target.QueriedType = QueriedType.Clone (clonectx);
6623                 }
6624         }
6625
6626         /// <summary>
6627         ///   Implements the qualified-alias-member (::) expression.
6628         /// </summary>
6629         public class QualifiedAliasMember : Expression
6630         {
6631                 string alias, identifier;
6632
6633                 public QualifiedAliasMember (string alias, string identifier, Location l)
6634                 {
6635                         if (RootContext.Version == LanguageVersion.ISO_1)
6636                                 Report.FeatureIsNotISO1 (l, "namespace alias qualifier");
6637
6638                         this.alias = alias;
6639                         this.identifier = identifier;
6640                         loc = l;
6641                 }
6642
6643                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6644                 {
6645                         if (alias == "global")
6646                                 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6647
6648                         int errors = Report.Errors;
6649                         FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6650                         if (fne == null) {
6651                                 if (errors == Report.Errors)
6652                                         Report.Error (432, loc, "Alias `{0}' not found", alias);
6653                                 return null;
6654                         }
6655                         if (fne.eclass != ExprClass.Namespace) {
6656                                 if (!silent)
6657                                         Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6658                                 return null;
6659                         }
6660                         return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6661                 }
6662
6663                 public override Expression DoResolve (EmitContext ec)
6664                 {
6665                         FullNamedExpression fne;
6666                         if (alias == "global") {
6667                                 fne = RootNamespace.Global;
6668                         } else {
6669                                 int errors = Report.Errors;
6670                                 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6671                                 if (fne == null) {
6672                                         if (errors == Report.Errors)
6673                                                 Report.Error (432, loc, "Alias `{0}' not found", alias);
6674                                         return null;
6675                                 }
6676                         }
6677
6678                         Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6679                         if (retval == null)
6680                                 return null;
6681
6682                         if (!(retval is FullNamedExpression)) {
6683                                 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6684                                 return null;
6685                         }
6686
6687                         // We defer this check till the end to match the behaviour of CSC
6688                         if (fne.eclass != ExprClass.Namespace) {
6689                                 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6690                                 return null;
6691                         }
6692                         return retval;
6693                 }
6694
6695                 public override void Emit (EmitContext ec)
6696                 {
6697                         throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6698                 }
6699
6700
6701                 public override string ToString ()
6702                 {
6703                         return alias + "::" + identifier;
6704                 }
6705
6706                 public override string GetSignatureForError ()
6707                 {
6708                         return ToString ();
6709                 }
6710
6711                 protected override void CloneTo (CloneContext clonectx, Expression t)
6712                 {
6713                         // Nothing 
6714                 }
6715         }
6716
6717         /// <summary>
6718         ///   Implements the member access expression
6719         /// </summary>
6720         public class MemberAccess : Expression {
6721                 public readonly string Identifier;
6722                 Expression expr;
6723
6724                 public MemberAccess (Expression expr, string id)
6725                         : this (expr, id, expr.Location)
6726                 {
6727                 }
6728
6729                 public MemberAccess (Expression expr, string identifier, Location loc)
6730                 {
6731                         this.expr = expr;
6732                         Identifier = identifier;
6733                         this.loc = loc;
6734                 }
6735
6736                 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6737                         : this (expr, identifier, loc)
6738                 {
6739                         this.args = args;
6740                 }
6741
6742                 TypeArguments args;
6743
6744                 protected string LookupIdentifier {
6745                         get { return MemberName.MakeName (Identifier, args); }
6746                 }
6747
6748                 // TODO: this method has very poor performace for Enum fields and
6749                 // probably for other constants as well
6750                 Expression DoResolve (EmitContext ec, Expression right_side)
6751                 {
6752                         if (type != null)
6753                                 throw new Exception ();
6754
6755                         //
6756                         // Resolve the expression with flow analysis turned off, we'll do the definite
6757                         // assignment checks later.  This is because we don't know yet what the expression
6758                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6759                         // definite assignment check on the actual field and not on the whole struct.
6760                         //
6761
6762                         SimpleName original = expr as SimpleName;
6763                         Expression expr_resolved = expr.Resolve (ec,
6764                                 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6765                                 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6766
6767                         if (expr_resolved == null)
6768                                 return null;
6769
6770                         if (expr_resolved is Namespace) {
6771                                 Namespace ns = (Namespace) expr_resolved;
6772                                 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6773 #if GMCS_SOURCE
6774                                 if ((retval != null) && (args != null))
6775                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6776 #endif
6777
6778                                 if (retval == null)
6779                                         ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6780                                 return retval;
6781                         }
6782
6783                         Type expr_type = expr_resolved.Type;
6784                         if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr_resolved is NullLiteral){
6785                                 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6786                                 return null;
6787                         }
6788                         if (expr_type == TypeManager.anonymous_method_type){
6789                                 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6790                                 return null;
6791                         }
6792
6793                         Constant c = expr_resolved as Constant;
6794                         if (c != null && c.GetValue () == null) {
6795                                 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6796                                         "System.NullReferenceException");
6797                         }
6798
6799                         Expression member_lookup;
6800                         member_lookup = MemberLookup (
6801                                 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6802 #if GMCS_SOURCE
6803                         if ((member_lookup == null) && (args != null)) {
6804                                 member_lookup = MemberLookup (
6805                                         ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6806                         }
6807 #endif
6808                         if (member_lookup == null) {
6809                                 ExtensionMethodGroupExpr ex_method_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
6810                                 if (ex_method_lookup != null) {
6811                                         ex_method_lookup.ExtensionExpression = expr_resolved;
6812                                         return ex_method_lookup.DoResolve (ec);
6813                                 }
6814
6815                                 MemberLookupFailed (
6816                                         ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
6817                                 return null;
6818                         }
6819
6820                         TypeExpr texpr = member_lookup as TypeExpr;
6821                         if (texpr != null) {
6822                                 if (!(expr_resolved is TypeExpr) && 
6823                                     (original == null || !original.IdenticalNameAndTypeName (ec, expr_resolved, loc))) {
6824                                         Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6825                                                 Identifier, member_lookup.GetSignatureForError ());
6826                                         return null;
6827                                 }
6828
6829                                 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6830                                         Report.SymbolRelatedToPreviousError (member_lookup.Type);
6831                                         ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6832                                         return null;
6833                                 }
6834
6835 #if GMCS_SOURCE
6836                                 ConstructedType ct = expr_resolved as ConstructedType;
6837                                 if (ct != null) {
6838                                         //
6839                                         // When looking up a nested type in a generic instance
6840                                         // via reflection, we always get a generic type definition
6841                                         // and not a generic instance - so we have to do this here.
6842                                         //
6843                                         // See gtest-172-lib.cs and gtest-172.cs for an example.
6844                                         //
6845                                         ct = new ConstructedType (
6846                                                 member_lookup.Type, ct.TypeArguments, loc);
6847
6848                                         return ct.ResolveAsTypeStep (ec, false);
6849                                 }
6850 #endif
6851                                 return member_lookup;
6852                         }
6853
6854                         MemberExpr me = (MemberExpr) member_lookup;
6855                         member_lookup = me.ResolveMemberAccess (ec, expr_resolved, loc, original);
6856                         if (member_lookup == null)
6857                                 return null;
6858
6859                         if (args != null) {
6860                                 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6861                                 if (mg == null)
6862                                         throw new InternalErrorException ();
6863
6864                                 return mg.ResolveGeneric (ec, args);
6865                         }
6866
6867                         if (original != null && !TypeManager.IsValueType (expr_type)) {
6868                                 me = member_lookup as MemberExpr;
6869                                 if (me != null && me.IsInstance) {
6870                                         LocalVariableReference var = expr_resolved as LocalVariableReference;
6871                                         if (var != null && !var.VerifyAssigned (ec))
6872                                                 return null;
6873                                 }
6874                         }
6875
6876                         // The following DoResolve/DoResolveLValue will do the definite assignment
6877                         // check.
6878
6879                         if (right_side != null)
6880                                 return member_lookup.DoResolveLValue (ec, right_side);
6881                         else
6882                                 return member_lookup.DoResolve (ec);
6883                 }
6884
6885                 public override Expression DoResolve (EmitContext ec)
6886                 {
6887                         return DoResolve (ec, null);
6888                 }
6889
6890                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6891                 {
6892                         return DoResolve (ec, right_side);
6893                 }
6894
6895                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6896                 {
6897                         return ResolveNamespaceOrType (ec, silent);
6898                 }
6899
6900                 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6901                 {
6902                         FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6903
6904                         if (new_expr == null)
6905                                 return null;
6906
6907                         if (new_expr is Namespace) {
6908                                 Namespace ns = (Namespace) new_expr;
6909                                 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6910 #if GMCS_SOURCE
6911                                 if ((retval != null) && (args != null))
6912                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6913 #endif
6914                                 if (!silent && retval == null)
6915                                         ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6916                                 return retval;
6917                         }
6918
6919                         TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6920                         if (tnew_expr == null)
6921                                 return null;
6922
6923                         Type expr_type = tnew_expr.Type;
6924
6925                         if (expr_type.IsPointer){
6926                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
6927                                        TypeManager.CSharpName (expr_type) + ")");
6928                                 return null;
6929                         }
6930
6931                         Expression member_lookup = MemberLookup (
6932                                 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6933                                 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6934                         if (member_lookup == null) {
6935                                 if (silent)
6936                                         return null;
6937
6938                                 member_lookup = MemberLookup(
6939                                     rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6940                                         MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6941
6942                                 if (member_lookup == null) {
6943                                         Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6944                                                       Identifier, new_expr.GetSignatureForError ());
6945                                 } else {
6946                                 // TODO: Report.SymbolRelatedToPreviousError
6947                                     member_lookup.Error_UnexpectedKind (null, "type", loc);
6948                                 }
6949                                 return null;
6950                         }
6951
6952                         TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6953                         if (texpr == null)
6954                                 return null;
6955
6956 #if GMCS_SOURCE
6957                         TypeArguments the_args = args;
6958                         if (TypeManager.HasGenericArguments (expr_type)) {
6959                                 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
6960
6961                                 TypeArguments new_args = new TypeArguments (loc);
6962                                 foreach (Type decl in decl_args)
6963                                         new_args.Add (new TypeExpression (decl, loc));
6964
6965                                 if (args != null)
6966                                         new_args.Add (args);
6967
6968                                 the_args = new_args;
6969                         }
6970
6971                         if (the_args != null) {
6972                                 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
6973                                 return ctype.ResolveAsTypeStep (rc, false);
6974                         }
6975 #endif
6976
6977                         return texpr;
6978                 }
6979
6980                 public override void Emit (EmitContext ec)
6981                 {
6982                         throw new Exception ("Should not happen");
6983                 }
6984
6985                 public override string ToString ()
6986                 {
6987                         return expr + "." + MemberName.MakeName (Identifier, args);
6988                 }
6989
6990                 public override string GetSignatureForError ()
6991                 {
6992                         return expr.GetSignatureForError () + "." + Identifier;
6993                 }
6994
6995                 protected override void CloneTo (CloneContext clonectx, Expression t)
6996                 {
6997                         MemberAccess target = (MemberAccess) t;
6998
6999                         target.expr = expr.Clone (clonectx);
7000                 }
7001         }
7002
7003         /// <summary>
7004         ///   Implements checked expressions
7005         /// </summary>
7006         public class CheckedExpr : Expression {
7007
7008                 public Expression Expr;
7009
7010                 public CheckedExpr (Expression e, Location l)
7011                 {
7012                         Expr = e;
7013                         loc = l;
7014                 }
7015
7016                 public override Expression DoResolve (EmitContext ec)
7017                 {
7018                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7019                                 Expr = Expr.Resolve (ec);
7020                         
7021                         if (Expr == null)
7022                                 return null;
7023
7024                         if (Expr is Constant)
7025                                 return Expr;
7026                         
7027                         eclass = Expr.eclass;
7028                         type = Expr.Type;
7029                         return this;
7030                 }
7031
7032                 public override void Emit (EmitContext ec)
7033                 {
7034                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7035                                 Expr.Emit (ec);
7036                 }
7037
7038                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7039                 {
7040                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7041                                 Expr.EmitBranchable (ec, target, onTrue);
7042                 }
7043
7044                 protected override void CloneTo (CloneContext clonectx, Expression t)
7045                 {
7046                         CheckedExpr target = (CheckedExpr) t;
7047
7048                         target.Expr = Expr.Clone (clonectx);
7049                 }
7050         }
7051
7052         /// <summary>
7053         ///   Implements the unchecked expression
7054         /// </summary>
7055         public class UnCheckedExpr : Expression {
7056
7057                 public Expression Expr;
7058
7059                 public UnCheckedExpr (Expression e, Location l)
7060                 {
7061                         Expr = e;
7062                         loc = l;
7063                 }
7064
7065                 public override Expression DoResolve (EmitContext ec)
7066                 {
7067                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7068                                 Expr = Expr.Resolve (ec);
7069
7070                         if (Expr == null)
7071                                 return null;
7072
7073                         if (Expr is Constant)
7074                                 return Expr;
7075                         
7076                         eclass = Expr.eclass;
7077                         type = Expr.Type;
7078                         return this;
7079                 }
7080
7081                 public override void Emit (EmitContext ec)
7082                 {
7083                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7084                                 Expr.Emit (ec);
7085                 }
7086                 
7087                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7088                 {
7089                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7090                                 Expr.EmitBranchable (ec, target, onTrue);
7091                 }
7092
7093                 protected override void CloneTo (CloneContext clonectx, Expression t)
7094                 {
7095                         UnCheckedExpr target = (UnCheckedExpr) t;
7096
7097                         target.Expr = Expr.Clone (clonectx);
7098                 }
7099         }
7100
7101         /// <summary>
7102         ///   An Element Access expression.
7103         ///
7104         ///   During semantic analysis these are transformed into 
7105         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7106         /// </summary>
7107         public class ElementAccess : Expression {
7108                 public ArrayList  Arguments;
7109                 public Expression Expr;
7110                 
7111                 public ElementAccess (Expression e, ArrayList e_list)
7112                 {
7113                         Expr = e;
7114
7115                         loc  = e.Location;
7116                         
7117                         if (e_list == null)
7118                                 return;
7119                         
7120                         Arguments = new ArrayList ();
7121                         foreach (Expression tmp in e_list)
7122                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7123                         
7124                 }
7125
7126                 bool CommonResolve (EmitContext ec)
7127                 {
7128                         Expr = Expr.Resolve (ec);
7129
7130                         if (Expr == null) 
7131                                 return false;
7132
7133                         if (Arguments == null)
7134                                 return false;
7135
7136                         foreach (Argument a in Arguments){
7137                                 if (!a.Resolve (ec, loc))
7138                                         return false;
7139                         }
7140
7141                         return true;
7142                 }
7143
7144                 Expression MakePointerAccess (EmitContext ec, Type t)
7145                 {
7146                         if (t == TypeManager.void_ptr_type){
7147                                 Error (242, "The array index operation is not valid on void pointers");
7148                                 return null;
7149                         }
7150                         if (Arguments.Count != 1){
7151                                 Error (196, "A pointer must be indexed by only one value");
7152                                 return null;
7153                         }
7154                         Expression p;
7155
7156                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7157                         if (p == null)
7158                                 return null;
7159                         return new Indirection (p, loc).Resolve (ec);
7160                 }
7161                 
7162                 public override Expression DoResolve (EmitContext ec)
7163                 {
7164                         if (!CommonResolve (ec))
7165                                 return null;
7166
7167                         //
7168                         // We perform some simple tests, and then to "split" the emit and store
7169                         // code we create an instance of a different class, and return that.
7170                         //
7171                         // I am experimenting with this pattern.
7172                         //
7173                         Type t = Expr.Type;
7174
7175                         if (t == TypeManager.array_type){
7176                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7177                                 return null;
7178                         }
7179                         
7180                         if (t.IsArray)
7181                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7182                         if (t.IsPointer)
7183                                 return MakePointerAccess (ec, Expr.Type);
7184
7185                         FieldExpr fe = Expr as FieldExpr;
7186                         if (fe != null) {
7187                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7188                                 if (ff != null) {
7189                                         return MakePointerAccess (ec, ff.ElementType);
7190                                 }
7191                         }
7192                         return (new IndexerAccess (this, loc)).Resolve (ec);
7193                 }
7194
7195                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7196                 {
7197                         if (!CommonResolve (ec))
7198                                 return null;
7199
7200                         Type t = Expr.Type;
7201                         if (t.IsArray)
7202                                 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7203
7204                         if (t.IsPointer)
7205                                 return MakePointerAccess (ec, Expr.Type);
7206
7207                         FieldExpr fe = Expr as FieldExpr;
7208                         if (fe != null) {
7209                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7210                                 if (ff != null) {
7211                                         if (!(fe.InstanceExpression is LocalVariableReference) && 
7212                                                 !(fe.InstanceExpression is This)) {
7213                                                 Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields");
7214                                                 return null;
7215                                         }
7216                                         if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
7217                                                 Error (1666, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
7218                                                 return null;
7219                                         }
7220                                         return MakePointerAccess (ec, ff.ElementType);
7221                                 }
7222                         }
7223                         return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7224                 }
7225                 
7226                 public override void Emit (EmitContext ec)
7227                 {
7228                         throw new Exception ("Should never be reached");
7229                 }
7230
7231                 protected override void CloneTo (CloneContext clonectx, Expression t)
7232                 {
7233                         ElementAccess target = (ElementAccess) t;
7234
7235                         target.Expr = Expr.Clone (clonectx);
7236                         target.Arguments = new ArrayList ();
7237                         foreach (Argument a in Arguments)
7238                                 target.Arguments.Add (a.Clone (clonectx));
7239                 }
7240         }
7241
7242         /// <summary>
7243         ///   Implements array access 
7244         /// </summary>
7245         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7246                 //
7247                 // Points to our "data" repository
7248                 //
7249                 ElementAccess ea;
7250
7251                 LocalTemporary temp;
7252                 bool prepared;
7253                 
7254                 public ArrayAccess (ElementAccess ea_data, Location l)
7255                 {
7256                         ea = ea_data;
7257                         eclass = ExprClass.Variable;
7258                         loc = l;
7259                 }
7260
7261                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7262                 {
7263                         return DoResolve (ec);
7264                 }
7265
7266                 public override Expression DoResolve (EmitContext ec)
7267                 {
7268 #if false
7269                         ExprClass eclass = ea.Expr.eclass;
7270
7271                         // As long as the type is valid
7272                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7273                               eclass == ExprClass.Value)) {
7274                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7275                                 return null;
7276                         }
7277 #endif
7278
7279                         Type t = ea.Expr.Type;
7280                         if (t.GetArrayRank () != ea.Arguments.Count){
7281                                 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7282                                           ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7283                                 return null;
7284                         }
7285
7286                         type = TypeManager.GetElementType (t);
7287                         if (type.IsPointer && !ec.InUnsafe){
7288                                 UnsafeError (ea.Location);
7289                                 return null;
7290                         }
7291
7292                         foreach (Argument a in ea.Arguments){
7293                                 Type argtype = a.Type;
7294
7295                                 if (argtype == TypeManager.int32_type ||
7296                                     argtype == TypeManager.uint32_type ||
7297                                     argtype == TypeManager.int64_type ||
7298                                     argtype == TypeManager.uint64_type) {
7299                                         Constant c = a.Expr as Constant;
7300                                         if (c != null && c.IsNegative) {
7301                                                 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7302                                         }
7303                                         continue;
7304                                 }
7305
7306                                 //
7307                                 // Mhm.  This is strage, because the Argument.Type is not the same as
7308                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7309                                 //
7310                                 // Wonder if I will run into trouble for this.
7311                                 //
7312                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7313                                 if (a.Expr == null)
7314                                         return null;
7315                         }
7316                         
7317                         eclass = ExprClass.Variable;
7318
7319                         return this;
7320                 }
7321
7322                 /// <summary>
7323                 ///    Emits the right opcode to load an object of Type `t'
7324                 ///    from an array of T
7325                 /// </summary>
7326                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7327                 {
7328                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7329                                 ig.Emit (OpCodes.Ldelem_U1);
7330                         else if (type == TypeManager.sbyte_type)
7331                                 ig.Emit (OpCodes.Ldelem_I1);
7332                         else if (type == TypeManager.short_type)
7333                                 ig.Emit (OpCodes.Ldelem_I2);
7334                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7335                                 ig.Emit (OpCodes.Ldelem_U2);
7336                         else if (type == TypeManager.int32_type)
7337                                 ig.Emit (OpCodes.Ldelem_I4);
7338                         else if (type == TypeManager.uint32_type)
7339                                 ig.Emit (OpCodes.Ldelem_U4);
7340                         else if (type == TypeManager.uint64_type)
7341                                 ig.Emit (OpCodes.Ldelem_I8);
7342                         else if (type == TypeManager.int64_type)
7343                                 ig.Emit (OpCodes.Ldelem_I8);
7344                         else if (type == TypeManager.float_type)
7345                                 ig.Emit (OpCodes.Ldelem_R4);
7346                         else if (type == TypeManager.double_type)
7347                                 ig.Emit (OpCodes.Ldelem_R8);
7348                         else if (type == TypeManager.intptr_type)
7349                                 ig.Emit (OpCodes.Ldelem_I);
7350                         else if (TypeManager.IsEnumType (type)){
7351                                 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7352                         } else if (type.IsValueType){
7353                                 ig.Emit (OpCodes.Ldelema, type);
7354                                 ig.Emit (OpCodes.Ldobj, type);
7355 #if GMCS_SOURCE
7356                         } else if (type.IsGenericParameter) {
7357                                 ig.Emit (OpCodes.Ldelem, type);
7358 #endif
7359                         } else if (type.IsPointer)
7360                                 ig.Emit (OpCodes.Ldelem_I);
7361                         else
7362                                 ig.Emit (OpCodes.Ldelem_Ref);
7363                 }
7364
7365                 /// <summary>
7366                 ///    Returns the right opcode to store an object of Type `t'
7367                 ///    from an array of T.  
7368                 /// </summary>
7369                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7370                 {
7371                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
7372                         has_type_arg = false; is_stobj = false;
7373                         t = TypeManager.TypeToCoreType (t);
7374                         if (TypeManager.IsEnumType (t))
7375                                 t = TypeManager.EnumToUnderlying (t);
7376                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7377                             t == TypeManager.bool_type)
7378                                 return OpCodes.Stelem_I1;
7379                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7380                                  t == TypeManager.char_type)
7381                                 return OpCodes.Stelem_I2;
7382                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7383                                 return OpCodes.Stelem_I4;
7384                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7385                                 return OpCodes.Stelem_I8;
7386                         else if (t == TypeManager.float_type)
7387                                 return OpCodes.Stelem_R4;
7388                         else if (t == TypeManager.double_type)
7389                                 return OpCodes.Stelem_R8;
7390                         else if (t == TypeManager.intptr_type) {
7391                                 has_type_arg = true;
7392                                 is_stobj = true;
7393                                 return OpCodes.Stobj;
7394                         } else if (t.IsValueType) {
7395                                 has_type_arg = true;
7396                                 is_stobj = true;
7397                                 return OpCodes.Stobj;
7398 #if GMCS_SOURCE
7399                         } else if (t.IsGenericParameter) {
7400                                 has_type_arg = true;
7401                                 return OpCodes.Stelem;
7402 #endif
7403
7404                         } else if (t.IsPointer)
7405                                 return OpCodes.Stelem_I;
7406                         else
7407                                 return OpCodes.Stelem_Ref;
7408                 }
7409
7410                 MethodInfo FetchGetMethod ()
7411                 {
7412                         ModuleBuilder mb = CodeGen.Module.Builder;
7413                         int arg_count = ea.Arguments.Count;
7414                         Type [] args = new Type [arg_count];
7415                         MethodInfo get;
7416                         
7417                         for (int i = 0; i < arg_count; i++){
7418                                 //args [i++] = a.Type;
7419                                 args [i] = TypeManager.int32_type;
7420                         }
7421                         
7422                         get = mb.GetArrayMethod (
7423                                 ea.Expr.Type, "Get",
7424                                 CallingConventions.HasThis |
7425                                 CallingConventions.Standard,
7426                                 type, args);
7427                         return get;
7428                 }
7429                                 
7430
7431                 MethodInfo FetchAddressMethod ()
7432                 {
7433                         ModuleBuilder mb = CodeGen.Module.Builder;
7434                         int arg_count = ea.Arguments.Count;
7435                         Type [] args = new Type [arg_count];
7436                         MethodInfo address;
7437                         Type ret_type;
7438                         
7439                         ret_type = TypeManager.GetReferenceType (type);
7440                         
7441                         for (int i = 0; i < arg_count; i++){
7442                                 //args [i++] = a.Type;
7443                                 args [i] = TypeManager.int32_type;
7444                         }
7445                         
7446                         address = mb.GetArrayMethod (
7447                                 ea.Expr.Type, "Address",
7448                                 CallingConventions.HasThis |
7449                                 CallingConventions.Standard,
7450                                 ret_type, args);
7451
7452                         return address;
7453                 }
7454
7455                 //
7456                 // Load the array arguments into the stack.
7457                 //
7458                 // If we have been requested to cache the values (cached_locations array
7459                 // initialized), then load the arguments the first time and store them
7460                 // in locals.  otherwise load from local variables.
7461                 //
7462                 void LoadArrayAndArguments (EmitContext ec)
7463                 {
7464                         ILGenerator ig = ec.ig;
7465                         
7466                         ea.Expr.Emit (ec);
7467                         foreach (Argument a in ea.Arguments){
7468                                 Type argtype = a.Expr.Type;
7469                                 
7470                                 a.Expr.Emit (ec);
7471                                 
7472                                 if (argtype == TypeManager.int64_type)
7473                                         ig.Emit (OpCodes.Conv_Ovf_I);
7474                                 else if (argtype == TypeManager.uint64_type)
7475                                         ig.Emit (OpCodes.Conv_Ovf_I_Un);
7476                         }
7477                 }
7478
7479                 public void Emit (EmitContext ec, bool leave_copy)
7480                 {
7481                         int rank = ea.Expr.Type.GetArrayRank ();
7482                         ILGenerator ig = ec.ig;
7483
7484                         if (!prepared) {
7485                                 LoadArrayAndArguments (ec);
7486                                 
7487                                 if (rank == 1)
7488                                         EmitLoadOpcode (ig, type);
7489                                 else {
7490                                         MethodInfo method;
7491                                         
7492                                         method = FetchGetMethod ();
7493                                         ig.Emit (OpCodes.Call, method);
7494                                 }
7495                         } else
7496                                 LoadFromPtr (ec.ig, this.type);
7497                         
7498                         if (leave_copy) {
7499                                 ec.ig.Emit (OpCodes.Dup);
7500                                 temp = new LocalTemporary (this.type);
7501                                 temp.Store (ec);
7502                         }
7503                 }
7504                 
7505                 public override void Emit (EmitContext ec)
7506                 {
7507                         Emit (ec, false);
7508                 }
7509
7510                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7511                 {
7512                         int rank = ea.Expr.Type.GetArrayRank ();
7513                         ILGenerator ig = ec.ig;
7514                         Type t = source.Type;
7515                         prepared = prepare_for_load;
7516
7517                         if (prepare_for_load) {
7518                                 AddressOf (ec, AddressOp.LoadStore);
7519                                 ec.ig.Emit (OpCodes.Dup);
7520                                 source.Emit (ec);
7521                                 if (leave_copy) {
7522                                         ec.ig.Emit (OpCodes.Dup);
7523                                         temp = new LocalTemporary (this.type);
7524                                         temp.Store (ec);
7525                                 }
7526                                 StoreFromPtr (ec.ig, t);
7527                                 
7528                                 if (temp != null) {
7529                                         temp.Emit (ec);
7530                                         temp.Release (ec);
7531                                 }
7532                                 
7533                                 return;
7534                         }
7535                         
7536                         LoadArrayAndArguments (ec);
7537
7538                         if (rank == 1) {
7539                                 bool is_stobj, has_type_arg;
7540                                 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7541                                 //
7542                                 // The stobj opcode used by value types will need
7543                                 // an address on the stack, not really an array/array
7544                                 // pair
7545                                 //
7546                                 if (is_stobj)
7547                                         ig.Emit (OpCodes.Ldelema, t);
7548                                 
7549                                 source.Emit (ec);
7550                                 if (leave_copy) {
7551                                         ec.ig.Emit (OpCodes.Dup);
7552                                         temp = new LocalTemporary (this.type);
7553                                         temp.Store (ec);
7554                                 }
7555                                 
7556                                 if (is_stobj)
7557                                         ig.Emit (OpCodes.Stobj, t);
7558                                 else if (has_type_arg)
7559                                         ig.Emit (op, t);
7560                                 else
7561                                         ig.Emit (op);
7562                         } else {
7563                                 ModuleBuilder mb = CodeGen.Module.Builder;
7564                                 int arg_count = ea.Arguments.Count;
7565                                 Type [] args = new Type [arg_count + 1];
7566                                 MethodInfo set;
7567                                 
7568                                 source.Emit (ec);
7569                                 if (leave_copy) {
7570                                         ec.ig.Emit (OpCodes.Dup);
7571                                         temp = new LocalTemporary (this.type);
7572                                         temp.Store (ec);
7573                                 }
7574                                 
7575                                 for (int i = 0; i < arg_count; i++){
7576                                         //args [i++] = a.Type;
7577                                         args [i] = TypeManager.int32_type;
7578                                 }
7579
7580                                 args [arg_count] = type;
7581                                 
7582                                 set = mb.GetArrayMethod (
7583                                         ea.Expr.Type, "Set",
7584                                         CallingConventions.HasThis |
7585                                         CallingConventions.Standard,
7586                                         TypeManager.void_type, args);
7587                                 
7588                                 ig.Emit (OpCodes.Call, set);
7589                         }
7590                         
7591                         if (temp != null) {
7592                                 temp.Emit (ec);
7593                                 temp.Release (ec);
7594                         }
7595                 }
7596
7597                 public void AddressOf (EmitContext ec, AddressOp mode)
7598                 {
7599                         int rank = ea.Expr.Type.GetArrayRank ();
7600                         ILGenerator ig = ec.ig;
7601
7602                         LoadArrayAndArguments (ec);
7603
7604                         if (rank == 1){
7605                                 ig.Emit (OpCodes.Ldelema, type);
7606                         } else {
7607                                 MethodInfo address = FetchAddressMethod ();
7608                                 ig.Emit (OpCodes.Call, address);
7609                         }
7610                 }
7611
7612                 public void EmitGetLength (EmitContext ec, int dim)
7613                 {
7614                         int rank = ea.Expr.Type.GetArrayRank ();
7615                         ILGenerator ig = ec.ig;
7616
7617                         ea.Expr.Emit (ec);
7618                         if (rank == 1) {
7619                                 ig.Emit (OpCodes.Ldlen);
7620                                 ig.Emit (OpCodes.Conv_I4);
7621                         } else {
7622                                 IntLiteral.EmitInt (ig, dim);
7623                                 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7624                         }
7625                 }
7626         }
7627         
7628         class Indexers {
7629                 // note that the ArrayList itself in mutable.  We just can't assign to 'Properties' again.
7630                 public readonly ArrayList Properties;
7631                 static Indexers empty;
7632
7633                 public struct Indexer {
7634                         public readonly PropertyInfo PropertyInfo;
7635                         public readonly MethodInfo Getter, Setter;
7636
7637                         public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7638                         {
7639                                 this.PropertyInfo = property_info;
7640                                 this.Getter = get;
7641                                 this.Setter = set;
7642                         }
7643                 }
7644
7645                 static Indexers ()
7646                 {
7647                         empty = new Indexers (null);
7648                 }
7649
7650                 Indexers (ArrayList array)
7651                 {
7652                         Properties = array;
7653                 }
7654
7655                 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
7656                 {
7657                         bool dummy;
7658                         if (mi == null)
7659                                 return;
7660                         foreach (PropertyInfo property in mi){
7661                                 MethodInfo get, set;
7662                                 
7663                                 get = property.GetGetMethod (true);
7664                                 set = property.GetSetMethod (true);
7665                                 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
7666                                         get = null;
7667                                 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
7668                                         set = null;
7669                                 if (get != null || set != null) {
7670                                         if (ix == empty)
7671                                                 ix = new Indexers (new ArrayList ());
7672                                         ix.Properties.Add (new Indexer (property, get, set));
7673                                 }
7674                         }
7675                 }
7676
7677                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7678                 {
7679                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
7680
7681                         return TypeManager.MemberLookup (
7682                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
7683                                 BindingFlags.Public | BindingFlags.Instance |
7684                                 BindingFlags.DeclaredOnly, p_name, null);
7685                 }
7686                 
7687                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type) 
7688                 {
7689                         Indexers ix = empty;
7690
7691 #if GMCS_SOURCE
7692                         if (lookup_type.IsGenericParameter) {
7693                                 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7694                                 if (gc == null)
7695                                         return empty;
7696
7697                                 if (gc.HasClassConstraint)
7698                                         Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7699
7700                                 Type[] ifaces = gc.InterfaceConstraints;
7701                                 foreach (Type itype in ifaces)
7702                                         Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7703
7704                                 return ix;
7705                         }
7706 #endif
7707
7708                         Type copy = lookup_type;
7709                         while (copy != TypeManager.object_type && copy != null){
7710                                 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7711                                 copy = copy.BaseType;
7712                         }
7713
7714                         if (lookup_type.IsInterface) {
7715                                 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7716                                 if (ifaces != null) {
7717                                         foreach (Type itype in ifaces)
7718                                                 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7719                                 }
7720                         }
7721
7722                         return ix;
7723                 }
7724         }
7725
7726         /// <summary>
7727         ///   Expressions that represent an indexer call.
7728         /// </summary>
7729         public class IndexerAccess : Expression, IAssignMethod {
7730                 //
7731                 // Points to our "data" repository
7732                 //
7733                 MethodInfo get, set;
7734                 ArrayList set_arguments;
7735                 bool is_base_indexer;
7736
7737                 protected Type indexer_type;
7738                 protected Type current_type;
7739                 protected Expression instance_expr;
7740                 protected ArrayList arguments;
7741                 
7742                 public IndexerAccess (ElementAccess ea, Location loc)
7743                         : this (ea.Expr, false, loc)
7744                 {
7745                         this.arguments = ea.Arguments;
7746                 }
7747
7748                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7749                                          Location loc)
7750                 {
7751                         this.instance_expr = instance_expr;
7752                         this.is_base_indexer = is_base_indexer;
7753                         this.eclass = ExprClass.Value;
7754                         this.loc = loc;
7755                 }
7756
7757                 protected virtual bool CommonResolve (EmitContext ec)
7758                 {
7759                         indexer_type = instance_expr.Type;
7760                         current_type = ec.ContainerType;
7761
7762                         return true;
7763                 }
7764
7765                 public override Expression DoResolve (EmitContext ec)
7766                 {
7767                         if (!CommonResolve (ec))
7768                                 return null;
7769
7770                         //
7771                         // Step 1: Query for all `Item' *properties*.  Notice
7772                         // that the actual methods are pointed from here.
7773                         //
7774                         // This is a group of properties, piles of them.  
7775
7776                         ArrayList AllGetters = null;
7777
7778                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7779                         if (ilist.Properties != null) {
7780                                 AllGetters = new ArrayList(ilist.Properties.Count);
7781                                 foreach (Indexers.Indexer ix in ilist.Properties) {
7782                                         if (ix.Getter != null)
7783                                                 AllGetters.Add (ix.Getter);
7784                                 }
7785                         }
7786
7787                         if (AllGetters == null) {
7788                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7789                                         TypeManager.CSharpName (indexer_type));
7790                                 return null;
7791                         }
7792
7793                         if (AllGetters.Count == 0) {
7794                                 // FIXME: we cannot simply select first one as the error message is missleading when
7795                                 // multiple indexers exist
7796                                 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
7797                                 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7798                                         TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
7799                                 return null;
7800                         }
7801
7802                         get = (MethodInfo)new MethodGroupExpr (AllGetters, loc).OverloadResolve (ec,
7803                                         arguments, false, loc);
7804
7805                         if (get == null) {
7806                                 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7807                                 return null;
7808                         }
7809
7810                         //
7811                         // Only base will allow this invocation to happen.
7812                         //
7813                         if (get.IsAbstract && this is BaseIndexerAccess){
7814                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
7815                                 return null;
7816                         }
7817
7818                         type = get.ReturnType;
7819                         if (type.IsPointer && !ec.InUnsafe){
7820                                 UnsafeError (loc);
7821                                 return null;
7822                         }
7823
7824                         instance_expr.CheckMarshalByRefAccess ();
7825                         
7826                         eclass = ExprClass.IndexerAccess;
7827                         return this;
7828                 }
7829
7830                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7831                 {
7832                         if (right_side == EmptyExpression.OutAccess) {
7833                                 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7834                                               GetSignatureForError ());
7835                                 return null;
7836                         }
7837
7838                         // if the indexer returns a value type, and we try to set a field in it
7839                         if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7840                                 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7841                                               GetSignatureForError ());
7842                                 return null;
7843                         }
7844
7845                         ArrayList AllSetters = new ArrayList();
7846                         if (!CommonResolve (ec))
7847                                 return null;
7848
7849                         bool found_any = false, found_any_setters = false;
7850
7851                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7852                         if (ilist.Properties != null) {
7853                                 found_any = true;
7854                                 foreach (Indexers.Indexer ix in ilist.Properties) {
7855                                         if (ix.Setter != null)
7856                                                 AllSetters.Add (ix.Setter);
7857                                 }
7858                         }
7859                         if (AllSetters.Count > 0) {
7860                                 found_any_setters = true;
7861                                 set_arguments = (ArrayList) arguments.Clone ();
7862                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7863                                 set = (MethodInfo)(new MethodGroupExpr (AllSetters, loc)).OverloadResolve (
7864                                         ec,
7865                                         set_arguments, false, loc);
7866                         }
7867
7868                         if (!found_any) {
7869                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7870                                               TypeManager.CSharpName (indexer_type));
7871                                 return null;
7872                         }
7873
7874                         if (!found_any_setters) {
7875                                 Error (154, "indexer can not be used in this context, because " +
7876                                        "it lacks a `set' accessor");
7877                                 return null;
7878                         }
7879
7880                         if (set == null) {
7881                                 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7882                                 return null;
7883                         }
7884
7885                         //
7886                         // Only base will allow this invocation to happen.
7887                         //
7888                         if (set.IsAbstract && this is BaseIndexerAccess){
7889                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
7890                                 return null;
7891                         }
7892
7893                         //
7894                         // Now look for the actual match in the list of indexers to set our "return" type
7895                         //
7896                         type = TypeManager.void_type;   // default value
7897                         foreach (Indexers.Indexer ix in ilist.Properties){
7898                                 if (ix.Setter == set){
7899                                         type = ix.PropertyInfo.PropertyType;
7900                                         break;
7901                                 }
7902                         }
7903
7904                         instance_expr.CheckMarshalByRefAccess ();
7905
7906                         eclass = ExprClass.IndexerAccess;
7907                         return this;
7908                 }
7909                 
7910                 bool prepared = false;
7911                 LocalTemporary temp;
7912                 
7913                 public void Emit (EmitContext ec, bool leave_copy)
7914                 {
7915                         Invocation.EmitCall (ec, is_base_indexer, instance_expr, get, arguments, loc, prepared, false);
7916                         if (leave_copy) {
7917                                 ec.ig.Emit (OpCodes.Dup);
7918                                 temp = new LocalTemporary (Type);
7919                                 temp.Store (ec);
7920                         }
7921                 }
7922                 
7923                 //
7924                 // source is ignored, because we already have a copy of it from the
7925                 // LValue resolution and we have already constructed a pre-cached
7926                 // version of the arguments (ea.set_arguments);
7927                 //
7928                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7929                 {
7930                         prepared = prepare_for_load;
7931                         Argument a = (Argument) set_arguments [set_arguments.Count - 1];
7932                         
7933                         if (prepared) {
7934                                 source.Emit (ec);
7935                                 if (leave_copy) {
7936                                         ec.ig.Emit (OpCodes.Dup);
7937                                         temp = new LocalTemporary (Type);
7938                                         temp.Store (ec);
7939                                 }
7940                         } else if (leave_copy) {
7941                                 temp = new LocalTemporary (Type);
7942                                 source.Emit (ec);
7943                                 temp.Store (ec);
7944                                 a.Expr = temp;
7945                         }
7946                         
7947                         Invocation.EmitCall (ec, is_base_indexer, instance_expr, set, set_arguments, loc, false, prepared);
7948                         
7949                         if (temp != null) {
7950                                 temp.Emit (ec);
7951                                 temp.Release (ec);
7952                         }
7953                 }
7954                 
7955                 
7956                 public override void Emit (EmitContext ec)
7957                 {
7958                         Emit (ec, false);
7959                 }
7960
7961                 public override string GetSignatureForError ()
7962                 {
7963                         // FIXME: print the argument list of the indexer
7964                         return instance_expr.GetSignatureForError () + ".this[...]";
7965                 }
7966
7967                 protected override void CloneTo (CloneContext clonectx, Expression t)
7968                 {
7969                         IndexerAccess target = (IndexerAccess) t;
7970
7971                         if (arguments != null){
7972                                 target.arguments = new ArrayList ();
7973                                 foreach (Argument a in arguments)
7974                                         target.arguments.Add (a.Clone (clonectx));
7975                         }
7976                         if (instance_expr != null)
7977                                 target.instance_expr = instance_expr.Clone (clonectx);
7978                 }
7979         }
7980
7981         /// <summary>
7982         ///   The base operator for method names
7983         /// </summary>
7984         public class BaseAccess : Expression {
7985                 public readonly string Identifier;
7986                 TypeArguments args;
7987
7988                 public BaseAccess (string member, Location l)
7989                 {
7990                         this.Identifier = member;
7991                         loc = l;
7992                 }
7993
7994                 public BaseAccess (string member, TypeArguments args, Location l)
7995                         : this (member, l)
7996                 {
7997                         this.args = args;
7998                 }
7999
8000                 public override Expression DoResolve (EmitContext ec)
8001                 {
8002                         Expression c = CommonResolve (ec);
8003
8004                         if (c == null)
8005                                 return null;
8006
8007                         //
8008                         // MethodGroups use this opportunity to flag an error on lacking ()
8009                         //
8010                         if (!(c is MethodGroupExpr))
8011                                 return c.Resolve (ec);
8012                         return c;
8013                 }
8014
8015                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
8016                 {
8017                         Expression c = CommonResolve (ec);
8018
8019                         if (c == null)
8020                                 return null;
8021
8022                         //
8023                         // MethodGroups use this opportunity to flag an error on lacking ()
8024                         //
8025                         if (! (c is MethodGroupExpr))
8026                                 return c.DoResolveLValue (ec, right_side);
8027
8028                         return c;
8029                 }
8030
8031                 Expression CommonResolve (EmitContext ec)
8032                 {
8033                         Expression member_lookup;
8034                         Type current_type = ec.ContainerType;
8035                         Type base_type = current_type.BaseType;
8036
8037                         if (ec.IsStatic){
8038                                 Error (1511, "Keyword `base' is not available in a static method");
8039                                 return null;
8040                         }
8041
8042                         if (ec.IsFieldInitializer){
8043                                 Error (1512, "Keyword `base' is not available in the current context");
8044                                 return null;
8045                         }
8046                         
8047                         member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8048                                                       AllMemberTypes, AllBindingFlags, loc);
8049                         if (member_lookup == null) {
8050                                 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8051                                 return null;
8052                         }
8053
8054                         Expression left;
8055                         
8056                         if (ec.IsStatic)
8057                                 left = new TypeExpression (base_type, loc);
8058                         else
8059                                 left = ec.GetThis (loc);
8060
8061                         MemberExpr me = (MemberExpr) member_lookup;
8062                         
8063                         Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8064
8065                         if (e is PropertyExpr) {
8066                                 PropertyExpr pe = (PropertyExpr) e;
8067
8068                                 pe.IsBase = true;
8069                         }
8070
8071                         MethodGroupExpr mg = e as MethodGroupExpr;
8072                         if (mg != null)
8073                                 mg.IsBase = true;
8074
8075                         if (args != null) {
8076                                 if (mg != null)
8077                                         return mg.ResolveGeneric (ec, args);
8078
8079                                 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8080                                               Identifier);
8081                                 return null;
8082                         }
8083
8084                         return e;
8085                 }
8086
8087                 public override void Emit (EmitContext ec)
8088                 {
8089                         throw new Exception ("Should never be called"); 
8090                 }
8091
8092                 protected override void CloneTo (CloneContext clonectx, Expression t)
8093                 {
8094                         BaseAccess target = (BaseAccess) t;
8095
8096                         target.args = args.Clone ();
8097                 }
8098         }
8099
8100         /// <summary>
8101         ///   The base indexer operator
8102         /// </summary>
8103         public class BaseIndexerAccess : IndexerAccess {
8104                 public BaseIndexerAccess (ArrayList args, Location loc)
8105                         : base (null, true, loc)
8106                 {
8107                         arguments = new ArrayList ();
8108                         foreach (Expression tmp in args)
8109                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8110                 }
8111
8112                 protected override bool CommonResolve (EmitContext ec)
8113                 {
8114                         instance_expr = ec.GetThis (loc);
8115
8116                         current_type = ec.ContainerType.BaseType;
8117                         indexer_type = current_type;
8118
8119                         foreach (Argument a in arguments){
8120                                 if (!a.Resolve (ec, loc))
8121                                         return false;
8122                         }
8123
8124                         return true;
8125                 }
8126         }
8127         
8128         /// <summary>
8129         ///   This class exists solely to pass the Type around and to be a dummy
8130         ///   that can be passed to the conversion functions (this is used by
8131         ///   foreach implementation to typecast the object return value from
8132         ///   get_Current into the proper type.  All code has been generated and
8133         ///   we only care about the side effect conversions to be performed
8134         ///
8135         ///   This is also now used as a placeholder where a no-action expression
8136         ///   is needed (the `New' class).
8137         /// </summary>
8138         public class EmptyExpression : Expression {
8139                 public static readonly EmptyExpression Null = new EmptyExpression ();
8140
8141                 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8142                 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8143                 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8144
8145                 static EmptyExpression temp = new EmptyExpression ();
8146                 public static EmptyExpression Grab ()
8147                 {
8148                         EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8149                         temp = null;
8150                         return retval;
8151                 }
8152
8153                 public static void Release (EmptyExpression e)
8154                 {
8155                         temp = e;
8156                 }
8157
8158                 // TODO: should be protected
8159                 public EmptyExpression ()
8160                 {
8161                         type = TypeManager.object_type;
8162                         eclass = ExprClass.Value;
8163                         loc = Location.Null;
8164                 }
8165
8166                 public EmptyExpression (Type t)
8167                 {
8168                         type = t;
8169                         eclass = ExprClass.Value;
8170                         loc = Location.Null;
8171                 }
8172                 
8173                 public override Expression DoResolve (EmitContext ec)
8174                 {
8175                         return this;
8176                 }
8177
8178                 public override void Emit (EmitContext ec)
8179                 {
8180                         // nothing, as we only exist to not do anything.
8181                 }
8182
8183                 //
8184                 // This is just because we might want to reuse this bad boy
8185                 // instead of creating gazillions of EmptyExpressions.
8186                 // (CanImplicitConversion uses it)
8187                 //
8188                 public void SetType (Type t)
8189                 {
8190                         type = t;
8191                 }
8192         }
8193
8194         public class UserCast : Expression {
8195                 MethodBase method;
8196                 Expression source;
8197                 
8198                 public UserCast (MethodInfo method, Expression source, Location l)
8199                 {
8200                         this.method = method;
8201                         this.source = source;
8202                         type = method.ReturnType;
8203                         eclass = ExprClass.Value;
8204                         loc = l;
8205                 }
8206
8207                 public Expression Source {
8208                         get {
8209                                 return source;
8210                         }
8211                 }
8212                         
8213                 public override Expression DoResolve (EmitContext ec)
8214                 {
8215                         //
8216                         // We are born fully resolved
8217                         //
8218                         return this;
8219                 }
8220
8221                 public override void Emit (EmitContext ec)
8222                 {
8223                         ILGenerator ig = ec.ig;
8224
8225                         source.Emit (ec);
8226                         
8227                         if (method is MethodInfo)
8228                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8229                         else
8230                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8231
8232                 }
8233         }
8234
8235         // <summary>
8236         //   This class is used to "construct" the type during a typecast
8237         //   operation.  Since the Type.GetType class in .NET can parse
8238         //   the type specification, we just use this to construct the type
8239         //   one bit at a time.
8240         // </summary>
8241         public class ComposedCast : TypeExpr {
8242                 Expression left;
8243                 string dim;
8244                 
8245                 public ComposedCast (Expression left, string dim)
8246                         : this (left, dim, left.Location)
8247                 {
8248                 }
8249
8250                 public ComposedCast (Expression left, string dim, Location l)
8251                 {
8252                         this.left = left;
8253                         this.dim = dim;
8254                         loc = l;
8255                 }
8256
8257 #if GMCS_SOURCE
8258                 public Expression RemoveNullable ()
8259                 {
8260                         if (dim.EndsWith ("?")) {
8261                                 dim = dim.Substring (0, dim.Length - 1);
8262                                 if (dim == "")
8263                                         return left;
8264                         }
8265
8266                         return this;
8267                 }
8268 #endif
8269
8270                 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8271                 {
8272                         TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8273                         if (lexpr == null)
8274                                 return null;
8275
8276                         Type ltype = lexpr.Type;
8277                         if ((ltype == TypeManager.void_type) && (dim != "*")) {
8278                                 Error_VoidInvalidInTheContext (loc);
8279                                 return null;
8280                         }
8281
8282 #if GMCS_SOURCE
8283                         if ((dim.Length > 0) && (dim [0] == '?')) {
8284                                 TypeExpr nullable = new NullableType (left, loc);
8285                                 if (dim.Length > 1)
8286                                         nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8287                                 return nullable.ResolveAsTypeTerminal (ec, false);
8288                         }
8289 #endif
8290
8291                         if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8292                                 return null;
8293
8294                         if (dim != "" && dim [0] == '[' &&
8295                             (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8296                                 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8297                                 return null;
8298                         }
8299
8300                         if (dim != "")
8301                                 type = TypeManager.GetConstructedType (ltype, dim);
8302                         else
8303                                 type = ltype;
8304
8305                         if (type == null)
8306                                 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8307
8308                         if (type.IsPointer && !ec.IsInUnsafeScope){
8309                                 UnsafeError (loc);
8310                                 return null;
8311                         }
8312
8313                         eclass = ExprClass.Type;
8314                         return this;
8315                 }
8316
8317                 public override string Name {
8318                         get { return left + dim; }
8319                 }
8320
8321                 public override string FullName {
8322                         get { return type.FullName; }
8323                 }
8324
8325                 public override string GetSignatureForError ()
8326                 {
8327                         return left.GetSignatureForError () + dim;
8328                 }
8329
8330                 protected override void CloneTo (CloneContext clonectx, Expression t)
8331                 {
8332                         ComposedCast target = (ComposedCast) t;
8333
8334                         target.left = left.Clone (clonectx);
8335                 }
8336         }
8337
8338         public class FixedBufferPtr : Expression {
8339                 Expression array;
8340
8341                 public FixedBufferPtr (Expression array, Type array_type, Location l)
8342                 {
8343                         this.array = array;
8344                         this.loc = l;
8345
8346                         type = TypeManager.GetPointerType (array_type);
8347                         eclass = ExprClass.Value;
8348                 }
8349
8350                 public override void Emit(EmitContext ec)
8351                 {
8352                         array.Emit (ec);
8353                 }
8354
8355                 public override Expression DoResolve (EmitContext ec)
8356                 {
8357                         //
8358                         // We are born fully resolved
8359                         //
8360                         return this;
8361                 }
8362         }
8363
8364
8365         //
8366         // This class is used to represent the address of an array, used
8367         // only by the Fixed statement, this generates "&a [0]" construct
8368         // for fixed (char *pa = a)
8369         //
8370         public class ArrayPtr : FixedBufferPtr {
8371                 Type array_type;
8372                 
8373                 public ArrayPtr (Expression array, Type array_type, Location l):
8374                         base (array, array_type, l)
8375                 {
8376                         this.array_type = array_type;
8377                 }
8378
8379                 public override void Emit (EmitContext ec)
8380                 {
8381                         base.Emit (ec);
8382                         
8383                         ILGenerator ig = ec.ig;
8384                         IntLiteral.EmitInt (ig, 0);
8385                         ig.Emit (OpCodes.Ldelema, array_type);
8386                 }
8387         }
8388
8389         //
8390         // Used by the fixed statement
8391         //
8392         public class StringPtr : Expression {
8393                 LocalBuilder b;
8394                 
8395                 public StringPtr (LocalBuilder b, Location l)
8396                 {
8397                         this.b = b;
8398                         eclass = ExprClass.Value;
8399                         type = TypeManager.char_ptr_type;
8400                         loc = l;
8401                 }
8402
8403                 public override Expression DoResolve (EmitContext ec)
8404                 {
8405                         // This should never be invoked, we are born in fully
8406                         // initialized state.
8407
8408                         return this;
8409                 }
8410
8411                 public override void Emit (EmitContext ec)
8412                 {
8413                         ILGenerator ig = ec.ig;
8414
8415                         ig.Emit (OpCodes.Ldloc, b);
8416                         ig.Emit (OpCodes.Conv_I);
8417                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8418                         ig.Emit (OpCodes.Add);
8419                 }
8420         }
8421         
8422         //
8423         // Implements the `stackalloc' keyword
8424         //
8425         public class StackAlloc : Expression {
8426                 Type otype;
8427                 Expression t;
8428                 Expression count;
8429                 
8430                 public StackAlloc (Expression type, Expression count, Location l)
8431                 {
8432                         t = type;
8433                         this.count = count;
8434                         loc = l;
8435                 }
8436
8437                 public override Expression DoResolve (EmitContext ec)
8438                 {
8439                         count = count.Resolve (ec);
8440                         if (count == null)
8441                                 return null;
8442                         
8443                         if (count.Type != TypeManager.int32_type){
8444                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8445                                 if (count == null)
8446                                         return null;
8447                         }
8448
8449                         Constant c = count as Constant;
8450                         if (c != null && c.IsNegative) {
8451                                 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8452                                 return null;
8453                         }
8454
8455                         if (ec.InCatch || ec.InFinally) {
8456                                 Error (255, "Cannot use stackalloc in finally or catch");
8457                                 return null;
8458                         }
8459
8460                         TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8461                         if (texpr == null)
8462                                 return null;
8463
8464                         otype = texpr.Type;
8465
8466                         if (!TypeManager.VerifyUnManaged (otype, loc))
8467                                 return null;
8468
8469                         type = TypeManager.GetPointerType (otype);
8470                         eclass = ExprClass.Value;
8471
8472                         return this;
8473                 }
8474
8475                 public override void Emit (EmitContext ec)
8476                 {
8477                         int size = GetTypeSize (otype);
8478                         ILGenerator ig = ec.ig;
8479                                 
8480                         if (size == 0)
8481                                 ig.Emit (OpCodes.Sizeof, otype);
8482                         else
8483                                 IntConstant.EmitInt (ig, size);
8484                         count.Emit (ec);
8485                         ig.Emit (OpCodes.Mul);
8486                         ig.Emit (OpCodes.Localloc);
8487                 }
8488
8489                 protected override void CloneTo (CloneContext clonectx, Expression t)
8490                 {
8491                         StackAlloc target = (StackAlloc) t;
8492                         target.count = count.Clone (clonectx);
8493                         target.t = t.Clone (clonectx);
8494                 }
8495         }
8496         
8497         public interface IInitializable
8498         {
8499                 bool Initialize (EmitContext ec, Expression target);
8500         }
8501         
8502         public class Initializer
8503         {
8504                 public readonly string Name;
8505                 public readonly object Value;
8506
8507                 public Initializer (string name, Expression value)
8508                 {
8509                         Name = name;
8510                         Value = value;
8511                 }
8512
8513                 public Initializer (string name, IInitializable value)
8514                 {
8515                         Name = name;
8516                         Value = value;
8517                 }
8518         }
8519         
8520         public class ObjectInitializer : IInitializable
8521         {
8522                 readonly ArrayList initializers;
8523                 public ObjectInitializer (ArrayList initializers)
8524                 {
8525                         this.initializers = initializers;
8526                 }
8527                 
8528                 public bool Initialize (EmitContext ec, Expression target)
8529                 {
8530                         ArrayList initialized = new ArrayList (initializers.Count);
8531                         for (int i = initializers.Count - 1; i >= 0; i--) {
8532                                 Initializer initializer = initializers[i] as Initializer;
8533                                 if (initialized.Contains (initializer.Name)) {
8534                                         //FIXME proper error
8535                                         Console.WriteLine ("Object member can only be initialized once");
8536                                         return false;
8537                                 }
8538                                 
8539                                 MemberAccess ma = new MemberAccess (target, initializer.Name);
8540                                 Expression expr = initializer.Value as Expression;
8541                                 // If it's an expresison, append the assign.
8542                                 if (expr != null) {
8543                                         Assign a = new Assign (ma, expr);
8544                                         ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (a));
8545                                 }
8546                                 // If it's another initializer (object or collection), initialize it.
8547                                 else if (!((IInitializable)initializer.Value).Initialize (ec, ma))
8548                                                         return false;
8549                                 
8550                                 initialized.Add (initializer.Name);
8551                         }
8552                         return true;
8553                 }
8554         }
8555         
8556         public class CollectionInitializer : IInitializable
8557         {
8558                 readonly ArrayList items;
8559                 public CollectionInitializer (ArrayList items)
8560                 {
8561                         this.items = items;
8562                 }
8563                 
8564                 bool CheckCollection (EmitContext ec, Expression e)
8565                 {
8566                         if (e == null || e.Type == null)
8567                                 return false;
8568                         bool is_ienumerable = false;
8569                         foreach (Type t in TypeManager.GetInterfaces (e.Type))
8570                                 if (t == typeof (IEnumerable)) {
8571                                         is_ienumerable = true;
8572                                         break;
8573                                 }
8574                         
8575                         if (!is_ienumerable)
8576                                 return false;
8577                         
8578                         MethodGroupExpr mg = Expression.MemberLookup (
8579                                 ec.ContainerType, e.Type, "Add", MemberTypes.Method,
8580                                 Expression.AllBindingFlags, Location.Null) as MethodGroupExpr;
8581
8582                         if (mg == null)
8583                                         return false;
8584                         
8585                         foreach (MethodInfo mi in mg.Methods) {
8586                                 if (TypeManager.GetParameterData (mi).Count != 1)
8587                                         continue;
8588                                 if ((mi.Attributes & MethodAttributes.Public) != MethodAttributes.Public)
8589                                         continue;
8590                                 return true;
8591                         }
8592                         return false;
8593                 }
8594                 
8595                 public bool Initialize (EmitContext ec, Expression target)
8596                 {
8597                         if (!CheckCollection (ec, target.Resolve (ec))) {
8598                                 // FIXME throw proper error
8599                                 Console.WriteLine ("Error: This is not a collection");
8600                                 return false;
8601                         }
8602                         
8603                         for (int i = items.Count - 1; i >= 0; i--) {
8604                                 MemberAccess ma = new MemberAccess (target, "Add");
8605                                 ArrayList array = new ArrayList ();
8606                                 array.Add (new Argument ((Expression)items[i]));
8607                                 Invocation invoke = new Invocation (ma, array);
8608                                 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (invoke));
8609                         }
8610                         return true;
8611                 }
8612         }
8613         
8614         public class AnonymousTypeInitializer : IInitializable
8615         {
8616                 readonly ArrayList initializers;
8617                 public AnonymousTypeInitializer (ArrayList initializers)
8618                 {
8619                         this.initializers = initializers;
8620                 }
8621                 
8622                 public bool Initialize (EmitContext ec, Expression target)
8623                 {
8624                         foreach (AnonymousTypeParameter p in initializers) {
8625                                 MemberAccess ma = new MemberAccess (target, p.Name);
8626                                 Assign a = p.Expression as Assign;
8627                                 Assign assign = new Assign (ma, (a != null) ? a.Source : p.Expression);
8628                                 ec.CurrentBlock.InsertStatementAfterCurrent (new StatementExpression (assign));
8629                         }
8630                         return true;
8631                 }
8632         }
8633
8634         public class NewInitialize : New, IInitializable
8635         {
8636                 IInitializable initializer;
8637
8638                 public bool Initialize (EmitContext ec, Expression target)
8639                 {
8640                         return initializer.Initialize (ec, target);
8641                 }
8642
8643                 public NewInitialize (Expression requested_type, ArrayList arguments, IInitializable initializer, Location l)
8644                         : base (requested_type, arguments, l)
8645                 {
8646                         this.initializer = initializer;
8647                 }
8648         }
8649
8650         public class AnonymousType : Expression
8651         {
8652                 ArrayList parameters;
8653                 TypeContainer parent;
8654                 TypeContainer anonymous_type;
8655
8656                 public AnonymousType (ArrayList parameters, TypeContainer parent, Location loc)
8657                 {
8658                         this.parameters = parameters;
8659                         this.parent = parent;
8660                         this.loc = loc;
8661                 }
8662
8663                 public override Expression DoResolve (EmitContext ec)
8664                 {
8665                         foreach (AnonymousTypeParameter p in parameters)
8666                                 p.Resolve (ec);
8667                         
8668                         anonymous_type = GetAnonymousType (ec);
8669
8670                         TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
8671                         AnonymousTypeInitializer ati = new AnonymousTypeInitializer (parameters);
8672                         return new NewInitialize (te, null, ati, loc).Resolve (ec);
8673                 }
8674
8675                 TypeContainer GetAnonymousType (EmitContext ec)
8676                 {
8677                         // See if we already have an anonymous type with the right fields.
8678                         // If not, create one.
8679                         // 
8680                         // Look through all availible pre-existing anonymous types:
8681                         foreach (DictionaryEntry d in parent.AnonymousTypes) {
8682                                 ArrayList p = d.Key as ArrayList;
8683                                 if (p.Count != parameters.Count)
8684                                         continue;
8685                                 bool match = true;
8686                                 // And for each of the fields we need...
8687                                 foreach (AnonymousTypeParameter atp in parameters) {
8688                                         // ... check each of the pre-existing A-type's fields.
8689                                         bool found = false;
8690                                         foreach (AnonymousTypeParameter a in p)
8691                                                 if (atp.Equals(a)) {
8692                                                         found = true;
8693                                                         break;
8694                                                 }
8695                                         // If the pre-existing A-type doesn't have one of our fields, try the next one
8696                                         if (!found) {
8697                                                 match = false;
8698                                                 break;
8699                                         }
8700                                 }
8701                                 // If it's a match, return it.
8702                                 if (match)
8703                                         return d.Value as TypeContainer;
8704                         }
8705                         // Otherwise, create a new type.
8706                         return CreateAnonymousType (ec);
8707                 }
8708
8709                 TypeContainer CreateAnonymousType (EmitContext ec)
8710                 {
8711                         TypeContainer type = new AnonymousClass (parent, loc);
8712                         foreach (AnonymousTypeParameter p in parameters) {
8713                                 TypeExpression te = new TypeExpression (p.Type, loc);
8714                                 Field field = new Field (type, te, Modifiers.PUBLIC, p.Name, null, loc);
8715                                 type.AddField (field);
8716                         }
8717                         type.DefineType ();
8718                         type.DefineMembers ();
8719                         parent.AnonymousTypes.Add (parameters, type);
8720                         return type;
8721                 }
8722
8723                 public override void Emit (EmitContext ec)
8724                 {
8725                         TypeExpression te = new TypeExpression (anonymous_type.TypeBuilder, loc);
8726                         new New (te, null, loc).Emit(ec);
8727                 }
8728         }
8729
8730         public class AnonymousTypeParameter : Expression
8731         {
8732                 LocatedToken token;
8733                 string name;
8734                 Expression expression;
8735
8736                 public LocatedToken Token {
8737                         get { return token; }
8738                 }
8739
8740                 public string Name {
8741                         get { return name; }
8742                 }
8743
8744                 public Expression Expression {
8745                         get { return expression; }
8746                 }
8747
8748                 public override bool Equals (object o)
8749                 {
8750                         AnonymousTypeParameter other = o as AnonymousTypeParameter;
8751                         return other != null && Name == other.Name && Type == other.Type;
8752                 }
8753                 
8754                 public override int GetHashCode ()
8755                 {
8756                         return name.GetHashCode ();
8757                 }
8758
8759                 public override Expression DoResolve (EmitContext ec)
8760                 {
8761                         Expression e = expression.Resolve(ec);
8762                         type = e.Type;
8763                         return e;
8764                 }
8765
8766                 public override void Emit (EmitContext ec)
8767                 {
8768                         expression.Emit(ec);
8769                 }
8770
8771                 public AnonymousTypeParameter (Expression expression, string name)
8772                 {
8773                         this.name = name;
8774                         this.expression = expression;
8775                         type = expression.Type;
8776                 }
8777         }
8778 }