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