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