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