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