[mcs] Implements expression bodied members
[mono.git] / mcs / mcs / nullable.cs
1 //
2 // nullable.cs: Nullable types support
3 //
4 // Authors: Martin Baulig (martin@ximian.com)
5 //          Miguel de Icaza (miguel@ximian.com)
6 //          Marek Safar (marek.safar@gmail.com)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 //
10 // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // Copyright 2004-2008 Novell, Inc
12 // Copyright 2011 Xamarin Inc
13 //
14
15 using System;
16 using SLE = System.Linq.Expressions;
17
18 #if STATIC
19 using IKVM.Reflection.Emit;
20 #else
21 using System.Reflection.Emit;
22 #endif
23         
24 namespace Mono.CSharp.Nullable
25 {
26         public class NullableType : TypeExpr
27         {
28                 readonly TypeSpec underlying;
29
30                 public NullableType (TypeSpec type, Location loc)
31                 {
32                         this.underlying = type;
33                         this.loc = loc;
34                 }
35
36                 public override TypeSpec ResolveAsType (IMemberContext ec)
37                 {
38                         eclass = ExprClass.Type;
39
40                         var otype = ec.Module.PredefinedTypes.Nullable.Resolve ();
41                         if (otype == null)
42                                 return null;
43
44                         TypeArguments args = new TypeArguments (new TypeExpression (underlying, loc));
45                         GenericTypeExpr ctype = new GenericTypeExpr (otype, args, loc);
46                         
47                         type = ctype.ResolveAsType (ec);
48                         return type;
49                 }
50         }
51
52         static class NullableInfo
53         {
54                 public static MethodSpec GetConstructor (TypeSpec nullableType)
55                 {
56                         return (MethodSpec) MemberCache.FindMember (nullableType,
57                                 MemberFilter.Constructor (ParametersCompiled.CreateFullyResolved (GetUnderlyingType (nullableType))), BindingRestriction.DeclaredOnly);
58                 }
59
60                 public static MethodSpec GetHasValue (TypeSpec nullableType)
61                 {
62                         return (MethodSpec) MemberCache.FindMember (nullableType,
63                                 MemberFilter.Method ("get_HasValue", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.None);
64                 }
65
66                 public static MethodSpec GetGetValueOrDefault (TypeSpec nullableType)
67                 {
68                         return (MethodSpec) MemberCache.FindMember (nullableType,
69                                 MemberFilter.Method ("GetValueOrDefault", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.None);
70                 }
71
72                 //
73                 // Don't use unless really required for correctness, see Unwrap::Emit
74                 //
75                 public static MethodSpec GetValue (TypeSpec nullableType)
76                 {
77                         return (MethodSpec) MemberCache.FindMember (nullableType,
78                                 MemberFilter.Method ("get_Value", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.None);
79                 }
80
81                 public static TypeSpec GetUnderlyingType (TypeSpec nullableType)
82                 {
83                         return ((InflatedTypeSpec) nullableType).TypeArguments[0];
84                 }
85
86                 public static TypeSpec GetEnumUnderlyingType (ModuleContainer module, TypeSpec nullableEnum)
87                 {
88                         return module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (module,
89                                 new[] { EnumSpec.GetUnderlyingType (GetUnderlyingType (nullableEnum)) });
90                 }
91         }
92
93         public class Unwrap : Expression, IMemoryLocation
94         {
95                 Expression expr;
96
97                 LocalTemporary temp;
98                 Expression temp_field;
99                 readonly bool useDefaultValue;
100
101                 public Unwrap (Expression expr, bool useDefaultValue = true)
102                 {
103                         this.expr = expr;
104                         this.loc = expr.Location;
105                         this.useDefaultValue = useDefaultValue;
106
107                         type = NullableInfo.GetUnderlyingType (expr.Type);
108                         eclass = expr.eclass;
109                 }
110
111                 public override bool ContainsEmitWithAwait ()
112                 {
113                         return expr.ContainsEmitWithAwait ();
114                 }
115
116                 // TODO: REMOVE
117                 public static Expression Create (Expression expr)
118                 {
119                         //
120                         // Avoid unwraping and wraping of same type
121                         //
122                         Wrap wrap = expr as Wrap;
123                         if (wrap != null)
124                                 return wrap.Child;
125
126                         return Create (expr, false);
127                 }
128
129                 public static Expression CreateUnwrapped (Expression expr)
130                 {
131                         //
132                         // Avoid unwraping and wraping of same type
133                         //
134                         Wrap wrap = expr as Wrap;
135                         if (wrap != null)
136                                 return wrap.Child;
137
138                         return Create (expr, true);
139                 }
140
141                 public static Unwrap Create (Expression expr, bool useDefaultValue)
142                 {
143                         return new Unwrap (expr, useDefaultValue);
144                 }
145                 
146                 public override Expression CreateExpressionTree (ResolveContext ec)
147                 {
148                         return expr.CreateExpressionTree (ec);
149                 }
150
151                 protected override Expression DoResolve (ResolveContext ec)
152                 {
153                         return this;
154                 }
155
156                 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
157                 {
158                         expr = expr.DoResolveLValue (ec, right_side);
159                         return this;
160                 }
161
162                 public override void Emit (EmitContext ec)
163                 {
164                         Store (ec);
165
166                         var call = new CallEmitter ();
167                         call.InstanceExpression = this;
168
169                         //
170                         // Using GetGetValueOrDefault is prefered because JIT can possibly
171                         // inline it whereas Value property contains a throw which is very
172                         // unlikely to be inlined
173                         //
174                         if (useDefaultValue)
175                                 call.EmitPredefined (ec, NullableInfo.GetGetValueOrDefault (expr.Type), null);
176                         else
177                                 call.EmitPredefined (ec, NullableInfo.GetValue (expr.Type), null);
178                 }
179
180                 public void EmitCheck (EmitContext ec)
181                 {
182                         Store (ec);
183
184                         var call = new CallEmitter ();
185                         call.InstanceExpression = this;
186
187                         call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null);
188                 }
189
190                 public override void EmitSideEffect (EmitContext ec)
191                 {
192                         expr.EmitSideEffect (ec);
193                 }
194
195                 public override Expression EmitToField (EmitContext ec)
196                 {
197                         if (temp_field == null)
198                                 temp_field = this.expr.EmitToField (ec);
199                         
200                         return this;
201                 }
202
203                 public override bool Equals (object obj)
204                 {
205                         Unwrap uw = obj as Unwrap;
206                         return uw != null && expr.Equals (uw.expr);
207                 }
208
209                 public override void FlowAnalysis (FlowAnalysisContext fc)
210                 {
211                         expr.FlowAnalysis (fc);
212                 }
213
214                 public Expression Original {
215                         get {
216                                 return expr;
217                         }
218                 }
219                 
220                 public override int GetHashCode ()
221                 {
222                         return expr.GetHashCode ();
223                 }
224
225                 public override bool IsNull {
226                         get {
227                                 return expr.IsNull;
228                         }
229                 }
230
231                 public void Store (EmitContext ec)
232                 {
233                         if (temp != null || temp_field != null)
234                                 return;
235
236                         if (expr is VariableReference)
237                                 return;
238
239                         expr.Emit (ec);
240                         LocalVariable.Store (ec);
241                 }
242
243                 public void Load (EmitContext ec)
244                 {
245                         if (temp_field != null)
246                                 temp_field.Emit (ec);
247                         else if (expr is VariableReference)
248                                 expr.Emit (ec);
249                         else
250                                 LocalVariable.Emit (ec);
251                 }
252
253                 public override SLE.Expression MakeExpression (BuilderContext ctx)
254                 {
255                         return expr.MakeExpression (ctx);
256                 }
257
258                 public void AddressOf (EmitContext ec, AddressOp mode)
259                 {
260                         IMemoryLocation ml;
261
262                         if (temp_field != null) {
263                                 ml = temp_field as IMemoryLocation;
264                                 if (ml == null) {
265                                         var lt = new LocalTemporary (temp_field.Type);
266                                         temp_field.Emit (ec);
267                                         lt.Store (ec);
268                                         ml = lt;
269                                 }
270                         } else {
271                                 ml = expr as VariableReference;
272                         }
273
274                         if (ml != null)
275                                 ml.AddressOf (ec, mode);
276                         else
277                                 LocalVariable.AddressOf (ec, mode);
278                 }
279
280                 //
281                 // Keeps result of non-variable expression
282                 //
283                 LocalTemporary LocalVariable {
284                         get {
285                                 if (temp == null && temp_field == null)
286                                         temp = new LocalTemporary (expr.Type);
287                                 return temp;
288                         }
289                 }
290         }
291
292         //
293         // Calls get_Value method on nullable expression
294         //
295         public class UnwrapCall : CompositeExpression
296         {
297                 public UnwrapCall (Expression expr)
298                         : base (expr)
299                 {
300                 }
301
302                 protected override Expression DoResolve (ResolveContext rc)
303                 {
304                         base.DoResolve (rc);
305
306                         if (type != null)
307                                 type = NullableInfo.GetUnderlyingType (type);
308
309                         return this;
310                 }
311
312                 public override void Emit (EmitContext ec)
313                 {
314                         var call = new CallEmitter ();
315                         call.InstanceExpression = Child;
316                         call.EmitPredefined (ec, NullableInfo.GetValue (Child.Type), null);
317                 }
318         }
319
320         public class Wrap : TypeCast
321         {
322                 private Wrap (Expression expr, TypeSpec type)
323                         : base (expr, type)
324                 {
325                         eclass = ExprClass.Value;
326                 }
327
328                 public override Expression CreateExpressionTree (ResolveContext ec)
329                 {
330                         TypeCast child_cast = child as TypeCast;
331                         if (child_cast != null) {
332                                 child.Type = type;
333                                 return child_cast.CreateExpressionTree (ec);
334                         }
335
336                         var user_cast = child as UserCast;
337                         if (user_cast != null) {
338                                 child.Type = type;
339                                 return user_cast.CreateExpressionTree (ec);
340                         }
341
342                         return base.CreateExpressionTree (ec);
343                 }
344
345                 public static Expression Create (Expression expr, TypeSpec type)
346                 {
347                         //
348                         // Avoid unwraping and wraping of the same type
349                         //
350                         Unwrap unwrap = expr as Unwrap;
351                         if (unwrap != null && expr.Type == NullableInfo.GetUnderlyingType (type))
352                                 return unwrap.Original;
353                 
354                         return new Wrap (expr, type);
355                 }
356                 
357                 public override void Emit (EmitContext ec)
358                 {
359                         child.Emit (ec);
360                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
361                 }
362         }
363
364         //
365         // Represents null literal lifted to nullable type
366         //
367         public class LiftedNull : NullConstant, IMemoryLocation
368         {
369                 private LiftedNull (TypeSpec nullable_type, Location loc)
370                         : base (nullable_type, loc)
371                 {
372                         eclass = ExprClass.Value;
373                 }
374
375                 public static Constant Create (TypeSpec nullable, Location loc)
376                 {
377                         return new LiftedNull (nullable, loc);
378                 }
379
380                 public static Constant CreateFromExpression (ResolveContext rc, Expression e)
381                 {
382                         if (!rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
383                                 rc.Report.Warning (458, 2, e.Location, "The result of the expression is always `null' of type `{0}'",
384                                         e.Type.GetSignatureForError ());
385                         }
386
387                         return ReducedExpression.Create (Create (e.Type, e.Location), e);
388                 }
389
390                 public override void Emit (EmitContext ec)
391                 {
392                         // TODO: generate less temporary variables
393                         LocalTemporary value_target = new LocalTemporary (type);
394
395                         value_target.AddressOf (ec, AddressOp.Store);
396                         ec.Emit (OpCodes.Initobj, type);
397                         value_target.Emit (ec);
398                         value_target.Release (ec);
399                 }
400
401                 public void AddressOf (EmitContext ec, AddressOp Mode)
402                 {
403                         LocalTemporary value_target = new LocalTemporary (type);
404                                 
405                         value_target.AddressOf (ec, AddressOp.Store);
406                         ec.Emit (OpCodes.Initobj, type);
407                         value_target.AddressOf (ec, Mode);
408                 }
409         }
410
411         //
412         // Generic lifting expression, supports all S/S? -> T/T? cases
413         //
414         public class LiftedConversion : Expression, IMemoryLocation
415         {
416                 Expression expr, null_value;
417                 Unwrap unwrap;
418
419                 public LiftedConversion (Expression expr, Unwrap unwrap, TypeSpec type)
420                 {
421                         this.expr = expr;
422                         this.unwrap = unwrap;
423                         this.loc = expr.Location;
424                         this.type = type;
425                 }
426
427                 public LiftedConversion (Expression expr, Expression unwrap, TypeSpec type)
428                         : this (expr, unwrap as Unwrap, type)
429                 {
430                 }
431
432                 public override bool ContainsEmitWithAwait ()
433                 {
434                         return unwrap.ContainsEmitWithAwait ();
435                 }
436                 
437                 public override Expression CreateExpressionTree (ResolveContext ec)
438                 {
439                         return expr.CreateExpressionTree (ec);
440                 }                       
441
442                 protected override Expression DoResolve (ResolveContext ec)
443                 {
444                         //
445                         // It's null when lifting non-nullable type
446                         //
447                         if (unwrap == null) {
448                                 // S -> T? is wrap only
449                                 if (type.IsNullableType)
450                                         return Wrap.Create (expr, type);
451
452                                 // S -> T can be simplified
453                                 return expr;
454                         }
455
456                         // Wrap target for T?
457                         if (type.IsNullableType) {
458                                 if (!expr.Type.IsNullableType) {
459                                         expr = Wrap.Create (expr, type);
460                                         if (expr == null)
461                                                 return null;
462                                 }
463
464                                 null_value = LiftedNull.Create (type, loc);
465                         } else if (TypeSpec.IsValueType (type)) {
466                                 null_value = LiftedNull.Create (type, loc);
467                         } else {
468                                 null_value = new NullConstant (type, loc);
469                         }
470
471                         eclass = ExprClass.Value;
472                         return this;
473                 }
474
475                 public override void Emit (EmitContext ec)
476                 {
477                         Label is_null_label = ec.DefineLabel ();
478                         Label end_label = ec.DefineLabel ();
479
480                         unwrap.EmitCheck (ec);
481                         ec.Emit (OpCodes.Brfalse, is_null_label);
482
483                         expr.Emit (ec);
484
485                         ec.Emit (OpCodes.Br, end_label);
486                         ec.MarkLabel (is_null_label);
487
488                         null_value.Emit (ec);
489
490                         ec.MarkLabel (end_label);
491                 }
492
493                 public override void FlowAnalysis (FlowAnalysisContext fc)
494                 {
495                         expr.FlowAnalysis (fc);
496                 }
497
498                 public void AddressOf (EmitContext ec, AddressOp mode)
499                 {
500                         unwrap.AddressOf (ec, mode);
501                 }
502         }
503
504         public class LiftedUnaryOperator : Unary, IMemoryLocation
505         {
506                 Unwrap unwrap;
507                 Expression user_operator;
508
509                 public LiftedUnaryOperator (Unary.Operator op, Expression expr, Location loc)
510                         : base (op, expr, loc)
511                 {
512                 }
513
514                 public void AddressOf (EmitContext ec, AddressOp mode)
515                 {
516                         unwrap.AddressOf (ec, mode);
517                 }
518
519                 public override Expression CreateExpressionTree (ResolveContext ec)
520                 {
521                         if (user_operator != null)
522                                 return user_operator.CreateExpressionTree (ec);
523
524                         if (Oper == Operator.UnaryPlus)
525                                 return Expr.CreateExpressionTree (ec);
526
527                         return base.CreateExpressionTree (ec);
528                 }
529
530                 protected override Expression DoResolve (ResolveContext ec)
531                 {
532                         unwrap = Unwrap.Create (Expr, false);
533                         if (unwrap == null)
534                                 return null;
535
536                         Expression res = base.ResolveOperator (ec, unwrap);
537                         if (res == null) {
538                                 Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
539                                 return null;
540                         }
541
542                         if (res != this) {
543                                 if (user_operator == null)
544                                         return res;
545                         } else {
546                                 res = Expr = LiftExpression (ec, Expr);
547                         }
548
549                         if (res == null)
550                                 return null;
551
552                         eclass = ExprClass.Value;
553                         type = res.Type;
554                         return this;
555                 }
556
557                 public override void Emit (EmitContext ec)
558                 {
559                         Label is_null_label = ec.DefineLabel ();
560                         Label end_label = ec.DefineLabel ();
561
562                         unwrap.EmitCheck (ec);
563                         ec.Emit (OpCodes.Brfalse, is_null_label);
564
565                         if (user_operator != null) {
566                                 user_operator.Emit (ec);
567                         } else {
568                                 EmitOperator (ec, NullableInfo.GetUnderlyingType (type));
569                         }
570
571                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
572                         ec.Emit (OpCodes.Br_S, end_label);
573
574                         ec.MarkLabel (is_null_label);
575                         LiftedNull.Create (type, loc).Emit (ec);
576
577                         ec.MarkLabel (end_label);
578                 }
579
580                 static Expression LiftExpression (ResolveContext ec, Expression expr)
581                 {
582                         var lifted_type = new NullableType (expr.Type, expr.Location);
583                         if (lifted_type.ResolveAsType (ec) == null)
584                                 return null;
585
586                         expr.Type = lifted_type.Type;
587                         return expr;
588                 }
589
590                 protected override Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
591                 {
592                         expr = base.ResolveEnumOperator (ec, expr, predefined);
593                         if (expr == null)
594                                 return null;
595
596                         Expr = LiftExpression (ec, Expr);
597                         return LiftExpression (ec, expr);
598                 }
599
600                 protected override Expression ResolveUserOperator (ResolveContext ec, Expression expr)
601                 {
602                         expr = base.ResolveUserOperator (ec, expr);
603                         if (expr == null)
604                                 return null;
605
606                         //
607                         // When a user operator is of non-nullable type
608                         //
609                         if (Expr is Unwrap) {
610                                 user_operator = LiftExpression (ec, expr);
611                                 return user_operator;
612                         }
613
614                         return expr;
615                 }
616         }
617
618         //
619         // Lifted version of binary operators
620         //
621         class LiftedBinaryOperator : Expression
622         {
623                 public LiftedBinaryOperator (Binary b)
624                 {
625                         this.Binary = b;
626                         this.loc = b.Location;
627                 }
628
629                 public Binary Binary { get; private set; }
630
631                 public Expression Left { get; set; }
632
633                 public Expression Right { get; set; }
634
635                 public Unwrap UnwrapLeft { get; set; }
636
637                 public Unwrap UnwrapRight { get; set; }
638
639                 public MethodSpec UserOperator { get; set; }
640
641                 bool IsBitwiseBoolean {
642                         get {
643                                 return (Binary.Oper == Binary.Operator.BitwiseAnd || Binary.Oper == Binary.Operator.BitwiseOr) &&
644                                 ((UnwrapLeft != null && UnwrapLeft.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) ||
645                                  (UnwrapRight != null && UnwrapRight.Type.BuiltinType == BuiltinTypeSpec.Type.Bool));
646                         }
647                 }
648
649                 public override bool ContainsEmitWithAwait ()
650                 {
651                         return Left.ContainsEmitWithAwait () || Right.ContainsEmitWithAwait ();
652                 }
653
654                 public override Expression CreateExpressionTree (ResolveContext rc)
655                 {
656                         if (UserOperator != null) {
657                                 Arguments args = new Arguments (2);
658                                 args.Add (new Argument (Binary.Left));
659                                 args.Add (new Argument (Binary.Right));
660
661                                 var method = new UserOperatorCall (UserOperator, args, Binary.CreateExpressionTree, loc);
662                                 return method.CreateExpressionTree (rc);
663                         }
664
665                         return Binary.CreateExpressionTree (rc);
666                 }
667
668                 protected override Expression DoResolve (ResolveContext rc)
669                 {
670                         if (rc.IsRuntimeBinder) {
671                                 if (UnwrapLeft == null && !Left.Type.IsNullableType)
672                                         Left = LiftOperand (rc, Left);
673
674                                 if (UnwrapRight == null && !Right.Type.IsNullableType)
675                                         Right = LiftOperand (rc, Right);
676                         } else {
677                                 if (UnwrapLeft == null && Left != null && Left.Type.IsNullableType) {
678                                         Left = Unwrap.CreateUnwrapped (Left);
679                                         UnwrapLeft = Left as Unwrap;
680                                 }
681
682                                 if (UnwrapRight == null && Right != null && Right.Type.IsNullableType) {
683                                         Right = Unwrap.CreateUnwrapped (Right);
684                                         UnwrapRight = Right as Unwrap;
685                                 }
686                         }
687
688                         type = Binary.Type;
689                         eclass = Binary.eclass; 
690
691                         return this;
692                 }
693
694                 Expression LiftOperand (ResolveContext rc, Expression expr)
695                 {
696                         TypeSpec type;
697                         if (expr.IsNull) {
698                                 type = Left.IsNull ? Right.Type : Left.Type;
699                         } else {
700                                 type = expr.Type;
701                         }
702
703                         if (!type.IsNullableType)
704                                 type = rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { type });
705
706                         return Wrap.Create (expr, type);
707                 }
708
709                 public override void Emit (EmitContext ec)
710                 {
711                         if (IsBitwiseBoolean && UserOperator == null) {
712                                 EmitBitwiseBoolean (ec);
713                                 return;
714                         }
715
716                         if ((Binary.Oper & Binary.Operator.EqualityMask) != 0) {
717                                 EmitEquality (ec);
718                                 return;
719                         }
720
721                         Label is_null_label = ec.DefineLabel ();
722                         Label end_label = ec.DefineLabel ();
723
724                         if (ec.HasSet (BuilderContext.Options.AsyncBody) && Right.ContainsEmitWithAwait ()) {
725                                 Left = Left.EmitToField (ec);
726                                 Right = Right.EmitToField (ec);
727                         }
728
729                         if (UnwrapLeft != null) {
730                                 UnwrapLeft.EmitCheck (ec);
731                         }
732
733                         //
734                         // Don't emit HasValue check when left and right expressions are same
735                         //
736                         if (UnwrapRight != null && !Binary.Left.Equals (Binary.Right)) {
737                                 UnwrapRight.EmitCheck (ec);
738                                 if (UnwrapLeft != null) {
739                                         ec.Emit (OpCodes.And);
740                                 }
741                         }
742
743                         ec.Emit (OpCodes.Brfalse, is_null_label);
744
745                         if (UserOperator != null) {
746                                 var args = new Arguments (2);
747                                 args.Add (new Argument (Left));
748                                 args.Add (new Argument (Right));
749
750                                 var call = new CallEmitter ();
751                                 call.EmitPredefined (ec, UserOperator, args);
752                         } else {
753                                 Binary.EmitOperator (ec, Left, Right);
754                         }
755
756                         //
757                         // Wrap the result when the operator return type is nullable type
758                         //
759                         if (type.IsNullableType)
760                                 ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
761
762                         ec.Emit (OpCodes.Br_S, end_label);
763                         ec.MarkLabel (is_null_label);
764
765                         if ((Binary.Oper & Binary.Operator.ComparisonMask) != 0) {
766                                 ec.EmitInt (0);
767                         } else {
768                                 LiftedNull.Create (type, loc).Emit (ec);
769                         }
770
771                         ec.MarkLabel (end_label);
772                 }
773
774                 void EmitBitwiseBoolean (EmitContext ec)
775                 {
776                         Label load_left = ec.DefineLabel ();
777                         Label load_right = ec.DefineLabel ();
778                         Label end_label = ec.DefineLabel ();
779                         Label is_null_label = ec.DefineLabel ();
780
781                         bool or = Binary.Oper == Binary.Operator.BitwiseOr;
782
783                         //
784                         // Both operands are bool? types
785                         //
786                         if (UnwrapLeft != null && UnwrapRight != null) {
787                                 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Binary.Right.ContainsEmitWithAwait ()) {
788                                         Left = Left.EmitToField (ec);
789                                         Right = Right.EmitToField (ec);
790                                 } else {
791                                         UnwrapLeft.Store (ec);
792                                         UnwrapRight.Store (ec);
793                                 }
794
795                                 Left.Emit (ec);
796                                 ec.Emit (OpCodes.Brtrue_S, load_right);
797
798                                 Right.Emit (ec);
799                                 ec.Emit (OpCodes.Brtrue_S, load_left);
800
801                                 UnwrapLeft.EmitCheck (ec);
802                                 ec.Emit (OpCodes.Brfalse_S, load_right);
803
804                                 // load left
805                                 ec.MarkLabel (load_left);
806                                 if (or)
807                                         UnwrapRight.Load (ec);
808                                 else
809                                         UnwrapLeft.Load (ec);
810
811                                 ec.Emit (OpCodes.Br_S, end_label);
812
813                                 // load right
814                                 ec.MarkLabel (load_right);
815                                 if (or)
816                                         UnwrapLeft.Load (ec);
817                                 else
818                                         UnwrapRight.Load (ec);
819
820                                 ec.MarkLabel (end_label);
821                                 return;
822                         }
823
824                         //
825                         // Faster version when one operand is bool
826                         //
827                         if (UnwrapLeft == null) {
828                                 //
829                                 // (bool, bool?)
830                                 //
831                                 // Optimizes remaining (false & bool?), (true | bool?) which are not easy to handle
832                                 // in binary expression reduction
833                                 //
834                                 var c = Left as BoolConstant;
835                                 if (c != null) {
836                                         // Keep evaluation order
837                                         UnwrapRight.Store (ec);
838
839                                         ec.EmitInt (or ? 1 : 0);
840                                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
841                                 } else if (Left.IsNull) {
842                                         UnwrapRight.Emit (ec);
843                                         ec.Emit (or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, is_null_label);
844
845                                         UnwrapRight.Load (ec);
846                                         ec.Emit (OpCodes.Br_S, end_label);
847
848                                         ec.MarkLabel (is_null_label);
849                                         LiftedNull.Create (type, loc).Emit (ec);
850                                 } else {
851                                         Left.Emit (ec);
852                                         ec.Emit (or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, load_right);
853
854                                         ec.EmitInt (or ? 1 : 0);
855                                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
856
857                                         ec.Emit (OpCodes.Br_S, end_label);
858
859                                         ec.MarkLabel (load_right);
860                                         UnwrapRight.Original.Emit (ec);
861                                 }
862                         } else {
863                                 //
864                                 // (bool?, bool)
865                                 //
866                                 // Keep left-right evaluation order
867                                 UnwrapLeft.Store (ec);
868
869                                 //
870                                 // Optimizes remaining (bool? & false), (bool? | true) which are not easy to handle
871                                 // in binary expression reduction
872                                 //
873                                 var c = Right as BoolConstant;
874                                 if (c != null) {
875                                         ec.EmitInt (or ? 1 : 0);
876                                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
877                                 } else if (Right.IsNull) {
878                                         UnwrapLeft.Emit (ec);
879                                         ec.Emit (or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, is_null_label);
880
881                                         UnwrapLeft.Load (ec);
882                                         ec.Emit (OpCodes.Br_S, end_label);
883
884                                         ec.MarkLabel (is_null_label);
885                                         LiftedNull.Create (type, loc).Emit (ec);
886                                 } else {
887                                         Right.Emit (ec);
888                                         ec.Emit (or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, load_right);
889
890                                         ec.EmitInt (or ? 1 : 0);
891                                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
892
893                                         ec.Emit (OpCodes.Br_S, end_label);
894
895                                         ec.MarkLabel (load_right);
896
897                                         UnwrapLeft.Load (ec);
898                                 }
899                         }
900
901                         ec.MarkLabel (end_label);
902                 }
903
904                 //
905                 // Emits optimized equality or inequality operator when possible
906                 //
907                 void EmitEquality (EmitContext ec)
908                 {
909                         //
910                         // Either left or right is null
911                         // 
912                         if (UnwrapLeft != null && Binary.Right.IsNull) { // TODO: Optimize for EmitBranchable
913                                 //
914                                 // left.HasValue == false 
915                                 //
916                                 UnwrapLeft.EmitCheck (ec);
917                                 if (Binary.Oper == Binary.Operator.Equality) {
918                                         ec.EmitInt (0);
919                                         ec.Emit (OpCodes.Ceq);
920                                 }
921                                 return;
922                         }
923
924                         if (UnwrapRight != null && Binary.Left.IsNull) {
925                                 //
926                                 // right.HasValue == false 
927                                 //
928                                 UnwrapRight.EmitCheck (ec);
929                                 if (Binary.Oper == Binary.Operator.Equality) {
930                                         ec.EmitInt (0);
931                                         ec.Emit (OpCodes.Ceq);
932                                 }
933                                 return;
934                         }
935
936                         Label dissimilar_label = ec.DefineLabel ();
937                         Label end_label = ec.DefineLabel ();
938
939                         if (UserOperator != null) {
940                                 var left = Left;
941
942                                 if (UnwrapLeft != null) {
943                                         UnwrapLeft.EmitCheck (ec);
944                                 } else {
945                                         // Keep evaluation order same
946                                         if (!(Left is VariableReference)) {
947                                                 Left.Emit (ec);
948                                                 var lt = new LocalTemporary (Left.Type);
949                                                 lt.Store (ec);
950                                                 left = lt;
951                                         }
952                                 }
953
954                                 if (UnwrapRight != null) {
955                                         UnwrapRight.EmitCheck (ec);
956
957                                         if (UnwrapLeft != null) {
958                                                 ec.Emit (OpCodes.Bne_Un, dissimilar_label);
959
960                                                 Label compare_label = ec.DefineLabel ();
961                                                 UnwrapLeft.EmitCheck (ec);
962                                                 ec.Emit (OpCodes.Brtrue, compare_label);
963
964                                                 if (Binary.Oper == Binary.Operator.Equality)
965                                                         ec.EmitInt (1);
966                                                 else
967                                                         ec.EmitInt (0);
968
969                                                 ec.Emit (OpCodes.Br, end_label);
970
971                                                 ec.MarkLabel (compare_label);
972                                         } else {
973                                                 ec.Emit (OpCodes.Brfalse, dissimilar_label);
974                                         }
975                                 } else {
976                                         ec.Emit (OpCodes.Brfalse, dissimilar_label);
977                                 }
978
979                                 var args = new Arguments (2);
980                                 args.Add (new Argument (left));
981                                 args.Add (new Argument (Right));
982
983                                 var call = new CallEmitter ();
984                                 call.EmitPredefined (ec, UserOperator, args);
985                         } else {
986                                 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Binary.Right.ContainsEmitWithAwait ()) {
987                                         Left = Left.EmitToField (ec);
988                                         Right = Right.EmitToField (ec);
989                                 }
990
991                                 //
992                                 // Emit underlying value comparison first.
993                                 //
994                                 // For this code: int? a = 1; bool b = a == 1;
995                                 //
996                                 // We emit something similar to this. Expressions with side effects have local
997                                 // variable created by Unwrap expression
998                                 //
999                                 //      left.GetValueOrDefault ()
1000                                 //      right
1001                                 //      bne.un.s   dissimilar_label
1002                                 //  left.HasValue
1003                                 //      br.s       end_label
1004                                 // dissimilar_label:
1005                                 //      ldc.i4.0
1006                                 // end_label:
1007                                 //
1008
1009                                 Left.Emit (ec);
1010                                 Right.Emit (ec);
1011
1012                                 ec.Emit (OpCodes.Bne_Un_S, dissimilar_label);
1013
1014                                 //
1015                                 // Check both left and right expressions for Unwrap call in which
1016                                 // case we need to run get_HasValue() check because the type is
1017                                 // nullable and could have null value
1018                                 //
1019                                 if (UnwrapLeft != null)
1020                                         UnwrapLeft.EmitCheck (ec);
1021
1022                                 if (UnwrapRight != null)
1023                                         UnwrapRight.EmitCheck (ec);
1024
1025                                 if (UnwrapLeft != null && UnwrapRight != null) {
1026                                         if (Binary.Oper == Binary.Operator.Inequality)
1027                                                 ec.Emit (OpCodes.Xor);
1028                                         else
1029                                                 ec.Emit (OpCodes.Ceq);
1030                                 } else {
1031                                         if (Binary.Oper == Binary.Operator.Inequality) {
1032                                                 ec.EmitInt (0);
1033                                                 ec.Emit (OpCodes.Ceq);
1034                                         }
1035                                 }
1036                         }
1037
1038                         ec.Emit (OpCodes.Br_S, end_label);
1039
1040                         ec.MarkLabel (dissimilar_label);
1041                         if (Binary.Oper == Binary.Operator.Inequality)
1042                                 ec.EmitInt (1);
1043                         else
1044                                 ec.EmitInt (0);
1045
1046                         ec.MarkLabel (end_label);
1047                 }
1048
1049                 public override void FlowAnalysis (FlowAnalysisContext fc)
1050                 {
1051                         Binary.FlowAnalysis (fc);
1052                 }
1053
1054                 public override SLE.Expression MakeExpression (BuilderContext ctx)
1055                 {
1056                         return Binary.MakeExpression (ctx, Left, Right);
1057                 }
1058         }
1059
1060         public class NullCoalescingOperator : Expression
1061         {
1062                 Expression left, right;
1063                 Unwrap unwrap;
1064
1065                 public NullCoalescingOperator (Expression left, Expression right)
1066                 {
1067                         this.left = left;
1068                         this.right = right;
1069                         this.loc = left.Location;
1070                 }
1071
1072                 public Expression LeftExpression {
1073                         get {
1074                                 return left;
1075                         }
1076                 }
1077
1078                 public Expression RightExpression {
1079                         get {
1080                                 return right;
1081                         }
1082                 }
1083                 
1084                 public override Expression CreateExpressionTree (ResolveContext ec)
1085                 {
1086                         if (left is NullLiteral)
1087                                 ec.Report.Error (845, loc, "An expression tree cannot contain a coalescing operator with null left side");
1088
1089                         UserCast uc = left as UserCast;
1090                         Expression conversion = null;
1091                         if (uc != null) {
1092                                 left = uc.Source;
1093
1094                                 Arguments c_args = new Arguments (2);
1095                                 c_args.Add (new Argument (uc.CreateExpressionTree (ec)));
1096                                 c_args.Add (new Argument (left.CreateExpressionTree (ec)));
1097                                 conversion = CreateExpressionFactoryCall (ec, "Lambda", c_args);
1098                         }
1099
1100                         Arguments args = new Arguments (3);
1101                         args.Add (new Argument (left.CreateExpressionTree (ec)));
1102                         args.Add (new Argument (right.CreateExpressionTree (ec)));
1103                         if (conversion != null)
1104                                 args.Add (new Argument (conversion));
1105                         
1106                         return CreateExpressionFactoryCall (ec, "Coalesce", args);
1107                 }
1108
1109                 Expression ConvertExpression (ResolveContext ec)
1110                 {
1111                         // TODO: ImplicitConversionExists should take care of this
1112                         if (left.eclass == ExprClass.MethodGroup)
1113                                 return null;
1114
1115                         TypeSpec ltype = left.Type;
1116
1117                         //
1118                         // If left is a nullable type and an implicit conversion exists from right to underlying type of left,
1119                         // the result is underlying type of left
1120                         //
1121                         if (ltype.IsNullableType) {
1122                                 unwrap = Unwrap.Create (left, false);
1123                                 if (unwrap == null)
1124                                         return null;
1125
1126                                 //
1127                                 // Reduce (left ?? null) to left
1128                                 //
1129                                 if (right.IsNull)
1130                                         return ReducedExpression.Create (left, this);
1131
1132                                 if (Convert.ImplicitConversionExists (ec, right, unwrap.Type)) {
1133                                         left = unwrap;
1134                                         ltype = left.Type;
1135
1136                                         //
1137                                         // If right is a dynamic expression, the result type is dynamic
1138                                         //
1139                                         if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1140                                                 type = right.Type;
1141
1142                                                 // Need to box underlying value type
1143                                                 left = Convert.ImplicitBoxingConversion (left, ltype, type);
1144                                                 return this;
1145                                         }
1146
1147                                         right = Convert.ImplicitConversion (ec, right, ltype, loc);
1148                                         type = ltype;
1149                                         return this;
1150                                 }
1151                         } else if (TypeSpec.IsReferenceType (ltype)) {
1152                                 if (Convert.ImplicitConversionExists (ec, right, ltype)) {
1153                                         //
1154                                         // If right is a dynamic expression, the result type is dynamic
1155                                         //
1156                                         if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1157                                                 type = right.Type;
1158                                                 return this;
1159                                         }
1160
1161                                         //
1162                                         // Reduce ("foo" ?? expr) to expression
1163                                         //
1164                                         Constant lc = left as Constant;
1165                                         if (lc != null && !lc.IsDefaultValue)
1166                                                 return ReducedExpression.Create (lc, this, false);
1167
1168                                         //
1169                                         // Reduce (left ?? null) to left OR (null-constant ?? right) to right
1170                                         //
1171                                         if (right.IsNull || lc != null) {
1172                                                 //
1173                                                 // Special case null ?? null
1174                                                 //
1175                                                 if (right.IsNull && ltype == right.Type)
1176                                                         return null;
1177
1178                                                 return ReducedExpression.Create (lc != null ? right : left, this, false);
1179                                         }
1180
1181                                         right = Convert.ImplicitConversion (ec, right, ltype, loc);
1182                                         type = ltype;
1183                                         return this;
1184                                 }
1185                         } else {
1186                                 return null;
1187                         }
1188
1189                         TypeSpec rtype = right.Type;
1190                         if (!Convert.ImplicitConversionExists (ec, unwrap ?? left, rtype) || right.eclass == ExprClass.MethodGroup)
1191                                 return null;
1192
1193                         //
1194                         // Reduce (null ?? right) to right
1195                         //
1196                         if (left.IsNull)
1197                                 return ReducedExpression.Create (right, this, false).Resolve (ec);
1198
1199                         left = Convert.ImplicitConversion (ec, unwrap ?? left, rtype, loc);
1200                         type = rtype;
1201                         return this;
1202                 }
1203
1204                 public override bool ContainsEmitWithAwait ()
1205                 {
1206                         if (unwrap != null)
1207                                 return unwrap.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
1208
1209                         return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
1210                 }
1211
1212                 protected override Expression DoResolve (ResolveContext ec)
1213                 {
1214                         left = left.Resolve (ec);
1215                         right = right.Resolve (ec);
1216
1217                         if (left == null || right == null)
1218                                 return null;
1219
1220                         eclass = ExprClass.Value;
1221
1222                         Expression e = ConvertExpression (ec);
1223                         if (e == null) {
1224                                 Binary.Error_OperatorCannotBeApplied (ec, left, right, "??", loc);
1225                                 return null;
1226                         }
1227
1228                         return e;
1229                 }
1230
1231                 public override void Emit (EmitContext ec)
1232                 {
1233                         Label end_label = ec.DefineLabel ();
1234
1235                         if (unwrap != null) {
1236                                 Label is_null_label = ec.DefineLabel ();
1237
1238                                 unwrap.EmitCheck (ec);
1239                                 ec.Emit (OpCodes.Brfalse, is_null_label);
1240
1241                                 //
1242                                 // When both expressions are nullable the unwrap
1243                                 // is needed only for null check not for value uwrap
1244                                 //
1245                                 if (type.IsNullableType && TypeSpecComparer.IsEqual (NullableInfo.GetUnderlyingType (type), unwrap.Type))
1246                                         unwrap.Load (ec);
1247                                 else
1248                                         left.Emit (ec);
1249
1250                                 ec.Emit (OpCodes.Br, end_label);
1251
1252                                 ec.MarkLabel (is_null_label);
1253                                 right.Emit (ec);
1254
1255                                 ec.MarkLabel (end_label);
1256                                 return;
1257                         }
1258
1259                         left.Emit (ec);
1260                         ec.Emit (OpCodes.Dup);
1261
1262                         // Only to make verifier happy
1263                         if (left.Type.IsGenericParameter)
1264                                 ec.Emit (OpCodes.Box, left.Type);
1265
1266                         ec.Emit (OpCodes.Brtrue, end_label);
1267
1268                         ec.Emit (OpCodes.Pop);
1269                         right.Emit (ec);
1270
1271                         ec.MarkLabel (end_label);
1272                 }
1273
1274                 public override void FlowAnalysis (FlowAnalysisContext fc)
1275                 {
1276                         left.FlowAnalysis (fc);
1277                         var left_da = fc.BranchDefiniteAssignment ();
1278                         right.FlowAnalysis (fc);
1279                         fc.DefiniteAssignment = left_da;
1280                 }
1281
1282                 protected override void CloneTo (CloneContext clonectx, Expression t)
1283                 {
1284                         NullCoalescingOperator target = (NullCoalescingOperator) t;
1285
1286                         target.left = left.Clone (clonectx);
1287                         target.right = right.Clone (clonectx);
1288                 }
1289                 
1290                 public override object Accept (StructuralVisitor visitor)
1291                 {
1292                         return visitor.Visit (this);
1293                 }
1294         }
1295
1296         class LiftedUnaryMutator : UnaryMutator
1297         {
1298                 public LiftedUnaryMutator (Mode mode, Expression expr, Location loc)
1299                         : base (mode, expr, loc)
1300                 {
1301                 }
1302
1303                 protected override Expression DoResolve (ResolveContext ec)
1304                 {
1305                         var orig_expr = expr;
1306
1307                         expr = Unwrap.Create (expr);
1308
1309                         var res = base.DoResolveOperation (ec);
1310
1311                         expr = orig_expr;
1312                         type = expr.Type;
1313
1314                         return res;
1315                 }
1316
1317                 protected override void EmitOperation (EmitContext ec)
1318                 {
1319                         Label is_null_label = ec.DefineLabel ();
1320                         Label end_label = ec.DefineLabel ();
1321
1322                         LocalTemporary lt = new LocalTemporary (type);
1323
1324                         // Value is on the stack
1325                         lt.Store (ec);
1326
1327                         var call = new CallEmitter ();
1328                         call.InstanceExpression = lt;
1329                         call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null);
1330
1331                         ec.Emit (OpCodes.Brfalse, is_null_label);
1332
1333                         call = new CallEmitter ();
1334                         call.InstanceExpression = lt;
1335                         call.EmitPredefined (ec, NullableInfo.GetGetValueOrDefault (expr.Type), null);
1336
1337                         lt.Release (ec);
1338
1339                         base.EmitOperation (ec);
1340
1341                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
1342                         ec.Emit (OpCodes.Br_S, end_label);
1343
1344                         ec.MarkLabel (is_null_label);
1345                         LiftedNull.Create (type, loc).Emit (ec);
1346
1347                         ec.MarkLabel (end_label);
1348                 }
1349         }
1350 }
1351