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