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