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