2007-04-01 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / expression.cs
1 //
2 // expression.cs: Expression representation for the IL tree.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Marek Safar (marek.safar@seznam.cz)
7 //
8 // (C) 2001, 2002, 2003 Ximian, Inc.
9 // (C) 2003, 2004 Novell, Inc.
10 //
11 #define USE_OLD
12
13 namespace Mono.CSharp {
14         using System;
15         using System.Collections;
16         using System.Reflection;
17         using System.Reflection.Emit;
18         using System.Text;
19
20         /// <summary>
21         ///   This is just a helper class, it is generated by Unary, UnaryMutator
22         ///   when an overloaded method has been found.  It just emits the code for a
23         ///   static call.
24         /// </summary>
25         public class StaticCallExpr : ExpressionStatement {
26                 ArrayList args;
27                 MethodInfo mi;
28
29                 public StaticCallExpr (MethodInfo m, ArrayList a, Location l)
30                 {
31                         mi = m;
32                         args = a;
33
34                         type = m.ReturnType;
35                         eclass = ExprClass.Value;
36                         loc = l;
37                 }
38
39                 public override Expression DoResolve (EmitContext ec)
40                 {
41                         //
42                         // We are born fully resolved
43                         //
44                         return this;
45                 }
46
47                 public override void Emit (EmitContext ec)
48                 {
49                         if (args != null) 
50                                 Invocation.EmitArguments (ec, mi, args, false, null);
51
52                         ec.ig.Emit (OpCodes.Call, mi);
53                         return;
54                 }
55                 
56                 static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
57                                                          Expression e, Location loc)
58                 {
59                         ArrayList args;
60                         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                         bool value_on_stack;
5302
5303                         if (is_type_parameter)
5304                                 value_on_stack = DoEmitTypeParameter (ec);
5305                         else
5306                                 value_on_stack = DoEmit (ec, false);
5307
5308                         if (value_on_stack)
5309                                 ec.ig.Emit (OpCodes.Pop);
5310
5311                 }
5312
5313                 public void AddressOf (EmitContext ec, AddressOp Mode)
5314                 {
5315                         if (is_type_parameter)
5316                                 throw new InvalidOperationException ();
5317
5318                         if (!type.IsValueType){
5319                                 //
5320                                 // We throw an exception.  So far, I believe we only need to support
5321                                 // value types:
5322                                 // foreach (int j in new StructType ())
5323                                 // see bug 42390
5324                                 //
5325                                 throw new Exception ("AddressOf should not be used for classes");
5326                         }
5327
5328                         if (!value_target_set)
5329                                 value_target = new LocalTemporary (type);
5330                                         
5331                         IMemoryLocation ml = (IMemoryLocation) value_target;
5332                         ml.AddressOf (ec, AddressOp.Store);
5333                         if (method != null)
5334                                 Invocation.EmitArguments (ec, method, Arguments, false, null);
5335
5336                         if (method == null)
5337                                 ec.ig.Emit (OpCodes.Initobj, type);
5338                         else 
5339                                 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5340                         
5341                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
5342                 }
5343
5344                 protected override void CloneTo (CloneContext clonectx, Expression t)
5345                 {
5346                         New target = (New) t;
5347
5348                         target.RequestedType = RequestedType.Clone (clonectx);
5349                         if (Arguments != null){
5350                                 target.Arguments = new ArrayList ();
5351                                 foreach (Argument a in Arguments){
5352                                         target.Arguments.Add (a.Clone (clonectx));
5353                                 }
5354                         }
5355                 }
5356         }
5357
5358         /// <summary>
5359         ///   14.5.10.2: Represents an array creation expression.
5360         /// </summary>
5361         ///
5362         /// <remarks>
5363         ///   There are two possible scenarios here: one is an array creation
5364         ///   expression that specifies the dimensions and optionally the
5365         ///   initialization data and the other which does not need dimensions
5366         ///   specified but where initialization data is mandatory.
5367         /// </remarks>
5368         public class ArrayCreation : Expression {
5369                 Expression requested_base_type;
5370                 ArrayList initializers;
5371
5372                 //
5373                 // The list of Argument types.
5374                 // This is used to construct the `newarray' or constructor signature
5375                 //
5376                 ArrayList arguments;
5377
5378                 //
5379                 // Method used to create the array object.
5380                 //
5381                 MethodBase new_method = null;
5382                 
5383                 Type array_element_type;
5384                 Type underlying_type;
5385                 bool is_one_dimensional = false;
5386                 bool is_builtin_type = false;
5387                 bool expect_initializers = false;
5388                 int num_arguments = 0;
5389                 int dimensions = 0;
5390                 string rank;
5391
5392                 ArrayList array_data;
5393
5394                 IDictionary bounds;
5395
5396                 // The number of constants in array initializers
5397                 int const_initializers_count;
5398                 bool only_constant_initializers;
5399                 
5400                 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5401                 {
5402                         this.requested_base_type = requested_base_type;
5403                         this.initializers = initializers;
5404                         this.rank = rank;
5405                         loc = l;
5406
5407                         arguments = new ArrayList ();
5408
5409                         foreach (Expression e in exprs) {
5410                                 arguments.Add (new Argument (e, Argument.AType.Expression));
5411                                 num_arguments++;
5412                         }
5413                 }
5414
5415                 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5416                 {
5417                         this.requested_base_type = requested_base_type;
5418                         this.initializers = initializers;
5419                         this.rank = rank;
5420                         loc = l;
5421
5422                         //this.rank = rank.Substring (0, rank.LastIndexOf ('['));
5423                         //
5424                         //string tmp = rank.Substring (rank.LastIndexOf ('['));
5425                         //
5426                         //dimensions = tmp.Length - 1;
5427                         expect_initializers = true;
5428                 }
5429
5430                 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5431                 {
5432                         StringBuilder sb = new StringBuilder (rank);
5433                         
5434                         sb.Append ("[");
5435                         for (int i = 1; i < idx_count; i++)
5436                                 sb.Append (",");
5437                         
5438                         sb.Append ("]");
5439
5440                         return new ComposedCast (base_type, sb.ToString (), loc);
5441                 }
5442
5443                 void Error_IncorrectArrayInitializer ()
5444                 {
5445                         Error (178, "Invalid rank specifier: expected `,' or `]'");
5446                 }
5447                 
5448                 bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5449                 {
5450                         if (specified_dims) { 
5451                                 Argument a = (Argument) arguments [idx];
5452
5453                                 if (!a.Resolve (ec, loc))
5454                                         return false;
5455
5456                                 Constant c = a.Expr as Constant;
5457                                 if (c != null) {
5458                                         c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
5459                                 }
5460
5461                                 if (c == null) {
5462                                         Report.Error (150, a.Expr.Location, "A constant value is expected");
5463                                         return false;
5464                                 }
5465
5466                                 int value = (int) c.GetValue ();
5467                                 
5468                                 if (value != probe.Count) {
5469                                         Error_IncorrectArrayInitializer ();
5470                                         return false;
5471                                 }
5472                                 
5473                                 bounds [idx] = value;
5474                         }
5475
5476                         int child_bounds = -1;
5477                         only_constant_initializers = true;
5478                         for (int i = 0; i < probe.Count; ++i) {
5479                                 object o = probe [i];
5480                                 if (o is ArrayList) {
5481                                         ArrayList sub_probe = o as ArrayList;
5482                                         int current_bounds = sub_probe.Count;
5483                                         
5484                                         if (child_bounds == -1) 
5485                                                 child_bounds = current_bounds;
5486
5487                                         else if (child_bounds != current_bounds){
5488                                                 Error_IncorrectArrayInitializer ();
5489                                                 return false;
5490                                         }
5491                                         if (idx + 1 >= dimensions){
5492                                                 Error (623, "Array initializers can only be used in a variable or field initializer. Try using a new expression instead");
5493                                                 return false;
5494                                         }
5495                                         
5496                                         bool ret = CheckIndices (ec, sub_probe, idx + 1, specified_dims);
5497                                         if (!ret)
5498                                                 return false;
5499                                 } else {
5500                                         if (child_bounds != -1){
5501                                                 Error_IncorrectArrayInitializer ();
5502                                                 return false;
5503                                         }
5504                                         
5505                                         Expression tmp = (Expression) o;
5506                                         tmp = tmp.Resolve (ec);
5507                                         if (tmp == null)
5508                                                 return false;
5509
5510                                         Expression conv = Convert.ImplicitConversionRequired (
5511                                                 ec, tmp, underlying_type, loc);
5512                                         
5513                                         if (conv == null) 
5514                                                 return false;
5515
5516                                         // Initializers with the default values can be ignored
5517                                         Constant c = conv as Constant;
5518                                         if (c != null) {
5519                                                 if (c.IsDefaultInitializer (array_element_type)) {
5520                                                         conv = null;
5521                                                 }
5522                                                 else {
5523                                                         ++const_initializers_count;
5524                                                 }
5525                                         } else {
5526                                                 only_constant_initializers = false;
5527                                         }
5528                                         
5529                                         array_data.Add (conv);
5530                                 }
5531                         }
5532
5533                         return true;
5534                 }
5535                 
5536                 public void UpdateIndices ()
5537                 {
5538                         int i = 0;
5539                         for (ArrayList probe = initializers; probe != null;) {
5540                                 if (probe.Count > 0 && probe [0] is ArrayList) {
5541                                         Expression e = new IntConstant (probe.Count, Location.Null);
5542                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5543
5544                                         bounds [i++] =  probe.Count;
5545                                         
5546                                         probe = (ArrayList) probe [0];
5547                                         
5548                                 } else {
5549                                         Expression e = new IntConstant (probe.Count, Location.Null);
5550                                         arguments.Add (new Argument (e, Argument.AType.Expression));
5551
5552                                         bounds [i++] = probe.Count;
5553                                         return;
5554                                 }
5555                         }
5556
5557                 }
5558                 
5559                 bool ResolveInitializers (EmitContext ec)
5560                 {
5561                         if (initializers == null) {
5562                                 return !expect_initializers;
5563                         }
5564                         
5565                         if (underlying_type == null)
5566                                 return false;
5567                         
5568                         //
5569                         // We use this to store all the date values in the order in which we
5570                         // will need to store them in the byte blob later
5571                         //
5572                         array_data = new ArrayList ();
5573                         bounds = new System.Collections.Specialized.HybridDictionary ();
5574                         
5575                         if (arguments != null)
5576                                 return CheckIndices (ec, initializers, 0, true);
5577
5578                         arguments = new ArrayList ();
5579
5580                         if (!CheckIndices (ec, initializers, 0, false))
5581                                 return false;
5582                                 
5583                         UpdateIndices ();
5584                                 
5585                         if (arguments.Count != dimensions) {
5586                                 Error_IncorrectArrayInitializer ();
5587                                 return false;
5588                         }
5589
5590                         return true;
5591                 }
5592
5593                 //
5594                 // Creates the type of the array
5595                 //
5596                 bool LookupType (EmitContext ec)
5597                 {
5598                         StringBuilder array_qualifier = new StringBuilder (rank);
5599
5600                         //
5601                         // `In the first form allocates an array instace of the type that results
5602                         // from deleting each of the individual expression from the expression list'
5603                         //
5604                         if (num_arguments > 0) {
5605                                 array_qualifier.Append ("[");
5606                                 for (int i = num_arguments-1; i > 0; i--)
5607                                         array_qualifier.Append (",");
5608                                 array_qualifier.Append ("]");                           
5609                         }
5610
5611                         //
5612                         // Lookup the type
5613                         //
5614                         TypeExpr array_type_expr;
5615                         array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5616                         array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
5617                         if (array_type_expr == null)
5618                                 return false;
5619
5620                         type = array_type_expr.Type;
5621                         underlying_type = TypeManager.GetElementType (type);
5622                         dimensions = type.GetArrayRank ();
5623
5624                         return true;
5625                 }
5626                 
5627                 public override Expression DoResolve (EmitContext ec)
5628                 {
5629                         if (type != null)
5630                                 return this;
5631
5632                         if (!LookupType (ec))
5633                                 return null;
5634                         
5635                         array_element_type = TypeManager.GetElementType (type);
5636                         if (array_element_type.IsAbstract && array_element_type.IsSealed) {
5637                                 Report.Error (719, loc, "`{0}': array elements cannot be of static type", TypeManager.CSharpName (array_element_type));
5638                                 return null;
5639                         }
5640
5641                         //
5642                         // First step is to validate the initializers and fill
5643                         // in any missing bits
5644                         //
5645                         if (!ResolveInitializers (ec))
5646                                 return null;
5647
5648                         int arg_count;
5649                         if (arguments == null)
5650                                 arg_count = 0;
5651                         else {
5652                                 arg_count = arguments.Count;
5653                                 foreach (Argument a in arguments){
5654                                         if (!a.Resolve (ec, loc))
5655                                                 return null;
5656
5657                                         Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5658                                         if (real_arg == null)
5659                                                 return null;
5660
5661                                         a.Expr = real_arg;
5662                                 }
5663                         }
5664                         
5665                         if (arg_count == 1) {
5666                                 is_one_dimensional = true;
5667                                 eclass = ExprClass.Value;
5668                                 return this;
5669                         }
5670
5671                         is_builtin_type = TypeManager.IsBuiltinType (type);
5672
5673                         if (is_builtin_type) {
5674                                 Expression ml;
5675                                 
5676                                 ml = MemberLookup (ec.ContainerType, type, ".ctor", MemberTypes.Constructor,
5677                                                    AllBindingFlags, loc);
5678                                 
5679                                 if (!(ml is MethodGroupExpr)) {
5680                                         ml.Error_UnexpectedKind (ec.DeclContainer, "method group", loc);
5681                                         return null;
5682                                 }
5683                                 
5684                                 if (ml == null) {
5685                                         Error (-6, "New invocation: Can not find a constructor for " +
5686                                                       "this argument list");
5687                                         return null;
5688                                 }
5689                                 
5690                                 new_method = ((MethodGroupExpr) ml).OverloadResolve (
5691                                         ec, arguments, false, loc);
5692
5693                                 if (new_method == null) {
5694                                         Error (-6, "New invocation: Can not find a constructor for " +
5695                                                       "this argument list");
5696                                         return null;
5697                                 }
5698                                 
5699                                 eclass = ExprClass.Value;
5700                                 return this;
5701                         } else {
5702                                 ModuleBuilder mb = CodeGen.Module.Builder;
5703                                 ArrayList args = new ArrayList ();
5704                                 
5705                                 if (arguments != null) {
5706                                         for (int i = 0; i < arg_count; i++)
5707                                                 args.Add (TypeManager.int32_type);
5708                                 }
5709                                 
5710                                 Type [] arg_types = null;
5711
5712                                 if (args.Count > 0)
5713                                         arg_types = new Type [args.Count];
5714                                 
5715                                 args.CopyTo (arg_types, 0);
5716                                 
5717                                 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5718                                                             arg_types);
5719
5720                                 if (new_method == null) {
5721                                         Error (-6, "New invocation: Can not find a constructor for " +
5722                                                       "this argument list");
5723                                         return null;
5724                                 }
5725                                 
5726                                 eclass = ExprClass.Value;
5727                                 return this;
5728                         }
5729                 }
5730
5731                 byte [] MakeByteBlob ()
5732                 {
5733                         int factor;
5734                         byte [] data;
5735                         byte [] element;
5736                         int count = array_data.Count;
5737
5738                         if (underlying_type.IsEnum)
5739                                 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
5740                         
5741                         factor = GetTypeSize (underlying_type);
5742                         if (factor == 0)
5743                                 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
5744
5745                         data = new byte [(count * factor + 4) & ~3];
5746                         int idx = 0;
5747
5748                         for (int i = 0; i < count; ++i) {
5749                                 object v = array_data [i];
5750
5751                                 if (v is EnumConstant)
5752                                         v = ((EnumConstant) v).Child;
5753                                 
5754                                 if (v is Constant && !(v is StringConstant))
5755                                         v = ((Constant) v).GetValue ();
5756                                 else {
5757                                         idx += factor;
5758                                         continue;
5759                                 }
5760                                 
5761                                 if (underlying_type == TypeManager.int64_type){
5762                                         if (!(v is Expression)){
5763                                                 long val = (long) v;
5764                                                 
5765                                                 for (int j = 0; j < factor; ++j) {
5766                                                         data [idx + j] = (byte) (val & 0xFF);
5767                                                         val = (val >> 8);
5768                                                 }
5769                                         }
5770                                 } else if (underlying_type == TypeManager.uint64_type){
5771                                         if (!(v is Expression)){
5772                                                 ulong val = (ulong) v;
5773
5774                                                 for (int j = 0; j < factor; ++j) {
5775                                                         data [idx + j] = (byte) (val & 0xFF);
5776                                                         val = (val >> 8);
5777                                                 }
5778                                         }
5779                                 } else if (underlying_type == TypeManager.float_type) {
5780                                         if (!(v is Expression)){
5781                                                 element = BitConverter.GetBytes ((float) v);
5782                                                         
5783                                                 for (int j = 0; j < factor; ++j)
5784                                                         data [idx + j] = element [j];
5785                                                 if (!BitConverter.IsLittleEndian)
5786                                                         System.Array.Reverse (data, idx, 4);
5787                                         }
5788                                 } else if (underlying_type == TypeManager.double_type) {
5789                                         if (!(v is Expression)){
5790                                                 element = BitConverter.GetBytes ((double) v);
5791
5792                                                 for (int j = 0; j < factor; ++j)
5793                                                         data [idx + j] = element [j];
5794
5795                                                 // FIXME: Handle the ARM float format.
5796                                                 if (!BitConverter.IsLittleEndian)
5797                                                         System.Array.Reverse (data, idx, 8);
5798                                         }
5799                                 } else if (underlying_type == TypeManager.char_type){
5800                                         if (!(v is Expression)){
5801                                                 int val = (int) ((char) v);
5802                                                 
5803                                                 data [idx] = (byte) (val & 0xff);
5804                                                 data [idx+1] = (byte) (val >> 8);
5805                                         }
5806                                 } else if (underlying_type == TypeManager.short_type){
5807                                         if (!(v is Expression)){
5808                                                 int val = (int) ((short) v);
5809                                         
5810                                                 data [idx] = (byte) (val & 0xff);
5811                                                 data [idx+1] = (byte) (val >> 8);
5812                                         }
5813                                 } else if (underlying_type == TypeManager.ushort_type){
5814                                         if (!(v is Expression)){
5815                                                 int val = (int) ((ushort) v);
5816                                         
5817                                                 data [idx] = (byte) (val & 0xff);
5818                                                 data [idx+1] = (byte) (val >> 8);
5819                                         }
5820                                 } else if (underlying_type == TypeManager.int32_type) {
5821                                         if (!(v is Expression)){
5822                                                 int val = (int) v;
5823                                         
5824                                                 data [idx]   = (byte) (val & 0xff);
5825                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
5826                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
5827                                                 data [idx+3] = (byte) (val >> 24);
5828                                         }
5829                                 } else if (underlying_type == TypeManager.uint32_type) {
5830                                         if (!(v is Expression)){
5831                                                 uint val = (uint) v;
5832                                         
5833                                                 data [idx]   = (byte) (val & 0xff);
5834                                                 data [idx+1] = (byte) ((val >> 8) & 0xff);
5835                                                 data [idx+2] = (byte) ((val >> 16) & 0xff);
5836                                                 data [idx+3] = (byte) (val >> 24);
5837                                         }
5838                                 } else if (underlying_type == TypeManager.sbyte_type) {
5839                                         if (!(v is Expression)){
5840                                                 sbyte val = (sbyte) v;
5841                                                 data [idx] = (byte) val;
5842                                         }
5843                                 } else if (underlying_type == TypeManager.byte_type) {
5844                                         if (!(v is Expression)){
5845                                                 byte val = (byte) v;
5846                                                 data [idx] = (byte) val;
5847                                         }
5848                                 } else if (underlying_type == TypeManager.bool_type) {
5849                                         if (!(v is Expression)){
5850                                                 bool val = (bool) v;
5851                                                 data [idx] = (byte) (val ? 1 : 0);
5852                                         }
5853                                 } else if (underlying_type == TypeManager.decimal_type){
5854                                         if (!(v is Expression)){
5855                                                 int [] bits = Decimal.GetBits ((decimal) v);
5856                                                 int p = idx;
5857
5858                                                 // FIXME: For some reason, this doesn't work on the MS runtime.
5859                                                 int [] nbits = new int [4];
5860                                                 nbits [0] = bits [3];
5861                                                 nbits [1] = bits [2];
5862                                                 nbits [2] = bits [0];
5863                                                 nbits [3] = bits [1];
5864                                                 
5865                                                 for (int j = 0; j < 4; j++){
5866                                                         data [p++] = (byte) (nbits [j] & 0xff);
5867                                                         data [p++] = (byte) ((nbits [j] >> 8) & 0xff);
5868                                                         data [p++] = (byte) ((nbits [j] >> 16) & 0xff);
5869                                                         data [p++] = (byte) (nbits [j] >> 24);
5870                                                 }
5871                                         }
5872                                 } else
5873                                         throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
5874
5875                                 idx += factor;
5876                         }
5877
5878                         return data;
5879                 }
5880
5881                 //
5882                 // Emits the initializers for the array
5883                 //
5884                 void EmitStaticInitializers (EmitContext ec)
5885                 {
5886                         //
5887                         // First, the static data
5888                         //
5889                         FieldBuilder fb;
5890                         ILGenerator ig = ec.ig;
5891                         
5892                         byte [] data = MakeByteBlob ();
5893
5894                         fb = RootContext.MakeStaticData (data);
5895
5896                         ig.Emit (OpCodes.Dup);
5897                         ig.Emit (OpCodes.Ldtoken, fb);
5898                         ig.Emit (OpCodes.Call,
5899                                  TypeManager.void_initializearray_array_fieldhandle);
5900                 }
5901
5902                 //
5903                 // Emits pieces of the array that can not be computed at compile
5904                 // time (variables and string locations).
5905                 //
5906                 // This always expect the top value on the stack to be the array
5907                 //
5908                 void EmitDynamicInitializers (EmitContext ec, bool emitConstants)
5909                 {
5910                         ILGenerator ig = ec.ig;
5911                         int dims = bounds.Count;
5912                         int [] current_pos = new int [dims];
5913
5914                         MethodInfo set = null;
5915
5916                         if (dims != 1){
5917                                 Type [] args = new Type [dims + 1];
5918
5919                                 for (int j = 0; j < dims; j++)
5920                                         args [j] = TypeManager.int32_type;
5921                                 args [dims] = array_element_type;
5922                                 
5923                                 set = CodeGen.Module.Builder.GetArrayMethod (
5924                                         type, "Set",
5925                                         CallingConventions.HasThis | CallingConventions.Standard,
5926                                         TypeManager.void_type, args);
5927                         }
5928
5929                         for (int i = 0; i < array_data.Count; i++){
5930
5931                                 Expression e = (Expression)array_data [i];
5932
5933                                 // Constant can be initialized via StaticInitializer
5934                                 if (e != null && !(!emitConstants && e is Constant)) {
5935                                         Type etype = e.Type;
5936
5937                                         ig.Emit (OpCodes.Dup);
5938
5939                                         for (int idx = 0; idx < dims; idx++) 
5940                                                 IntConstant.EmitInt (ig, current_pos [idx]);
5941
5942                                         //
5943                                         // If we are dealing with a struct, get the
5944                                         // address of it, so we can store it.
5945                                         //
5946                                         if ((dims == 1) && etype.IsValueType &&
5947                                             (!TypeManager.IsBuiltinOrEnum (etype) ||
5948                                              etype == TypeManager.decimal_type)) {
5949                                                 if (e is New){
5950                                                         New n = (New) e;
5951
5952                                                         //
5953                                                         // Let new know that we are providing
5954                                                         // the address where to store the results
5955                                                         //
5956                                                         n.DisableTemporaryValueType ();
5957                                                 }
5958
5959                                                 ig.Emit (OpCodes.Ldelema, etype);
5960                                         }
5961
5962                                         e.Emit (ec);
5963
5964                                         if (dims == 1) {
5965                                                 bool is_stobj, has_type_arg;
5966                                                 OpCode op = ArrayAccess.GetStoreOpcode (etype, out is_stobj, out has_type_arg);
5967                                                 if (is_stobj)
5968                                                         ig.Emit (OpCodes.Stobj, etype);
5969                                                 else if (has_type_arg)
5970                                                         ig.Emit (op, etype);
5971                                                 else
5972                                                         ig.Emit (op);
5973                                         } else 
5974                                                 ig.Emit (OpCodes.Call, set);
5975
5976                                 }
5977                                 
5978                                 //
5979                                 // Advance counter
5980                                 //
5981                                 for (int j = dims - 1; j >= 0; j--){
5982                                         current_pos [j]++;
5983                                         if (current_pos [j] < (int) bounds [j])
5984                                                 break;
5985                                         current_pos [j] = 0;
5986                                 }
5987                         }
5988                 }
5989
5990                 void EmitArrayArguments (EmitContext ec)
5991                 {
5992                         ILGenerator ig = ec.ig;
5993                         
5994                         foreach (Argument a in arguments) {
5995                                 Type atype = a.Type;
5996                                 a.Emit (ec);
5997
5998                                 if (atype == TypeManager.uint64_type)
5999                                         ig.Emit (OpCodes.Conv_Ovf_U4);
6000                                 else if (atype == TypeManager.int64_type)
6001                                         ig.Emit (OpCodes.Conv_Ovf_I4);
6002                         }
6003                 }
6004                 
6005                 public override void Emit (EmitContext ec)
6006                 {
6007                         ILGenerator ig = ec.ig;
6008                         
6009                         EmitArrayArguments (ec);
6010                         if (is_one_dimensional)
6011                                 ig.Emit (OpCodes.Newarr, array_element_type);
6012                         else {
6013                                 if (is_builtin_type) 
6014                                         ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
6015                                 else 
6016                                         ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
6017                         }
6018                         
6019                         if (initializers == null)
6020                                 return;
6021
6022                         // Emit static initializer for arrays which have contain more than 4 items and
6023                         // the static initializer will initialize at least 25% of array values.
6024                         // NOTE: const_initializers_count does not contain default constant values.
6025                         if (const_initializers_count >= 4 && const_initializers_count * 4 > (array_data.Count) &&
6026                                 TypeManager.IsPrimitiveType (array_element_type)) {
6027                                 EmitStaticInitializers (ec);
6028
6029                                 if (!only_constant_initializers)
6030                                         EmitDynamicInitializers (ec, false);
6031                         } else {
6032                                 EmitDynamicInitializers (ec, true);
6033                         }                               
6034                 }
6035
6036                 public override bool GetAttributableValue (Type valueType, out object value)
6037                 {
6038                         if (!is_one_dimensional){
6039 //                              Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
6040                                 return base.GetAttributableValue (null, out value);
6041                         }
6042
6043                         if (array_data == null) {
6044                                 Constant c = (Constant)((Argument)arguments [0]).Expr;
6045                                 if (c.IsDefaultValue) {
6046                                         value = Array.CreateInstance (array_element_type, 0);
6047                                         return true;
6048                                 }
6049 //                              Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
6050                                 return base.GetAttributableValue (null, out value);
6051                         }
6052                         
6053                         Array ret = Array.CreateInstance (array_element_type, array_data.Count);
6054                         object element_value;
6055                         for (int i = 0; i < ret.Length; ++i)
6056                         {
6057                                 Expression e = (Expression)array_data [i];
6058
6059                                 // Is null when an initializer is optimized (value == predefined value)
6060                                 if (e == null) 
6061                                         continue;
6062
6063                                 if (!e.GetAttributableValue (array_element_type, out element_value)) {
6064                                         value = null;
6065                                         return false;
6066                                 }
6067                                 ret.SetValue (element_value, i);
6068                         }
6069                         value = ret;
6070                         return true;
6071                 }
6072                 
6073                 protected override void CloneTo (CloneContext clonectx, Expression t)
6074                 {
6075                         ArrayCreation target = (ArrayCreation) t;
6076
6077                         target.requested_base_type = requested_base_type.Clone (clonectx);
6078                         target.arguments = new ArrayList ();
6079                         foreach (Argument a in arguments)
6080                                 target.arguments.Add (a.Clone (clonectx));
6081
6082                         if (initializers != null){
6083                                 target.initializers = new ArrayList ();
6084                                 foreach (Expression initializer in initializers)
6085                                         target.initializers.Add (initializer.Clone (clonectx));
6086                         }
6087                 }
6088         }
6089         
6090         public sealed class CompilerGeneratedThis : This
6091         {
6092                 public static This Instance = new CompilerGeneratedThis ();
6093
6094                 private CompilerGeneratedThis ()
6095                         : base (Location.Null)
6096                 {
6097                 }
6098
6099                 public override Expression DoResolve (EmitContext ec)
6100                 {
6101                         eclass = ExprClass.Variable;
6102                         type = ec.ContainerType;
6103                         variable = new SimpleThis (type);
6104                         return this;
6105                 }
6106         }
6107         
6108         /// <summary>
6109         ///   Represents the `this' construct
6110         /// </summary>
6111
6112         public class This : VariableReference, IVariable
6113         {
6114                 Block block;
6115                 VariableInfo variable_info;
6116                 protected Variable variable;
6117                 bool is_struct;
6118
6119                 public This (Block block, Location loc)
6120                 {
6121                         this.loc = loc;
6122                         this.block = block;
6123                 }
6124
6125                 public This (Location loc)
6126                 {
6127                         this.loc = loc;
6128                 }
6129
6130                 public VariableInfo VariableInfo {
6131                         get { return variable_info; }
6132                 }
6133
6134                 public bool VerifyFixed ()
6135                 {
6136                         return !TypeManager.IsValueType (Type);
6137                 }
6138
6139                 public override bool IsRef {
6140                         get { return is_struct; }
6141                 }
6142
6143                 public override Variable Variable {
6144                         get { return variable; }
6145                 }
6146
6147                 public bool ResolveBase (EmitContext ec)
6148                 {
6149                         eclass = ExprClass.Variable;
6150
6151                         if (ec.TypeContainer.CurrentType != null)
6152                                 type = ec.TypeContainer.CurrentType;
6153                         else
6154                                 type = ec.ContainerType;
6155
6156                         is_struct = ec.TypeContainer is Struct;
6157
6158                         if (ec.IsStatic) {
6159                                 Error (26, "Keyword `this' is not valid in a static property, " +
6160                                        "static method, or static field initializer");
6161                                 return false;
6162                         }
6163
6164                         if (block != null) {
6165                                 if (block.Toplevel.ThisVariable != null)
6166                                         variable_info = block.Toplevel.ThisVariable.VariableInfo;
6167
6168                                 AnonymousContainer am = ec.CurrentAnonymousMethod;
6169                                 if (is_struct && (am != null) && !am.IsIterator) {
6170                                         Report.Error (1673, loc, "Anonymous methods inside structs " +
6171                                                       "cannot access instance members of `this'. " +
6172                                                       "Consider copying `this' to a local variable " +
6173                                                       "outside the anonymous method and using the " +
6174                                                       "local instead.");
6175                                         return false;
6176                                 }
6177
6178                                 RootScopeInfo host = block.Toplevel.RootScope;
6179                                 if ((host != null) && !ec.IsConstructor &&
6180                                     (!is_struct || host.IsIterator)) {
6181                                         variable = host.CaptureThis ();
6182                                         type = variable.Type;
6183                                         is_struct = false;
6184                                 }
6185                         }
6186
6187                         if (variable == null)
6188                                 variable = new SimpleThis (type);
6189                         
6190                         return true;
6191                 }
6192
6193                 //
6194                 // Called from Invocation to check if the invocation is correct
6195                 //
6196                 public bool CheckThisUsage (EmitContext ec)
6197                 {
6198                         if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
6199                             !variable_info.IsAssigned (ec)) {
6200                                 Error (188, "The `this' object cannot be used before all of its " +
6201                                        "fields are assigned to");
6202                                 variable_info.SetAssigned (ec);
6203                                 return false;
6204                         }
6205
6206                         return true;
6207                 }
6208                 
6209                 public override Expression DoResolve (EmitContext ec)
6210                 {
6211                         if (!ResolveBase (ec))
6212                                 return null;
6213
6214
6215                         if (ec.IsFieldInitializer) {
6216                                 Error (27, "Keyword `this' is not available in the current context");
6217                                 return null;
6218                         }
6219
6220                         return this;
6221                 }
6222
6223                 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
6224                 {
6225                         if (!ResolveBase (ec))
6226                                 return null;
6227
6228                         if (variable_info != null)
6229                                 variable_info.SetAssigned (ec);
6230                         
6231                         if (ec.TypeContainer is Class){
6232                                 Error (1604, "Cannot assign to 'this' because it is read-only");
6233                                 return null;
6234                         }
6235
6236                         return this;
6237                 }
6238                 public override int GetHashCode()
6239                 {
6240                         return block.GetHashCode ();
6241                 }
6242
6243                 public override bool Equals (object obj)
6244                 {
6245                         This t = obj as This;
6246                         if (t == null)
6247                                 return false;
6248
6249                         return block == t.block;
6250                 }
6251
6252                 protected class SimpleThis : Variable
6253                 {
6254                         Type type;
6255
6256                         public SimpleThis (Type type)
6257                         {
6258                                 this.type = type;
6259                         }
6260
6261                         public override Type Type {
6262                                 get { return type; }
6263                         }
6264
6265                         public override bool HasInstance {
6266                                 get { return false; }
6267                         }
6268
6269                         public override bool NeedsTemporary {
6270                                 get { return false; }
6271                         }
6272
6273                         public override void EmitInstance (EmitContext ec)
6274                         {
6275                                 // Do nothing.
6276                         }
6277
6278                         public override void Emit (EmitContext ec)
6279                         {
6280                                 ec.ig.Emit (OpCodes.Ldarg_0);
6281                         }
6282
6283                         public override void EmitAssign (EmitContext ec)
6284                         {
6285                                 throw new InvalidOperationException ();
6286                         }
6287
6288                         public override void EmitAddressOf (EmitContext ec)
6289                         {
6290                                 ec.ig.Emit (OpCodes.Ldarg_0);
6291                         }
6292                 }
6293
6294                 protected override void CloneTo (CloneContext clonectx, Expression t)
6295                 {
6296                         This target = (This) t;
6297
6298                         target.block = clonectx.LookupBlock (block);
6299                 }
6300         }
6301
6302         /// <summary>
6303         ///   Represents the `__arglist' construct
6304         /// </summary>
6305         public class ArglistAccess : Expression
6306         {
6307                 public ArglistAccess (Location loc)
6308                 {
6309                         this.loc = loc;
6310                 }
6311
6312                 public override Expression DoResolve (EmitContext ec)
6313                 {
6314                         eclass = ExprClass.Variable;
6315                         type = TypeManager.runtime_argument_handle_type;
6316
6317                         if (ec.IsFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs) 
6318                         {
6319                                 Error (190, "The __arglist construct is valid only within " +
6320                                        "a variable argument method");
6321                                 return null;
6322                         }
6323
6324                         return this;
6325                 }
6326
6327                 public override void Emit (EmitContext ec)
6328                 {
6329                         ec.ig.Emit (OpCodes.Arglist);
6330                 }
6331
6332                 protected override void CloneTo (CloneContext clonectx, Expression target)
6333                 {
6334                         // nothing.
6335                 }
6336         }
6337
6338         /// <summary>
6339         ///   Represents the `__arglist (....)' construct
6340         /// </summary>
6341         public class Arglist : Expression
6342         {
6343                 public Argument[] Arguments;
6344
6345                 public Arglist (Location loc)
6346                         : this (Argument.Empty, loc)
6347                 {
6348                 }
6349
6350                 public Arglist (Argument[] args, Location l)
6351                 {
6352                         Arguments = args;
6353                         loc = l;
6354                 }
6355
6356                 public Type[] ArgumentTypes {
6357                         get {
6358                                 Type[] retval = new Type [Arguments.Length];
6359                                 for (int i = 0; i < Arguments.Length; i++)
6360                                         retval [i] = Arguments [i].Type;
6361                                 return retval;
6362                         }
6363                 }
6364
6365                 public override Expression DoResolve (EmitContext ec)
6366                 {
6367                         eclass = ExprClass.Variable;
6368                         type = TypeManager.runtime_argument_handle_type;
6369
6370                         foreach (Argument arg in Arguments) {
6371                                 if (!arg.Resolve (ec, loc))
6372                                         return null;
6373                         }
6374
6375                         return this;
6376                 }
6377
6378                 public override void Emit (EmitContext ec)
6379                 {
6380                         foreach (Argument arg in Arguments)
6381                                 arg.Emit (ec);
6382                 }
6383
6384                 protected override void CloneTo (CloneContext clonectx, Expression t)
6385                 {
6386                         Arglist target = (Arglist) t;
6387
6388                         target.Arguments = new Argument [Arguments.Length];
6389                         for (int i = 0; i < Arguments.Length; i++)
6390                                 target.Arguments [i] = Arguments [i].Clone (clonectx);
6391                 }
6392         }
6393
6394         //
6395         // This produces the value that renders an instance, used by the iterators code
6396         //
6397         public class ProxyInstance : Expression, IMemoryLocation  {
6398                 public override Expression DoResolve (EmitContext ec)
6399                 {
6400                         eclass = ExprClass.Variable;
6401                         type = ec.ContainerType;
6402                         return this;
6403                 }
6404                 
6405                 public override void Emit (EmitContext ec)
6406                 {
6407                         ec.ig.Emit (OpCodes.Ldarg_0);
6408
6409                 }
6410                 
6411                 public void AddressOf (EmitContext ec, AddressOp mode)
6412                 {
6413                         ec.ig.Emit (OpCodes.Ldarg_0);
6414                 }
6415         }
6416
6417         /// <summary>
6418         ///   Implements the typeof operator
6419         /// </summary>
6420         public class TypeOf : Expression {
6421                 Expression QueriedType;
6422                 protected Type typearg;
6423                 
6424                 public TypeOf (Expression queried_type, Location l)
6425                 {
6426                         QueriedType = queried_type;
6427                         loc = l;
6428                 }
6429
6430                 public override Expression DoResolve (EmitContext ec)
6431                 {
6432                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6433                         if (texpr == null)
6434                                 return null;
6435
6436                         typearg = texpr.Type;
6437
6438                         if (typearg == TypeManager.void_type) {
6439                                 Error (673, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
6440                                 return null;
6441                         }
6442
6443                         if (typearg.IsPointer && !ec.InUnsafe){
6444                                 UnsafeError (loc);
6445                                 return null;
6446                         }
6447
6448                         type = TypeManager.type_type;
6449                         // Even though what is returned is a type object, it's treated as a value by the compiler.
6450                         // In particular, 'typeof (Foo).X' is something totally different from 'Foo.X'.
6451                         eclass = ExprClass.Value;
6452                         return this;
6453                 }
6454
6455                 public override void Emit (EmitContext ec)
6456                 {
6457                         ec.ig.Emit (OpCodes.Ldtoken, typearg);
6458                         ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6459                 }
6460
6461                 public override bool GetAttributableValue (Type valueType, out object value)
6462                 {
6463                         if (TypeManager.ContainsGenericParameters (typearg)) {
6464                                 Report.SymbolRelatedToPreviousError(typearg);
6465                                 Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters",
6466                                              TypeManager.CSharpName(typearg));
6467                                 value = null;
6468                                 return false;
6469                         }
6470
6471                         if (valueType == TypeManager.object_type) {
6472                                 value = (object)typearg;
6473                                 return true;
6474                         }
6475                         value = typearg;
6476                         return true;
6477                 }
6478
6479                 public Type TypeArgument
6480                 {
6481                         get
6482                         {
6483                                 return typearg;
6484                         }
6485                 }
6486
6487                 protected override void CloneTo (CloneContext clonectx, Expression t)
6488                 {
6489                         TypeOf target = (TypeOf) t;
6490
6491                         target.QueriedType = QueriedType.Clone (clonectx);
6492                 }
6493         }
6494
6495         /// <summary>
6496         ///   Implements the `typeof (void)' operator
6497         /// </summary>
6498         public class TypeOfVoid : TypeOf {
6499                 public TypeOfVoid (Location l) : base (null, l)
6500                 {
6501                         loc = l;
6502                 }
6503
6504                 public override Expression DoResolve (EmitContext ec)
6505                 {
6506                         type = TypeManager.type_type;
6507                         typearg = TypeManager.void_type;
6508                         // See description in TypeOf.
6509                         eclass = ExprClass.Value;
6510                         return this;
6511                 }
6512         }
6513
6514         /// <summary>
6515         ///   Implements the sizeof expression
6516         /// </summary>
6517         public class SizeOf : Expression {
6518                 public Expression QueriedType;
6519                 Type type_queried;
6520                 
6521                 public SizeOf (Expression queried_type, Location l)
6522                 {
6523                         this.QueriedType = queried_type;
6524                         loc = l;
6525                 }
6526
6527                 public override Expression DoResolve (EmitContext ec)
6528                 {
6529                         TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
6530                         if (texpr == null)
6531                                 return null;
6532
6533 #if GMCS_SOURCE
6534                         if (texpr is TypeParameterExpr){
6535                                 ((TypeParameterExpr)texpr).Error_CannotUseAsUnmanagedType (loc);
6536                                 return null;
6537                         }
6538 #endif
6539
6540                         type_queried = texpr.Type;
6541                         if (type_queried.IsEnum)
6542                                 type_queried = TypeManager.EnumToUnderlying (type_queried);
6543
6544                         if (type_queried == TypeManager.void_type) {
6545                                 Expression.Error_VoidInvalidInTheContext (loc);
6546                                 return null;
6547                         }
6548
6549                         int size_of = GetTypeSize (type_queried);
6550                         if (size_of > 0) {
6551                                 return new IntConstant (size_of, loc);
6552                         }
6553
6554                         if (!ec.InUnsafe) {
6555                                 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)",
6556                                          TypeManager.CSharpName (type_queried));
6557                                 return null;
6558                         }
6559
6560                         if (!TypeManager.VerifyUnManaged (type_queried, loc)){
6561                                 return null;
6562                         }
6563                         
6564                         type = TypeManager.int32_type;
6565                         eclass = ExprClass.Value;
6566                         return this;
6567                 }
6568
6569                 public override void Emit (EmitContext ec)
6570                 {
6571                         int size = GetTypeSize (type_queried);
6572
6573                         if (size == 0)
6574                                 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6575                         else
6576                                 IntConstant.EmitInt (ec.ig, size);
6577                 }
6578
6579                 protected override void CloneTo (CloneContext clonectx, Expression t)
6580                 {
6581                         SizeOf target = (SizeOf) t;
6582
6583                         target.QueriedType = QueriedType.Clone (clonectx);
6584                 }
6585         }
6586
6587         /// <summary>
6588         ///   Implements the qualified-alias-member (::) expression.
6589         /// </summary>
6590         public class QualifiedAliasMember : Expression
6591         {
6592                 string alias, identifier;
6593
6594                 public QualifiedAliasMember (string alias, string identifier, Location l)
6595                 {
6596                         this.alias = alias;
6597                         this.identifier = identifier;
6598                         loc = l;
6599                 }
6600
6601                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6602                 {
6603                         if (alias == "global")
6604                                 return new MemberAccess (RootNamespace.Global, identifier, loc).ResolveAsTypeStep (ec, silent);
6605
6606                         int errors = Report.Errors;
6607                         FullNamedExpression fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6608                         if (fne == null) {
6609                                 if (errors == Report.Errors)
6610                                         Report.Error (432, loc, "Alias `{0}' not found", alias);
6611                                 return null;
6612                         }
6613                         if (fne.eclass != ExprClass.Namespace) {
6614                                 if (!silent)
6615                                         Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6616                                 return null;
6617                         }
6618                         return new MemberAccess (fne, identifier).ResolveAsTypeStep (ec, silent);
6619                 }
6620
6621                 public override Expression DoResolve (EmitContext ec)
6622                 {
6623                         FullNamedExpression fne;
6624                         if (alias == "global") {
6625                                 fne = RootNamespace.Global;
6626                         } else {
6627                                 int errors = Report.Errors;
6628                                 fne = ec.DeclContainer.NamespaceEntry.LookupAlias (alias);
6629                                 if (fne == null) {
6630                                         if (errors == Report.Errors)
6631                                                 Report.Error (432, loc, "Alias `{0}' not found", alias);
6632                                         return null;
6633                                 }
6634                         }
6635
6636                         Expression retval = new MemberAccess (fne, identifier).DoResolve (ec);
6637                         if (retval == null)
6638                                 return null;
6639
6640                         if (!(retval is FullNamedExpression)) {
6641                                 Report.Error (687, loc, "The expression `{0}::{1}' did not resolve to a namespace or a type", alias, identifier);
6642                                 return null;
6643                         }
6644
6645                         // We defer this check till the end to match the behaviour of CSC
6646                         if (fne.eclass != ExprClass.Namespace) {
6647                                 Report.Error (431, loc, "`{0}' cannot be used with '::' since it denotes a type", alias);
6648                                 return null;
6649                         }
6650                         return retval;
6651                 }
6652
6653                 public override void Emit (EmitContext ec)
6654                 {
6655                         throw new InternalErrorException ("QualifiedAliasMember found in resolved tree");
6656                 }
6657
6658
6659                 public override string ToString ()
6660                 {
6661                         return alias + "::" + identifier;
6662                 }
6663
6664                 public override string GetSignatureForError ()
6665                 {
6666                         return ToString ();
6667                 }
6668
6669                 protected override void CloneTo (CloneContext clonectx, Expression t)
6670                 {
6671                         // Nothing 
6672                 }
6673         }
6674
6675         /// <summary>
6676         ///   Implements the member access expression
6677         /// </summary>
6678         public class MemberAccess : Expression {
6679                 public readonly string Identifier;
6680                 Expression expr;
6681
6682                 public MemberAccess (Expression expr, string id)
6683                         : this (expr, id, expr.Location)
6684                 {
6685                 }
6686
6687                 public MemberAccess (Expression expr, string identifier, Location loc)
6688                 {
6689                         this.expr = expr;
6690                         Identifier = identifier;
6691                         this.loc = loc;
6692                 }
6693
6694                 public MemberAccess (Expression expr, string identifier, TypeArguments args, Location loc)
6695                         : this (expr, identifier, loc)
6696                 {
6697                         this.args = args;
6698                 }
6699
6700                 TypeArguments args;
6701
6702                 public Expression Expr {
6703                         get { return expr; }
6704                 }
6705
6706                 protected string LookupIdentifier {
6707                         get { return MemberName.MakeName (Identifier, args); }
6708                 }
6709
6710                 // TODO: this method has very poor performace for Enum fields and
6711                 // probably for other constants as well
6712                 Expression DoResolve (EmitContext ec, Expression right_side)
6713                 {
6714                         if (type != null)
6715                                 throw new Exception ();
6716
6717                         //
6718                         // Resolve the expression with flow analysis turned off, we'll do the definite
6719                         // assignment checks later.  This is because we don't know yet what the expression
6720                         // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6721                         // definite assignment check on the actual field and not on the whole struct.
6722                         //
6723
6724                         SimpleName original = expr as SimpleName;
6725                         expr = expr.Resolve (ec,
6726                                 ResolveFlags.VariableOrValue | ResolveFlags.Type |
6727                                 ResolveFlags.Intermediate | ResolveFlags.DisableStructFlowAnalysis);
6728
6729                         if (expr == null)
6730                                 return null;
6731
6732                         if (expr is Namespace) {
6733                                 Namespace ns = (Namespace) expr;
6734                                 FullNamedExpression retval = ns.Lookup (ec.DeclContainer, LookupIdentifier, loc);
6735 #if GMCS_SOURCE
6736                                 if ((retval != null) && (args != null))
6737                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (ec, false);
6738 #endif
6739
6740                                 if (retval == null)
6741                                         ns.Error_NamespaceDoesNotExist (ec.DeclContainer, loc, Identifier);
6742                                 return retval;
6743                         }
6744
6745                         Type expr_type = expr.Type;
6746                         if (expr_type.IsPointer || expr_type == TypeManager.void_type || expr is NullLiteral){
6747                                 Unary.Error_OperatorCannotBeApplied (loc, ".", expr_type);
6748                                 return null;
6749                         }
6750                         if (expr_type == TypeManager.anonymous_method_type){
6751                                 Unary.Error_OperatorCannotBeApplied (loc, ".", "anonymous method");
6752                                 return null;
6753                         }
6754
6755                         Constant c = expr as Constant;
6756                         if (c != null && c.GetValue () == null) {
6757                                 Report.Warning (1720, 1, loc, "Expression will always cause a `{0}'",
6758                                         "System.NullReferenceException");
6759                         }
6760
6761                         Expression member_lookup;
6762                         member_lookup = MemberLookup (
6763                                 ec.ContainerType, expr_type, expr_type, Identifier, loc);
6764 #if GMCS_SOURCE
6765                         if ((member_lookup == null) && (args != null)) {
6766                                 member_lookup = MemberLookup (
6767                                         ec.ContainerType, expr_type, expr_type, LookupIdentifier, loc);
6768                         }
6769 #endif
6770                         if (member_lookup == null) {
6771                                 member_lookup = ec.DeclContainer.LookupExtensionMethod (expr_type, Identifier);
6772                                 if (member_lookup != null)
6773                                         return member_lookup.DoResolve (ec);
6774
6775                                 MemberLookupFailed (
6776                                         ec.ContainerType, expr_type, expr_type, Identifier, null, true, loc);
6777                                 return null;
6778                         }
6779
6780                         TypeExpr texpr = member_lookup as TypeExpr;
6781                         if (texpr != null) {
6782                                 if (!(expr is TypeExpr) && 
6783                                     (original == null || !original.IdenticalNameAndTypeName (ec, expr, loc))) {
6784                                         Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
6785                                                 Identifier, member_lookup.GetSignatureForError ());
6786                                         return null;
6787                                 }
6788
6789                                 if (!texpr.CheckAccessLevel (ec.DeclContainer)) {
6790                                         Report.SymbolRelatedToPreviousError (member_lookup.Type);
6791                                         ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type));
6792                                         return null;
6793                                 }
6794
6795 #if GMCS_SOURCE
6796                                 ConstructedType ct = expr as ConstructedType;
6797                                 if (ct != null) {
6798                                         //
6799                                         // When looking up a nested type in a generic instance
6800                                         // via reflection, we always get a generic type definition
6801                                         // and not a generic instance - so we have to do this here.
6802                                         //
6803                                         // See gtest-172-lib.cs and gtest-172.cs for an example.
6804                                         //
6805                                         ct = new ConstructedType (
6806                                                 member_lookup.Type, ct.TypeArguments, loc);
6807
6808                                         return ct.ResolveAsTypeStep (ec, false);
6809                                 }
6810 #endif
6811                                 return member_lookup;
6812                         }
6813
6814                         MemberExpr me = (MemberExpr) member_lookup;
6815                         member_lookup = me.ResolveMemberAccess (ec, expr, loc, original);
6816                         if (member_lookup == null)
6817                                 return null;
6818
6819                         if (args != null) {
6820                                 MethodGroupExpr mg = member_lookup as MethodGroupExpr;
6821                                 if (mg == null)
6822                                         throw new InternalErrorException ();
6823
6824                                 return mg.ResolveGeneric (ec, args);
6825                         }
6826
6827                         if (original != null && !TypeManager.IsValueType (expr_type)) {
6828                                 me = member_lookup as MemberExpr;
6829                                 if (me != null && me.IsInstance) {
6830                                         LocalVariableReference var = expr as LocalVariableReference;
6831                                         if (var != null && !var.VerifyAssigned (ec))
6832                                                 return null;
6833                                 }
6834                         }
6835
6836                         // The following DoResolve/DoResolveLValue will do the definite assignment
6837                         // check.
6838
6839                         if (right_side != null)
6840                                 return member_lookup.DoResolveLValue (ec, right_side);
6841                         else
6842                                 return member_lookup.DoResolve (ec);
6843                 }
6844
6845                 public override Expression DoResolve (EmitContext ec)
6846                 {
6847                         return DoResolve (ec, null);
6848                 }
6849
6850                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6851                 {
6852                         return DoResolve (ec, right_side);
6853                 }
6854
6855                 public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
6856                 {
6857                         return ResolveNamespaceOrType (ec, silent);
6858                 }
6859
6860                 public FullNamedExpression ResolveNamespaceOrType (IResolveContext rc, bool silent)
6861                 {
6862                         FullNamedExpression new_expr = expr.ResolveAsTypeStep (rc, silent);
6863
6864                         if (new_expr == null)
6865                                 return null;
6866
6867                         if (new_expr is Namespace) {
6868                                 Namespace ns = (Namespace) new_expr;
6869                                 FullNamedExpression retval = ns.Lookup (rc.DeclContainer, LookupIdentifier, loc);
6870 #if GMCS_SOURCE
6871                                 if ((retval != null) && (args != null))
6872                                         retval = new ConstructedType (retval, args, loc).ResolveAsTypeStep (rc, false);
6873 #endif
6874                                 if (!silent && retval == null)
6875                                         ns.Error_NamespaceDoesNotExist (rc.DeclContainer, loc, LookupIdentifier);
6876                                 return retval;
6877                         }
6878
6879                         TypeExpr tnew_expr = new_expr.ResolveAsTypeTerminal (rc, false);
6880                         if (tnew_expr == null)
6881                                 return null;
6882
6883                         Type expr_type = tnew_expr.Type;
6884
6885                         if (expr_type.IsPointer){
6886                                 Error (23, "The `.' operator can not be applied to pointer operands (" +
6887                                        TypeManager.CSharpName (expr_type) + ")");
6888                                 return null;
6889                         }
6890
6891                         Expression member_lookup = MemberLookup (
6892                                 rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6893                                 MemberTypes.NestedType, BindingFlags.Public | BindingFlags.NonPublic, loc);
6894                         if (member_lookup == null) {
6895                                 if (silent)
6896                                         return null;
6897
6898                                 member_lookup = MemberLookup(
6899                                     rc.DeclContainer.TypeBuilder, expr_type, expr_type, LookupIdentifier,
6900                                         MemberTypes.All, BindingFlags.Public | BindingFlags.NonPublic, loc);
6901
6902                                 if (member_lookup == null) {
6903                                         Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
6904                                                       Identifier, new_expr.GetSignatureForError ());
6905                                 } else {
6906                                 // TODO: Report.SymbolRelatedToPreviousError
6907                                     member_lookup.Error_UnexpectedKind (null, "type", loc);
6908                                 }
6909                                 return null;
6910                         }
6911
6912                         TypeExpr texpr = member_lookup.ResolveAsTypeTerminal (rc, false);
6913                         if (texpr == null)
6914                                 return null;
6915
6916 #if GMCS_SOURCE
6917                         TypeArguments the_args = args;
6918                         if (TypeManager.HasGenericArguments (expr_type)) {
6919                                 Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
6920
6921                                 TypeArguments new_args = new TypeArguments (loc);
6922                                 foreach (Type decl in decl_args)
6923                                         new_args.Add (new TypeExpression (decl, loc));
6924
6925                                 if (args != null)
6926                                         new_args.Add (args);
6927
6928                                 the_args = new_args;
6929                         }
6930
6931                         if (the_args != null) {
6932                                 ConstructedType ctype = new ConstructedType (texpr.Type, the_args, loc);
6933                                 return ctype.ResolveAsTypeStep (rc, false);
6934                         }
6935 #endif
6936
6937                         return texpr;
6938                 }
6939
6940                 public override void Emit (EmitContext ec)
6941                 {
6942                         throw new Exception ("Should not happen");
6943                 }
6944
6945                 public override string ToString ()
6946                 {
6947                         return expr + "." + MemberName.MakeName (Identifier, args);
6948                 }
6949
6950                 public override string GetSignatureForError ()
6951                 {
6952                         return expr.GetSignatureForError () + "." + Identifier;
6953                 }
6954
6955                 protected override void CloneTo (CloneContext clonectx, Expression t)
6956                 {
6957                         MemberAccess target = (MemberAccess) t;
6958
6959                         target.expr = expr.Clone (clonectx);
6960                 }
6961         }
6962
6963         /// <summary>
6964         ///   Implements checked expressions
6965         /// </summary>
6966         public class CheckedExpr : Expression {
6967
6968                 public Expression Expr;
6969
6970                 public CheckedExpr (Expression e, Location l)
6971                 {
6972                         Expr = e;
6973                         loc = l;
6974                 }
6975
6976                 public override Expression DoResolve (EmitContext ec)
6977                 {
6978                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6979                                 Expr = Expr.Resolve (ec);
6980                         
6981                         if (Expr == null)
6982                                 return null;
6983
6984                         if (Expr is Constant)
6985                                 return Expr;
6986                         
6987                         eclass = Expr.eclass;
6988                         type = Expr.Type;
6989                         return this;
6990                 }
6991
6992                 public override void Emit (EmitContext ec)
6993                 {
6994                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
6995                                 Expr.Emit (ec);
6996                 }
6997
6998                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
6999                 {
7000                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
7001                                 Expr.EmitBranchable (ec, target, onTrue);
7002                 }
7003
7004                 protected override void CloneTo (CloneContext clonectx, Expression t)
7005                 {
7006                         CheckedExpr target = (CheckedExpr) t;
7007
7008                         target.Expr = Expr.Clone (clonectx);
7009                 }
7010         }
7011
7012         /// <summary>
7013         ///   Implements the unchecked expression
7014         /// </summary>
7015         public class UnCheckedExpr : Expression {
7016
7017                 public Expression Expr;
7018
7019                 public UnCheckedExpr (Expression e, Location l)
7020                 {
7021                         Expr = e;
7022                         loc = l;
7023                 }
7024
7025                 public override Expression DoResolve (EmitContext ec)
7026                 {
7027                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7028                                 Expr = Expr.Resolve (ec);
7029
7030                         if (Expr == null)
7031                                 return null;
7032
7033                         if (Expr is Constant)
7034                                 return Expr;
7035                         
7036                         eclass = Expr.eclass;
7037                         type = Expr.Type;
7038                         return this;
7039                 }
7040
7041                 public override void Emit (EmitContext ec)
7042                 {
7043                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7044                                 Expr.Emit (ec);
7045                 }
7046                 
7047                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
7048                 {
7049                         using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
7050                                 Expr.EmitBranchable (ec, target, onTrue);
7051                 }
7052
7053                 protected override void CloneTo (CloneContext clonectx, Expression t)
7054                 {
7055                         UnCheckedExpr target = (UnCheckedExpr) t;
7056
7057                         target.Expr = Expr.Clone (clonectx);
7058                 }
7059         }
7060
7061         /// <summary>
7062         ///   An Element Access expression.
7063         ///
7064         ///   During semantic analysis these are transformed into 
7065         ///   IndexerAccess, ArrayAccess or a PointerArithmetic.
7066         /// </summary>
7067         public class ElementAccess : Expression {
7068                 public ArrayList  Arguments;
7069                 public Expression Expr;
7070                 
7071                 public ElementAccess (Expression e, ArrayList e_list)
7072                 {
7073                         Expr = e;
7074
7075                         loc  = e.Location;
7076                         
7077                         if (e_list == null)
7078                                 return;
7079                         
7080                         Arguments = new ArrayList ();
7081                         foreach (Expression tmp in e_list)
7082                                 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
7083                         
7084                 }
7085
7086                 bool CommonResolve (EmitContext ec)
7087                 {
7088                         Expr = Expr.Resolve (ec);
7089
7090                         if (Expr == null) 
7091                                 return false;
7092
7093                         if (Arguments == null)
7094                                 return false;
7095
7096                         foreach (Argument a in Arguments){
7097                                 if (!a.Resolve (ec, loc))
7098                                         return false;
7099                         }
7100
7101                         return true;
7102                 }
7103
7104                 Expression MakePointerAccess (EmitContext ec, Type t)
7105                 {
7106                         if (t == TypeManager.void_ptr_type){
7107                                 Error (242, "The array index operation is not valid on void pointers");
7108                                 return null;
7109                         }
7110                         if (Arguments.Count != 1){
7111                                 Error (196, "A pointer must be indexed by only one value");
7112                                 return null;
7113                         }
7114                         Expression p;
7115
7116                         p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
7117                         if (p == null)
7118                                 return null;
7119                         return new Indirection (p, loc).Resolve (ec);
7120                 }
7121                 
7122                 public override Expression DoResolve (EmitContext ec)
7123                 {
7124                         if (!CommonResolve (ec))
7125                                 return null;
7126
7127                         //
7128                         // We perform some simple tests, and then to "split" the emit and store
7129                         // code we create an instance of a different class, and return that.
7130                         //
7131                         // I am experimenting with this pattern.
7132                         //
7133                         Type t = Expr.Type;
7134
7135                         if (t == TypeManager.array_type){
7136                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
7137                                 return null;
7138                         }
7139                         
7140                         if (t.IsArray)
7141                                 return (new ArrayAccess (this, loc)).Resolve (ec);
7142                         if (t.IsPointer)
7143                                 return MakePointerAccess (ec, Expr.Type);
7144
7145                         FieldExpr fe = Expr as FieldExpr;
7146                         if (fe != null) {
7147                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7148                                 if (ff != null) {
7149                                         return MakePointerAccess (ec, ff.ElementType);
7150                                 }
7151                         }
7152                         return (new IndexerAccess (this, loc)).Resolve (ec);
7153                 }
7154
7155                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7156                 {
7157                         if (!CommonResolve (ec))
7158                                 return null;
7159
7160                         Type t = Expr.Type;
7161                         if (t.IsArray)
7162                                 return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
7163
7164                         if (t.IsPointer)
7165                                 return MakePointerAccess (ec, Expr.Type);
7166
7167                         FieldExpr fe = Expr as FieldExpr;
7168                         if (fe != null) {
7169                                 IFixedBuffer ff = AttributeTester.GetFixedBuffer (fe.FieldInfo);
7170                                 if (ff != null) {
7171                                         if (!(fe.InstanceExpression is LocalVariableReference) && 
7172                                                 !(fe.InstanceExpression is This)) {
7173                                                 Report.Error (1708, loc, "Fixed size buffers can only be accessed through locals or fields");
7174                                                 return null;
7175                                         }
7176                                         if (!ec.InFixedInitializer && ec.ContainerType.IsValueType) {
7177                                                 Error (1666, "You cannot use fixed size buffers contained in unfixed expressions. Try using the fixed statement");
7178                                                 return null;
7179                                         }
7180                                         return MakePointerAccess (ec, ff.ElementType);
7181                                 }
7182                         }
7183                         return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
7184                 }
7185                 
7186                 public override void Emit (EmitContext ec)
7187                 {
7188                         throw new Exception ("Should never be reached");
7189                 }
7190
7191                 protected override void CloneTo (CloneContext clonectx, Expression t)
7192                 {
7193                         ElementAccess target = (ElementAccess) t;
7194
7195                         target.Expr = Expr.Clone (clonectx);
7196                         target.Arguments = new ArrayList ();
7197                         foreach (Argument a in Arguments)
7198                                 target.Arguments.Add (a.Clone (clonectx));
7199                 }
7200         }
7201
7202         /// <summary>
7203         ///   Implements array access 
7204         /// </summary>
7205         public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
7206                 //
7207                 // Points to our "data" repository
7208                 //
7209                 ElementAccess ea;
7210
7211                 LocalTemporary temp;
7212                 bool prepared;
7213                 
7214                 public ArrayAccess (ElementAccess ea_data, Location l)
7215                 {
7216                         ea = ea_data;
7217                         eclass = ExprClass.Variable;
7218                         loc = l;
7219                 }
7220
7221                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7222                 {
7223                         return DoResolve (ec);
7224                 }
7225
7226                 public override Expression DoResolve (EmitContext ec)
7227                 {
7228 #if false
7229                         ExprClass eclass = ea.Expr.eclass;
7230
7231                         // As long as the type is valid
7232                         if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
7233                               eclass == ExprClass.Value)) {
7234                                 ea.Expr.Error_UnexpectedKind ("variable or value");
7235                                 return null;
7236                         }
7237 #endif
7238
7239                         Type t = ea.Expr.Type;
7240                         if (t.GetArrayRank () != ea.Arguments.Count){
7241                                 Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
7242                                           ea.Arguments.Count.ToString (), t.GetArrayRank ().ToString ());
7243                                 return null;
7244                         }
7245
7246                         type = TypeManager.GetElementType (t);
7247                         if (type.IsPointer && !ec.InUnsafe){
7248                                 UnsafeError (ea.Location);
7249                                 return null;
7250                         }
7251
7252                         foreach (Argument a in ea.Arguments){
7253                                 Type argtype = a.Type;
7254
7255                                 if (argtype == TypeManager.int32_type ||
7256                                     argtype == TypeManager.uint32_type ||
7257                                     argtype == TypeManager.int64_type ||
7258                                     argtype == TypeManager.uint64_type) {
7259                                         Constant c = a.Expr as Constant;
7260                                         if (c != null && c.IsNegative) {
7261                                                 Report.Warning (251, 2, ea.Location, "Indexing an array with a negative index (array indices always start at zero)");
7262                                         }
7263                                         continue;
7264                                 }
7265
7266                                 //
7267                                 // Mhm.  This is strage, because the Argument.Type is not the same as
7268                                 // Argument.Expr.Type: the value changes depending on the ref/out setting.
7269                                 //
7270                                 // Wonder if I will run into trouble for this.
7271                                 //
7272                                 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
7273                                 if (a.Expr == null)
7274                                         return null;
7275                         }
7276                         
7277                         eclass = ExprClass.Variable;
7278
7279                         return this;
7280                 }
7281
7282                 /// <summary>
7283                 ///    Emits the right opcode to load an object of Type `t'
7284                 ///    from an array of T
7285                 /// </summary>
7286                 static public void EmitLoadOpcode (ILGenerator ig, Type type)
7287                 {
7288                         if (type == TypeManager.byte_type || type == TypeManager.bool_type)
7289                                 ig.Emit (OpCodes.Ldelem_U1);
7290                         else if (type == TypeManager.sbyte_type)
7291                                 ig.Emit (OpCodes.Ldelem_I1);
7292                         else if (type == TypeManager.short_type)
7293                                 ig.Emit (OpCodes.Ldelem_I2);
7294                         else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
7295                                 ig.Emit (OpCodes.Ldelem_U2);
7296                         else if (type == TypeManager.int32_type)
7297                                 ig.Emit (OpCodes.Ldelem_I4);
7298                         else if (type == TypeManager.uint32_type)
7299                                 ig.Emit (OpCodes.Ldelem_U4);
7300                         else if (type == TypeManager.uint64_type)
7301                                 ig.Emit (OpCodes.Ldelem_I8);
7302                         else if (type == TypeManager.int64_type)
7303                                 ig.Emit (OpCodes.Ldelem_I8);
7304                         else if (type == TypeManager.float_type)
7305                                 ig.Emit (OpCodes.Ldelem_R4);
7306                         else if (type == TypeManager.double_type)
7307                                 ig.Emit (OpCodes.Ldelem_R8);
7308                         else if (type == TypeManager.intptr_type)
7309                                 ig.Emit (OpCodes.Ldelem_I);
7310                         else if (TypeManager.IsEnumType (type)){
7311                                 EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
7312                         } else if (type.IsValueType){
7313                                 ig.Emit (OpCodes.Ldelema, type);
7314                                 ig.Emit (OpCodes.Ldobj, type);
7315 #if GMCS_SOURCE
7316                         } else if (type.IsGenericParameter) {
7317                                 ig.Emit (OpCodes.Ldelem, type);
7318 #endif
7319                         } else if (type.IsPointer)
7320                                 ig.Emit (OpCodes.Ldelem_I);
7321                         else
7322                                 ig.Emit (OpCodes.Ldelem_Ref);
7323                 }
7324
7325                 /// <summary>
7326                 ///    Returns the right opcode to store an object of Type `t'
7327                 ///    from an array of T.  
7328                 /// </summary>
7329                 static public OpCode GetStoreOpcode (Type t, out bool is_stobj, out bool has_type_arg)
7330                 {
7331                         //Console.WriteLine (new System.Diagnostics.StackTrace ());
7332                         has_type_arg = false; is_stobj = false;
7333                         t = TypeManager.TypeToCoreType (t);
7334                         if (TypeManager.IsEnumType (t))
7335                                 t = TypeManager.EnumToUnderlying (t);
7336                         if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
7337                             t == TypeManager.bool_type)
7338                                 return OpCodes.Stelem_I1;
7339                         else if (t == TypeManager.short_type || t == TypeManager.ushort_type ||
7340                                  t == TypeManager.char_type)
7341                                 return OpCodes.Stelem_I2;
7342                         else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
7343                                 return OpCodes.Stelem_I4;
7344                         else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
7345                                 return OpCodes.Stelem_I8;
7346                         else if (t == TypeManager.float_type)
7347                                 return OpCodes.Stelem_R4;
7348                         else if (t == TypeManager.double_type)
7349                                 return OpCodes.Stelem_R8;
7350                         else if (t == TypeManager.intptr_type) {
7351                                 has_type_arg = true;
7352                                 is_stobj = true;
7353                                 return OpCodes.Stobj;
7354                         } else if (t.IsValueType) {
7355                                 has_type_arg = true;
7356                                 is_stobj = true;
7357                                 return OpCodes.Stobj;
7358 #if GMCS_SOURCE
7359                         } else if (t.IsGenericParameter) {
7360                                 has_type_arg = true;
7361                                 return OpCodes.Stelem;
7362 #endif
7363
7364                         } else if (t.IsPointer)
7365                                 return OpCodes.Stelem_I;
7366                         else
7367                                 return OpCodes.Stelem_Ref;
7368                 }
7369
7370                 MethodInfo FetchGetMethod ()
7371                 {
7372                         ModuleBuilder mb = CodeGen.Module.Builder;
7373                         int arg_count = ea.Arguments.Count;
7374                         Type [] args = new Type [arg_count];
7375                         MethodInfo get;
7376                         
7377                         for (int i = 0; i < arg_count; i++){
7378                                 //args [i++] = a.Type;
7379                                 args [i] = TypeManager.int32_type;
7380                         }
7381                         
7382                         get = mb.GetArrayMethod (
7383                                 ea.Expr.Type, "Get",
7384                                 CallingConventions.HasThis |
7385                                 CallingConventions.Standard,
7386                                 type, args);
7387                         return get;
7388                 }
7389                                 
7390
7391                 MethodInfo FetchAddressMethod ()
7392                 {
7393                         ModuleBuilder mb = CodeGen.Module.Builder;
7394                         int arg_count = ea.Arguments.Count;
7395                         Type [] args = new Type [arg_count];
7396                         MethodInfo address;
7397                         Type ret_type;
7398                         
7399                         ret_type = TypeManager.GetReferenceType (type);
7400                         
7401                         for (int i = 0; i < arg_count; i++){
7402                                 //args [i++] = a.Type;
7403                                 args [i] = TypeManager.int32_type;
7404                         }
7405                         
7406                         address = mb.GetArrayMethod (
7407                                 ea.Expr.Type, "Address",
7408                                 CallingConventions.HasThis |
7409                                 CallingConventions.Standard,
7410                                 ret_type, args);
7411
7412                         return address;
7413                 }
7414
7415                 //
7416                 // Load the array arguments into the stack.
7417                 //
7418                 // If we have been requested to cache the values (cached_locations array
7419                 // initialized), then load the arguments the first time and store them
7420                 // in locals.  otherwise load from local variables.
7421                 //
7422                 void LoadArrayAndArguments (EmitContext ec)
7423                 {
7424                         ILGenerator ig = ec.ig;
7425                         
7426                         ea.Expr.Emit (ec);
7427                         foreach (Argument a in ea.Arguments){
7428                                 Type argtype = a.Expr.Type;
7429                                 
7430                                 a.Expr.Emit (ec);
7431                                 
7432                                 if (argtype == TypeManager.int64_type)
7433                                         ig.Emit (OpCodes.Conv_Ovf_I);
7434                                 else if (argtype == TypeManager.uint64_type)
7435                                         ig.Emit (OpCodes.Conv_Ovf_I_Un);
7436                         }
7437                 }
7438
7439                 public void Emit (EmitContext ec, bool leave_copy)
7440                 {
7441                         int rank = ea.Expr.Type.GetArrayRank ();
7442                         ILGenerator ig = ec.ig;
7443
7444                         if (!prepared) {
7445                                 LoadArrayAndArguments (ec);
7446                                 
7447                                 if (rank == 1)
7448                                         EmitLoadOpcode (ig, type);
7449                                 else {
7450                                         MethodInfo method;
7451                                         
7452                                         method = FetchGetMethod ();
7453                                         ig.Emit (OpCodes.Call, method);
7454                                 }
7455                         } else
7456                                 LoadFromPtr (ec.ig, this.type);
7457                         
7458                         if (leave_copy) {
7459                                 ec.ig.Emit (OpCodes.Dup);
7460                                 temp = new LocalTemporary (this.type);
7461                                 temp.Store (ec);
7462                         }
7463                 }
7464                 
7465                 public override void Emit (EmitContext ec)
7466                 {
7467                         Emit (ec, false);
7468                 }
7469
7470                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7471                 {
7472                         int rank = ea.Expr.Type.GetArrayRank ();
7473                         ILGenerator ig = ec.ig;
7474                         Type t = source.Type;
7475                         prepared = prepare_for_load;
7476
7477                         if (prepare_for_load) {
7478                                 AddressOf (ec, AddressOp.LoadStore);
7479                                 ec.ig.Emit (OpCodes.Dup);
7480                                 source.Emit (ec);
7481                                 if (leave_copy) {
7482                                         ec.ig.Emit (OpCodes.Dup);
7483                                         temp = new LocalTemporary (this.type);
7484                                         temp.Store (ec);
7485                                 }
7486                                 StoreFromPtr (ec.ig, t);
7487                                 
7488                                 if (temp != null) {
7489                                         temp.Emit (ec);
7490                                         temp.Release (ec);
7491                                 }
7492                                 
7493                                 return;
7494                         }
7495                         
7496                         LoadArrayAndArguments (ec);
7497
7498                         if (rank == 1) {
7499                                 bool is_stobj, has_type_arg;
7500                                 OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg);
7501                                 //
7502                                 // The stobj opcode used by value types will need
7503                                 // an address on the stack, not really an array/array
7504                                 // pair
7505                                 //
7506                                 if (is_stobj)
7507                                         ig.Emit (OpCodes.Ldelema, t);
7508                                 
7509                                 source.Emit (ec);
7510                                 if (leave_copy) {
7511                                         ec.ig.Emit (OpCodes.Dup);
7512                                         temp = new LocalTemporary (this.type);
7513                                         temp.Store (ec);
7514                                 }
7515                                 
7516                                 if (is_stobj)
7517                                         ig.Emit (OpCodes.Stobj, t);
7518                                 else if (has_type_arg)
7519                                         ig.Emit (op, t);
7520                                 else
7521                                         ig.Emit (op);
7522                         } else {
7523                                 ModuleBuilder mb = CodeGen.Module.Builder;
7524                                 int arg_count = ea.Arguments.Count;
7525                                 Type [] args = new Type [arg_count + 1];
7526                                 MethodInfo set;
7527                                 
7528                                 source.Emit (ec);
7529                                 if (leave_copy) {
7530                                         ec.ig.Emit (OpCodes.Dup);
7531                                         temp = new LocalTemporary (this.type);
7532                                         temp.Store (ec);
7533                                 }
7534                                 
7535                                 for (int i = 0; i < arg_count; i++){
7536                                         //args [i++] = a.Type;
7537                                         args [i] = TypeManager.int32_type;
7538                                 }
7539
7540                                 args [arg_count] = type;
7541                                 
7542                                 set = mb.GetArrayMethod (
7543                                         ea.Expr.Type, "Set",
7544                                         CallingConventions.HasThis |
7545                                         CallingConventions.Standard,
7546                                         TypeManager.void_type, args);
7547                                 
7548                                 ig.Emit (OpCodes.Call, set);
7549                         }
7550                         
7551                         if (temp != null) {
7552                                 temp.Emit (ec);
7553                                 temp.Release (ec);
7554                         }
7555                 }
7556
7557                 public void AddressOf (EmitContext ec, AddressOp mode)
7558                 {
7559                         int rank = ea.Expr.Type.GetArrayRank ();
7560                         ILGenerator ig = ec.ig;
7561
7562                         LoadArrayAndArguments (ec);
7563
7564                         if (rank == 1){
7565                                 ig.Emit (OpCodes.Ldelema, type);
7566                         } else {
7567                                 MethodInfo address = FetchAddressMethod ();
7568                                 ig.Emit (OpCodes.Call, address);
7569                         }
7570                 }
7571
7572                 public void EmitGetLength (EmitContext ec, int dim)
7573                 {
7574                         int rank = ea.Expr.Type.GetArrayRank ();
7575                         ILGenerator ig = ec.ig;
7576
7577                         ea.Expr.Emit (ec);
7578                         if (rank == 1) {
7579                                 ig.Emit (OpCodes.Ldlen);
7580                                 ig.Emit (OpCodes.Conv_I4);
7581                         } else {
7582                                 IntLiteral.EmitInt (ig, dim);
7583                                 ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
7584                         }
7585                 }
7586         }
7587         
7588         class Indexers {
7589                 // note that the ArrayList itself in mutable.  We just can't assign to 'Properties' again.
7590                 public readonly ArrayList Properties;
7591                 static Indexers empty;
7592
7593                 public struct Indexer {
7594                         public readonly PropertyInfo PropertyInfo;
7595                         public readonly MethodInfo Getter, Setter;
7596
7597                         public Indexer (PropertyInfo property_info, MethodInfo get, MethodInfo set)
7598                         {
7599                                 this.PropertyInfo = property_info;
7600                                 this.Getter = get;
7601                                 this.Setter = set;
7602                         }
7603                 }
7604
7605                 static Indexers ()
7606                 {
7607                         empty = new Indexers (null);
7608                 }
7609
7610                 Indexers (ArrayList array)
7611                 {
7612                         Properties = array;
7613                 }
7614
7615                 static void Append (ref Indexers ix, Type caller_type, MemberInfo [] mi)
7616                 {
7617                         bool dummy;
7618                         if (mi == null)
7619                                 return;
7620                         foreach (PropertyInfo property in mi){
7621                                 MethodInfo get, set;
7622                                 
7623                                 get = property.GetGetMethod (true);
7624                                 set = property.GetSetMethod (true);
7625                                 if (get != null && !Expression.IsAccessorAccessible (caller_type, get, out dummy))
7626                                         get = null;
7627                                 if (set != null && !Expression.IsAccessorAccessible (caller_type, set, out dummy))
7628                                         set = null;
7629                                 if (get != null || set != null) {
7630                                         if (ix == empty)
7631                                                 ix = new Indexers (new ArrayList ());
7632                                         ix.Properties.Add (new Indexer (property, get, set));
7633                                 }
7634                         }
7635                 }
7636
7637                 static private MemberInfo [] GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7638                 {
7639                         string p_name = TypeManager.IndexerPropertyName (lookup_type);
7640
7641                         return TypeManager.MemberLookup (
7642                                 caller_type, caller_type, lookup_type, MemberTypes.Property,
7643                                 BindingFlags.Public | BindingFlags.Instance |
7644                                 BindingFlags.DeclaredOnly, p_name, null);
7645                 }
7646                 
7647                 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type) 
7648                 {
7649                         Indexers ix = empty;
7650
7651 #if GMCS_SOURCE
7652                         if (lookup_type.IsGenericParameter) {
7653                                 GenericConstraints gc = TypeManager.GetTypeParameterConstraints (lookup_type);
7654                                 if (gc == null)
7655                                         return empty;
7656
7657                                 if (gc.HasClassConstraint)
7658                                         Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, gc.ClassConstraint));
7659
7660                                 Type[] ifaces = gc.InterfaceConstraints;
7661                                 foreach (Type itype in ifaces)
7662                                         Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7663
7664                                 return ix;
7665                         }
7666 #endif
7667
7668                         Type copy = lookup_type;
7669                         while (copy != TypeManager.object_type && copy != null){
7670                                 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, copy));
7671                                 copy = copy.BaseType;
7672                         }
7673
7674                         if (lookup_type.IsInterface) {
7675                                 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7676                                 if (ifaces != null) {
7677                                         foreach (Type itype in ifaces)
7678                                                 Append (ref ix, caller_type, GetIndexersForTypeOrInterface (caller_type, itype));
7679                                 }
7680                         }
7681
7682                         return ix;
7683                 }
7684         }
7685
7686         /// <summary>
7687         ///   Expressions that represent an indexer call.
7688         /// </summary>
7689         public class IndexerAccess : Expression, IAssignMethod {
7690                 //
7691                 // Points to our "data" repository
7692                 //
7693                 MethodInfo get, set;
7694                 ArrayList set_arguments;
7695                 bool is_base_indexer;
7696
7697                 protected Type indexer_type;
7698                 protected Type current_type;
7699                 protected Expression instance_expr;
7700                 protected ArrayList arguments;
7701                 
7702                 public IndexerAccess (ElementAccess ea, Location loc)
7703                         : this (ea.Expr, false, loc)
7704                 {
7705                         this.arguments = ea.Arguments;
7706                 }
7707
7708                 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7709                                          Location loc)
7710                 {
7711                         this.instance_expr = instance_expr;
7712                         this.is_base_indexer = is_base_indexer;
7713                         this.eclass = ExprClass.Value;
7714                         this.loc = loc;
7715                 }
7716
7717                 protected virtual bool CommonResolve (EmitContext ec)
7718                 {
7719                         indexer_type = instance_expr.Type;
7720                         current_type = ec.ContainerType;
7721
7722                         return true;
7723                 }
7724
7725                 public override Expression DoResolve (EmitContext ec)
7726                 {
7727                         if (!CommonResolve (ec))
7728                                 return null;
7729
7730                         //
7731                         // Step 1: Query for all `Item' *properties*.  Notice
7732                         // that the actual methods are pointed from here.
7733                         //
7734                         // This is a group of properties, piles of them.  
7735
7736                         ArrayList AllGetters = null;
7737
7738                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7739                         if (ilist.Properties != null) {
7740                                 AllGetters = new ArrayList(ilist.Properties.Count);
7741                                 foreach (Indexers.Indexer ix in ilist.Properties) {
7742                                         if (ix.Getter != null)
7743                                                 AllGetters.Add (ix.Getter);
7744                                 }
7745                         }
7746
7747                         if (AllGetters == null) {
7748                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7749                                         TypeManager.CSharpName (indexer_type));
7750                                 return null;
7751                         }
7752
7753                         if (AllGetters.Count == 0) {
7754                                 // FIXME: we cannot simply select first one as the error message is missleading when
7755                                 // multiple indexers exist
7756                                 Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
7757                                 Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
7758                                         TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
7759                                 return null;
7760                         }
7761
7762                         get = (MethodInfo)new MethodGroupExpr (AllGetters, loc).OverloadResolve (ec,
7763                                         arguments, false, loc);
7764
7765                         if (get == null) {
7766                                 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7767                                 return null;
7768                         }
7769
7770                         //
7771                         // Only base will allow this invocation to happen.
7772                         //
7773                         if (get.IsAbstract && this is BaseIndexerAccess){
7774                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (get));
7775                                 return null;
7776                         }
7777
7778                         type = get.ReturnType;
7779                         if (type.IsPointer && !ec.InUnsafe){
7780                                 UnsafeError (loc);
7781                                 return null;
7782                         }
7783
7784                         instance_expr.CheckMarshalByRefAccess ();
7785                         
7786                         eclass = ExprClass.IndexerAccess;
7787                         return this;
7788                 }
7789
7790                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7791                 {
7792                         if (right_side == EmptyExpression.OutAccess) {
7793                                 Report.Error (206, loc, "A property or indexer `{0}' may not be passed as an out or ref parameter",
7794                                               GetSignatureForError ());
7795                                 return null;
7796                         }
7797
7798                         // if the indexer returns a value type, and we try to set a field in it
7799                         if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
7800                                 Report.Error (1612, loc, "Cannot modify the return value of `{0}' because it is not a variable",
7801                                               GetSignatureForError ());
7802                                 return null;
7803                         }
7804
7805                         ArrayList AllSetters = new ArrayList();
7806                         if (!CommonResolve (ec))
7807                                 return null;
7808
7809                         bool found_any = false, found_any_setters = false;
7810
7811                         Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
7812                         if (ilist.Properties != null) {
7813                                 found_any = true;
7814                                 foreach (Indexers.Indexer ix in ilist.Properties) {
7815                                         if (ix.Setter != null)
7816                                                 AllSetters.Add (ix.Setter);
7817                                 }
7818                         }
7819                         if (AllSetters.Count > 0) {
7820                                 found_any_setters = true;
7821                                 set_arguments = (ArrayList) arguments.Clone ();
7822                                 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7823                                 set = (MethodInfo)(new MethodGroupExpr (AllSetters, loc)).OverloadResolve (
7824                                         ec,
7825                                         set_arguments, false, loc);
7826                         }
7827
7828                         if (!found_any) {
7829                                 Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
7830                                               TypeManager.CSharpName (indexer_type));
7831                                 return null;
7832                         }
7833
7834                         if (!found_any_setters) {
7835                                 Error (154, "indexer can not be used in this context, because " +
7836                                        "it lacks a `set' accessor");
7837                                 return null;
7838                         }
7839
7840                         if (set == null) {
7841                                 Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
7842                                 return null;
7843                         }
7844
7845                         //
7846                         // Only base will allow this invocation to happen.
7847                         //
7848                         if (set.IsAbstract && this is BaseIndexerAccess){
7849                                 Error_CannotCallAbstractBase (TypeManager.CSharpSignature (set));
7850                                 return null;
7851                         }
7852
7853                         //
7854                         // Now look for the actual match in the list of indexers to set our "return" type
7855                         //
7856                         type = TypeManager.void_type;   // default value
7857                         foreach (Indexers.Indexer ix in ilist.Properties){
7858                                 if (ix.Setter == set){
7859                                         type = ix.PropertyInfo.PropertyType;
7860                                         break;
7861                                 }
7862                         }
7863
7864                         instance_expr.CheckMarshalByRefAccess ();
7865
7866                         eclass = ExprClass.IndexerAccess;
7867                         return this;
7868                 }
7869                 
7870                 bool prepared = false;
7871                 LocalTemporary temp;
7872                 
7873                 public void Emit (EmitContext ec, bool leave_copy)
7874                 {
7875                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false);
7876                         if (leave_copy) {
7877                                 ec.ig.Emit (OpCodes.Dup);
7878                                 temp = new LocalTemporary (Type);
7879                                 temp.Store (ec);
7880                         }
7881                 }
7882                 
7883                 //
7884                 // source is ignored, because we already have a copy of it from the
7885                 // LValue resolution and we have already constructed a pre-cached
7886                 // version of the arguments (ea.set_arguments);
7887                 //
7888                 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
7889                 {
7890                         prepared = prepare_for_load;
7891                         Argument a = (Argument) set_arguments [set_arguments.Count - 1];
7892                         
7893                         if (prepared) {
7894                                 source.Emit (ec);
7895                                 if (leave_copy) {
7896                                         ec.ig.Emit (OpCodes.Dup);
7897                                         temp = new LocalTemporary (Type);
7898                                         temp.Store (ec);
7899                                 }
7900                         } else if (leave_copy) {
7901                                 temp = new LocalTemporary (Type);
7902                                 source.Emit (ec);
7903                                 temp.Store (ec);
7904                                 a.Expr = temp;
7905                         }
7906                         
7907                         Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
7908                         
7909                         if (temp != null) {
7910                                 temp.Emit (ec);
7911                                 temp.Release (ec);
7912                         }
7913                 }
7914                 
7915                 
7916                 public override void Emit (EmitContext ec)
7917                 {
7918                         Emit (ec, false);
7919                 }
7920
7921                 public override string GetSignatureForError ()
7922                 {
7923                         // FIXME: print the argument list of the indexer
7924                         return instance_expr.GetSignatureForError () + ".this[...]";
7925                 }
7926
7927                 protected override void CloneTo (CloneContext clonectx, Expression t)
7928                 {
7929                         IndexerAccess target = (IndexerAccess) t;
7930
7931                         if (arguments != null){
7932                                 target.arguments = new ArrayList ();
7933                                 foreach (Argument a in arguments)
7934                                         target.arguments.Add (a.Clone (clonectx));
7935                         }
7936                         if (instance_expr != null)
7937                                 target.instance_expr = instance_expr.Clone (clonectx);
7938                 }
7939         }
7940
7941         /// <summary>
7942         ///   The base operator for method names
7943         /// </summary>
7944         public class BaseAccess : Expression {
7945                 public readonly string Identifier;
7946                 TypeArguments args;
7947
7948                 public BaseAccess (string member, Location l)
7949                 {
7950                         this.Identifier = member;
7951                         loc = l;
7952                 }
7953
7954                 public BaseAccess (string member, TypeArguments args, Location l)
7955                         : this (member, l)
7956                 {
7957                         this.args = args;
7958                 }
7959
7960                 public override Expression DoResolve (EmitContext ec)
7961                 {
7962                         Expression c = CommonResolve (ec);
7963
7964                         if (c == null)
7965                                 return null;
7966
7967                         //
7968                         // MethodGroups use this opportunity to flag an error on lacking ()
7969                         //
7970                         if (!(c is MethodGroupExpr))
7971                                 return c.Resolve (ec);
7972                         return c;
7973                 }
7974
7975                 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7976                 {
7977                         Expression c = CommonResolve (ec);
7978
7979                         if (c == null)
7980                                 return null;
7981
7982                         //
7983                         // MethodGroups use this opportunity to flag an error on lacking ()
7984                         //
7985                         if (! (c is MethodGroupExpr))
7986                                 return c.DoResolveLValue (ec, right_side);
7987
7988                         return c;
7989                 }
7990
7991                 Expression CommonResolve (EmitContext ec)
7992                 {
7993                         Expression member_lookup;
7994                         Type current_type = ec.ContainerType;
7995                         Type base_type = current_type.BaseType;
7996
7997                         if (ec.IsStatic){
7998                                 Error (1511, "Keyword `base' is not available in a static method");
7999                                 return null;
8000                         }
8001
8002                         if (ec.IsFieldInitializer){
8003                                 Error (1512, "Keyword `base' is not available in the current context");
8004                                 return null;
8005                         }
8006                         
8007                         member_lookup = MemberLookup (ec.ContainerType, null, base_type, Identifier,
8008                                                       AllMemberTypes, AllBindingFlags, loc);
8009                         if (member_lookup == null) {
8010                                 MemberLookupFailed (ec.ContainerType, base_type, base_type, Identifier, null, true, loc);
8011                                 return null;
8012                         }
8013
8014                         Expression left;
8015                         
8016                         if (ec.IsStatic)
8017                                 left = new TypeExpression (base_type, loc);
8018                         else
8019                                 left = ec.GetThis (loc);
8020
8021                         MemberExpr me = (MemberExpr) member_lookup;
8022                         
8023                         Expression e = me.ResolveMemberAccess (ec, left, loc, null);
8024
8025                         if (e is PropertyExpr) {
8026                                 PropertyExpr pe = (PropertyExpr) e;
8027
8028                                 pe.IsBase = true;
8029                         }
8030
8031                         MethodGroupExpr mg = e as MethodGroupExpr;
8032                         if (mg != null)
8033                                 mg.IsBase = true;
8034
8035                         if (args != null) {
8036                                 if (mg != null)
8037                                         return mg.ResolveGeneric (ec, args);
8038
8039                                 Report.Error (307, loc, "`{0}' cannot be used with type arguments",
8040                                               Identifier);
8041                                 return null;
8042                         }
8043
8044                         return e;
8045                 }
8046
8047                 public override void Emit (EmitContext ec)
8048                 {
8049                         throw new Exception ("Should never be called"); 
8050                 }
8051
8052                 protected override void CloneTo (CloneContext clonectx, Expression t)
8053                 {
8054                         BaseAccess target = (BaseAccess) t;
8055
8056                         target.args = args.Clone ();
8057                 }
8058         }
8059
8060         /// <summary>
8061         ///   The base indexer operator
8062         /// </summary>
8063         public class BaseIndexerAccess : IndexerAccess {
8064                 public BaseIndexerAccess (ArrayList args, Location loc)
8065                         : base (null, true, loc)
8066                 {
8067                         arguments = new ArrayList ();
8068                         foreach (Expression tmp in args)
8069                                 arguments.Add (new Argument (tmp, Argument.AType.Expression));
8070                 }
8071
8072                 protected override bool CommonResolve (EmitContext ec)
8073                 {
8074                         instance_expr = ec.GetThis (loc);
8075
8076                         current_type = ec.ContainerType.BaseType;
8077                         indexer_type = current_type;
8078
8079                         foreach (Argument a in arguments){
8080                                 if (!a.Resolve (ec, loc))
8081                                         return false;
8082                         }
8083
8084                         return true;
8085                 }
8086         }
8087         
8088         /// <summary>
8089         ///   This class exists solely to pass the Type around and to be a dummy
8090         ///   that can be passed to the conversion functions (this is used by
8091         ///   foreach implementation to typecast the object return value from
8092         ///   get_Current into the proper type.  All code has been generated and
8093         ///   we only care about the side effect conversions to be performed
8094         ///
8095         ///   This is also now used as a placeholder where a no-action expression
8096         ///   is needed (the `New' class).
8097         /// </summary>
8098         public class EmptyExpression : Expression {
8099                 public static readonly EmptyExpression Null = new EmptyExpression ();
8100
8101                 public static readonly EmptyExpression OutAccess = new EmptyExpression ();
8102                 public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
8103                 public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
8104
8105                 static EmptyExpression temp = new EmptyExpression ();
8106                 public static EmptyExpression Grab ()
8107                 {
8108                         EmptyExpression retval = temp == null ? new EmptyExpression () : temp;
8109                         temp = null;
8110                         return retval;
8111                 }
8112
8113                 public static void Release (EmptyExpression e)
8114                 {
8115                         temp = e;
8116                 }
8117
8118                 // TODO: should be protected
8119                 public EmptyExpression ()
8120                 {
8121                         type = TypeManager.object_type;
8122                         eclass = ExprClass.Value;
8123                         loc = Location.Null;
8124                 }
8125
8126                 public EmptyExpression (Type t)
8127                 {
8128                         type = t;
8129                         eclass = ExprClass.Value;
8130                         loc = Location.Null;
8131                 }
8132                 
8133                 public override Expression DoResolve (EmitContext ec)
8134                 {
8135                         return this;
8136                 }
8137
8138                 public override void Emit (EmitContext ec)
8139                 {
8140                         // nothing, as we only exist to not do anything.
8141                 }
8142
8143                 //
8144                 // This is just because we might want to reuse this bad boy
8145                 // instead of creating gazillions of EmptyExpressions.
8146                 // (CanImplicitConversion uses it)
8147                 //
8148                 public void SetType (Type t)
8149                 {
8150                         type = t;
8151                 }
8152         }
8153
8154         public class UserCast : Expression {
8155                 MethodBase method;
8156                 Expression source;
8157                 
8158                 public UserCast (MethodInfo method, Expression source, Location l)
8159                 {
8160                         this.method = method;
8161                         this.source = source;
8162                         type = method.ReturnType;
8163                         eclass = ExprClass.Value;
8164                         loc = l;
8165                 }
8166
8167                 public Expression Source {
8168                         get {
8169                                 return source;
8170                         }
8171                 }
8172                         
8173                 public override Expression DoResolve (EmitContext ec)
8174                 {
8175                         //
8176                         // We are born fully resolved
8177                         //
8178                         return this;
8179                 }
8180
8181                 public override void Emit (EmitContext ec)
8182                 {
8183                         ILGenerator ig = ec.ig;
8184
8185                         source.Emit (ec);
8186                         
8187                         if (method is MethodInfo)
8188                                 ig.Emit (OpCodes.Call, (MethodInfo) method);
8189                         else
8190                                 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
8191
8192                 }
8193         }
8194
8195         // <summary>
8196         //   This class is used to "construct" the type during a typecast
8197         //   operation.  Since the Type.GetType class in .NET can parse
8198         //   the type specification, we just use this to construct the type
8199         //   one bit at a time.
8200         // </summary>
8201         public class ComposedCast : TypeExpr {
8202                 Expression left;
8203                 string dim;
8204                 
8205                 public ComposedCast (Expression left, string dim)
8206                         : this (left, dim, left.Location)
8207                 {
8208                 }
8209
8210                 public ComposedCast (Expression left, string dim, Location l)
8211                 {
8212                         this.left = left;
8213                         this.dim = dim;
8214                         loc = l;
8215                 }
8216
8217 #if GMCS_SOURCE
8218                 public Expression RemoveNullable ()
8219                 {
8220                         if (dim.EndsWith ("?")) {
8221                                 dim = dim.Substring (0, dim.Length - 1);
8222                                 if (dim == "")
8223                                         return left;
8224                         }
8225
8226                         return this;
8227                 }
8228 #endif
8229
8230                 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
8231                 {
8232                         TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
8233                         if (lexpr == null)
8234                                 return null;
8235
8236                         Type ltype = lexpr.Type;
8237                         if ((ltype == TypeManager.void_type) && (dim != "*")) {
8238                                 Error_VoidInvalidInTheContext (loc);
8239                                 return null;
8240                         }
8241
8242 #if GMCS_SOURCE
8243                         if ((dim.Length > 0) && (dim [0] == '?')) {
8244                                 TypeExpr nullable = new NullableType (left, loc);
8245                                 if (dim.Length > 1)
8246                                         nullable = new ComposedCast (nullable, dim.Substring (1), loc);
8247                                 return nullable.ResolveAsTypeTerminal (ec, false);
8248                         }
8249 #endif
8250
8251                         if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
8252                                 return null;
8253
8254                         if (dim != "" && dim [0] == '[' &&
8255                             (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
8256                                 Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
8257                                 return null;
8258                         }
8259
8260                         if (dim != "")
8261                                 type = TypeManager.GetConstructedType (ltype, dim);
8262                         else
8263                                 type = ltype;
8264
8265                         if (type == null)
8266                                 throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
8267
8268                         if (type.IsPointer && !ec.IsInUnsafeScope){
8269                                 UnsafeError (loc);
8270                                 return null;
8271                         }
8272
8273                         eclass = ExprClass.Type;
8274                         return this;
8275                 }
8276
8277                 public override string Name {
8278                         get { return left + dim; }
8279                 }
8280
8281                 public override string FullName {
8282                         get { return type.FullName; }
8283                 }
8284
8285                 public override string GetSignatureForError ()
8286                 {
8287                         return left.GetSignatureForError () + dim;
8288                 }
8289
8290                 protected override void CloneTo (CloneContext clonectx, Expression t)
8291                 {
8292                         ComposedCast target = (ComposedCast) t;
8293
8294                         target.left = left.Clone (clonectx);
8295                 }
8296         }
8297
8298         public class FixedBufferPtr : Expression {
8299                 Expression array;
8300
8301                 public FixedBufferPtr (Expression array, Type array_type, Location l)
8302                 {
8303                         this.array = array;
8304                         this.loc = l;
8305
8306                         type = TypeManager.GetPointerType (array_type);
8307                         eclass = ExprClass.Value;
8308                 }
8309
8310                 public override void Emit(EmitContext ec)
8311                 {
8312                         array.Emit (ec);
8313                 }
8314
8315                 public override Expression DoResolve (EmitContext ec)
8316                 {
8317                         //
8318                         // We are born fully resolved
8319                         //
8320                         return this;
8321                 }
8322         }
8323
8324
8325         //
8326         // This class is used to represent the address of an array, used
8327         // only by the Fixed statement, this generates "&a [0]" construct
8328         // for fixed (char *pa = a)
8329         //
8330         public class ArrayPtr : FixedBufferPtr {
8331                 Type array_type;
8332                 
8333                 public ArrayPtr (Expression array, Type array_type, Location l):
8334                         base (array, array_type, l)
8335                 {
8336                         this.array_type = array_type;
8337                 }
8338
8339                 public override void Emit (EmitContext ec)
8340                 {
8341                         base.Emit (ec);
8342                         
8343                         ILGenerator ig = ec.ig;
8344                         IntLiteral.EmitInt (ig, 0);
8345                         ig.Emit (OpCodes.Ldelema, array_type);
8346                 }
8347         }
8348
8349         //
8350         // Used by the fixed statement
8351         //
8352         public class StringPtr : Expression {
8353                 LocalBuilder b;
8354                 
8355                 public StringPtr (LocalBuilder b, Location l)
8356                 {
8357                         this.b = b;
8358                         eclass = ExprClass.Value;
8359                         type = TypeManager.char_ptr_type;
8360                         loc = l;
8361                 }
8362
8363                 public override Expression DoResolve (EmitContext ec)
8364                 {
8365                         // This should never be invoked, we are born in fully
8366                         // initialized state.
8367
8368                         return this;
8369                 }
8370
8371                 public override void Emit (EmitContext ec)
8372                 {
8373                         ILGenerator ig = ec.ig;
8374
8375                         ig.Emit (OpCodes.Ldloc, b);
8376                         ig.Emit (OpCodes.Conv_I);
8377                         ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
8378                         ig.Emit (OpCodes.Add);
8379                 }
8380         }
8381         
8382         //
8383         // Implements the `stackalloc' keyword
8384         //
8385         public class StackAlloc : Expression {
8386                 Type otype;
8387                 Expression t;
8388                 Expression count;
8389                 
8390                 public StackAlloc (Expression type, Expression count, Location l)
8391                 {
8392                         t = type;
8393                         this.count = count;
8394                         loc = l;
8395                 }
8396
8397                 public override Expression DoResolve (EmitContext ec)
8398                 {
8399                         count = count.Resolve (ec);
8400                         if (count == null)
8401                                 return null;
8402                         
8403                         if (count.Type != TypeManager.int32_type){
8404                                 count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
8405                                 if (count == null)
8406                                         return null;
8407                         }
8408
8409                         Constant c = count as Constant;
8410                         if (c != null && c.IsNegative) {
8411                                 Report.Error (247, loc, "Cannot use a negative size with stackalloc");
8412                                 return null;
8413                         }
8414
8415                         if (ec.InCatch || ec.InFinally) {
8416                                 Error (255, "Cannot use stackalloc in finally or catch");
8417                                 return null;
8418                         }
8419
8420                         TypeExpr texpr = t.ResolveAsTypeTerminal (ec, false);
8421                         if (texpr == null)
8422                                 return null;
8423
8424                         otype = texpr.Type;
8425
8426                         if (!TypeManager.VerifyUnManaged (otype, loc))
8427                                 return null;
8428
8429                         type = TypeManager.GetPointerType (otype);
8430                         eclass = ExprClass.Value;
8431
8432                         return this;
8433                 }
8434
8435                 public override void Emit (EmitContext ec)
8436                 {
8437                         int size = GetTypeSize (otype);
8438                         ILGenerator ig = ec.ig;
8439                                 
8440                         if (size == 0)
8441                                 ig.Emit (OpCodes.Sizeof, otype);
8442                         else
8443                                 IntConstant.EmitInt (ig, size);
8444                         count.Emit (ec);
8445                         ig.Emit (OpCodes.Mul);
8446                         ig.Emit (OpCodes.Localloc);
8447                 }
8448
8449                 protected override void CloneTo (CloneContext clonectx, Expression t)
8450                 {
8451                         StackAlloc target = (StackAlloc) t;
8452                         target.count = count.Clone (clonectx);
8453                         target.t = t.Clone (clonectx);
8454                 }
8455         }
8456 }