Rewrite lifted binary operators to match C# spec more closely. Fixes #12608 and about...
[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 Expression EmitToField (EmitContext ec)
191                 {
192                         if (temp_field == null)
193                                 temp_field = this.expr.EmitToField (ec);
194                         
195                         return this;
196                 }
197
198                 public override bool Equals (object obj)
199                 {
200                         Unwrap uw = obj as Unwrap;
201                         return uw != null && expr.Equals (uw.expr);
202                 }
203
204                 public Expression Original {
205                         get {
206                                 return expr;
207                         }
208                 }
209                 
210                 public override int GetHashCode ()
211                 {
212                         return expr.GetHashCode ();
213                 }
214
215                 public override bool IsNull {
216                         get {
217                                 return expr.IsNull;
218                         }
219                 }
220
221                 public void Store (EmitContext ec)
222                 {
223                         if (temp != null || temp_field != null)
224                                 return;
225
226                         if (expr is VariableReference)
227                                 return;
228
229                         expr.Emit (ec);
230                         LocalVariable.Store (ec);
231                 }
232
233                 public void Load (EmitContext ec)
234                 {
235                         if (temp_field != null)
236                                 temp_field.Emit (ec);
237                         else if (expr is VariableReference)
238                                 expr.Emit (ec);
239                         else
240                                 LocalVariable.Emit (ec);
241                 }
242
243                 public override SLE.Expression MakeExpression (BuilderContext ctx)
244                 {
245                         return expr.MakeExpression (ctx);
246                 }
247
248                 public void AddressOf (EmitContext ec, AddressOp mode)
249                 {
250                         IMemoryLocation ml;
251
252                         if (temp_field != null) {
253                                 ml = temp_field as IMemoryLocation;
254                                 if (ml == null) {
255                                         var lt = new LocalTemporary (temp_field.Type);
256                                         temp_field.Emit (ec);
257                                         lt.Store (ec);
258                                         ml = lt;
259                                 }
260                         } else {
261                                 ml = expr as VariableReference;
262                         }
263
264                         if (ml != null)
265                                 ml.AddressOf (ec, mode);
266                         else
267                                 LocalVariable.AddressOf (ec, mode);
268                 }
269
270                 //
271                 // Keeps result of non-variable expression
272                 //
273                 LocalTemporary LocalVariable {
274                         get {
275                                 if (temp == null && temp_field == null)
276                                         temp = new LocalTemporary (expr.Type);
277                                 return temp;
278                         }
279                 }
280         }
281
282         //
283         // Calls get_Value method on nullable expression
284         //
285         public class UnwrapCall : CompositeExpression
286         {
287                 public UnwrapCall (Expression expr)
288                         : base (expr)
289                 {
290                 }
291
292                 protected override Expression DoResolve (ResolveContext rc)
293                 {
294                         base.DoResolve (rc);
295
296                         if (type != null)
297                                 type = NullableInfo.GetUnderlyingType (type);
298
299                         return this;
300                 }
301
302                 public override void Emit (EmitContext ec)
303                 {
304                         var call = new CallEmitter ();
305                         call.InstanceExpression = Child;
306                         call.EmitPredefined (ec, NullableInfo.GetValue (Child.Type), null);
307                 }
308         }
309
310         public class Wrap : TypeCast
311         {
312                 private Wrap (Expression expr, TypeSpec type)
313                         : base (expr, type)
314                 {
315                         eclass = ExprClass.Value;
316                 }
317
318                 public override Expression CreateExpressionTree (ResolveContext ec)
319                 {
320                         TypeCast child_cast = child as TypeCast;
321                         if (child_cast != null) {
322                                 child.Type = type;
323                                 return child_cast.CreateExpressionTree (ec);
324                         }
325
326                         var user_cast = child as UserCast;
327                         if (user_cast != null) {
328                                 child.Type = type;
329                                 return user_cast.CreateExpressionTree (ec);
330                         }
331
332                         return base.CreateExpressionTree (ec);
333                 }
334
335                 public static Expression Create (Expression expr, TypeSpec type)
336                 {
337                         //
338                         // Avoid unwraping and wraping of the same type
339                         //
340                         Unwrap unwrap = expr as Unwrap;
341                         if (unwrap != null && expr.Type == NullableInfo.GetUnderlyingType (type))
342                                 return unwrap.Original;
343                 
344                         return new Wrap (expr, type);
345                 }
346                 
347                 public override void Emit (EmitContext ec)
348                 {
349                         child.Emit (ec);
350                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
351                 }
352         }
353
354         //
355         // Represents null literal lifted to nullable type
356         //
357         public class LiftedNull : NullConstant, IMemoryLocation
358         {
359                 private LiftedNull (TypeSpec nullable_type, Location loc)
360                         : base (nullable_type, loc)
361                 {
362                         eclass = ExprClass.Value;
363                 }
364
365                 public static Constant Create (TypeSpec nullable, Location loc)
366                 {
367                         return new LiftedNull (nullable, loc);
368                 }
369
370                 public static Constant CreateFromExpression (ResolveContext rc, Expression e)
371                 {
372                         if (!rc.HasSet (ResolveContext.Options.ExpressionTreeConversion)) {
373                                 rc.Report.Warning (458, 2, e.Location, "The result of the expression is always `null' of type `{0}'",
374                                         e.Type.GetSignatureForError ());
375                         }
376
377                         return ReducedExpression.Create (Create (e.Type, e.Location), e);
378                 }
379
380                 public override void Emit (EmitContext ec)
381                 {
382                         // TODO: generate less temporary variables
383                         LocalTemporary value_target = new LocalTemporary (type);
384
385                         value_target.AddressOf (ec, AddressOp.Store);
386                         ec.Emit (OpCodes.Initobj, type);
387                         value_target.Emit (ec);
388                         value_target.Release (ec);
389                 }
390
391                 public void AddressOf (EmitContext ec, AddressOp Mode)
392                 {
393                         LocalTemporary value_target = new LocalTemporary (type);
394                                 
395                         value_target.AddressOf (ec, AddressOp.Store);
396                         ec.Emit (OpCodes.Initobj, type);
397                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
398                 }
399         }
400
401         //
402         // Generic lifting expression, supports all S/S? -> T/T? cases
403         //
404         public class Lifted : Expression, IMemoryLocation
405         {
406                 Expression expr, null_value;
407                 Unwrap unwrap;
408
409                 public Lifted (Expression expr, Unwrap unwrap, TypeSpec type)
410                 {
411                         this.expr = expr;
412                         this.unwrap = unwrap;
413                         this.loc = expr.Location;
414                         this.type = type;
415                 }
416
417                 public Lifted (Expression expr, Expression unwrap, TypeSpec type)
418                         : this (expr, unwrap as Unwrap, type)
419                 {
420                 }
421
422                 public override bool ContainsEmitWithAwait ()
423                 {
424                         return unwrap.ContainsEmitWithAwait ();
425                 }
426                 
427                 public override Expression CreateExpressionTree (ResolveContext ec)
428                 {
429                         return expr.CreateExpressionTree (ec);
430                 }                       
431
432                 protected override Expression DoResolve (ResolveContext ec)
433                 {
434                         //
435                         // It's null when lifting non-nullable type
436                         //
437                         if (unwrap == null) {
438                                 // S -> T? is wrap only
439                                 if (type.IsNullableType)
440                                         return Wrap.Create (expr, type);
441
442                                 // S -> T can be simplified
443                                 return expr;
444                         }
445
446                         // Wrap target for T?
447                         if (type.IsNullableType) {
448                                 expr = Wrap.Create (expr, type);
449                                 if (expr == null)
450                                         return null;
451
452                                 null_value = LiftedNull.Create (type, loc);
453                         } else if (TypeSpec.IsValueType (type)) {
454                                 null_value = LiftedNull.Create (type, loc);
455                         } else {
456                                 null_value = new NullConstant (type, loc);
457                         }
458
459                         eclass = ExprClass.Value;
460                         return this;
461                 }
462
463                 public override void Emit (EmitContext ec)
464                 {
465                         Label is_null_label = ec.DefineLabel ();
466                         Label end_label = ec.DefineLabel ();
467
468                         unwrap.EmitCheck (ec);
469                         ec.Emit (OpCodes.Brfalse, is_null_label);
470
471                         expr.Emit (ec);
472
473                         ec.Emit (OpCodes.Br, end_label);
474                         ec.MarkLabel (is_null_label);
475
476                         null_value.Emit (ec);
477                         ec.MarkLabel (end_label);
478                 }
479
480                 public void AddressOf (EmitContext ec, AddressOp mode)
481                 {
482                         unwrap.AddressOf (ec, mode);
483                 }
484         }
485
486         public class LiftedUnaryOperator : Unary, IMemoryLocation
487         {
488                 Unwrap unwrap;
489                 Expression user_operator;
490
491                 public LiftedUnaryOperator (Unary.Operator op, Expression expr, Location loc)
492                         : base (op, expr, loc)
493                 {
494                 }
495
496                 public void AddressOf (EmitContext ec, AddressOp mode)
497                 {
498                         unwrap.AddressOf (ec, mode);
499                 }
500
501                 public override Expression CreateExpressionTree (ResolveContext ec)
502                 {
503                         if (user_operator != null)
504                                 return user_operator.CreateExpressionTree (ec);
505
506                         if (Oper == Operator.UnaryPlus)
507                                 return Expr.CreateExpressionTree (ec);
508
509                         return base.CreateExpressionTree (ec);
510                 }
511
512                 protected override Expression DoResolve (ResolveContext ec)
513                 {
514                         unwrap = Unwrap.Create (Expr, false);
515                         if (unwrap == null)
516                                 return null;
517
518                         Expression res = base.ResolveOperator (ec, unwrap);
519                         if (res != this) {
520                                 if (user_operator == null)
521                                         return res;
522                         } else {
523                                 res = Expr = LiftExpression (ec, Expr);
524                         }
525
526                         if (res == null)
527                                 return null;
528
529                         eclass = ExprClass.Value;
530                         type = res.Type;
531                         return this;
532                 }
533
534                 public override void Emit (EmitContext ec)
535                 {
536                         Label is_null_label = ec.DefineLabel ();
537                         Label end_label = ec.DefineLabel ();
538
539                         unwrap.EmitCheck (ec);
540                         ec.Emit (OpCodes.Brfalse, is_null_label);
541
542                         if (user_operator != null) {
543                                 user_operator.Emit (ec);
544                         } else {
545                                 EmitOperator (ec, NullableInfo.GetUnderlyingType (type));
546                         }
547
548                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
549                         ec.Emit (OpCodes.Br_S, end_label);
550
551                         ec.MarkLabel (is_null_label);
552                         LiftedNull.Create (type, loc).Emit (ec);
553
554                         ec.MarkLabel (end_label);
555                 }
556
557                 static Expression LiftExpression (ResolveContext ec, Expression expr)
558                 {
559                         var lifted_type = new NullableType (expr.Type, expr.Location);
560                         if (lifted_type.ResolveAsType (ec) == null)
561                                 return null;
562
563                         expr.Type = lifted_type.Type;
564                         return expr;
565                 }
566
567                 protected override Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
568                 {
569                         expr = base.ResolveEnumOperator (ec, expr, predefined);
570                         if (expr == null)
571                                 return null;
572
573                         Expr = LiftExpression (ec, Expr);
574                         return LiftExpression (ec, expr);
575                 }
576
577                 protected override Expression ResolveUserOperator (ResolveContext ec, Expression expr)
578                 {
579                         expr = base.ResolveUserOperator (ec, expr);
580                         if (expr == null)
581                                 return null;
582
583                         //
584                         // When a user operator is of non-nullable type
585                         //
586                         if (Expr is Unwrap) {
587                                 user_operator = LiftExpression (ec, expr);
588                                 return user_operator;
589                         }
590
591                         return expr;
592                 }
593         }
594
595         //
596         // Lifted version of binary operators
597         //
598         class LiftedBinaryOperator : Expression
599         {
600                 public LiftedBinaryOperator (Binary b)
601                 {
602                         this.Binary = b;
603                         this.loc = b.Location;
604                 }
605
606                 public Binary Binary { get; private set; }
607
608                 public Expression Left { get; set; }
609
610                 public Expression Right { get; set; }
611
612                 public Unwrap UnwrapLeft { get; set; }
613
614                 public Unwrap UnwrapRight { get; set; }
615
616                 public MethodSpec UserOperator { get; set; }
617
618                 bool IsBitwiseBoolean {
619                         get {
620                                 return (Binary.Oper == Binary.Operator.BitwiseAnd || Binary.Oper == Binary.Operator.BitwiseOr) &&
621                                 ((UnwrapLeft != null && UnwrapLeft.Type.BuiltinType == BuiltinTypeSpec.Type.Bool) ||
622                                  (UnwrapRight != null && UnwrapRight.Type.BuiltinType == BuiltinTypeSpec.Type.Bool));
623                         }
624                 }
625
626                 public override bool ContainsEmitWithAwait ()
627                 {
628                         return Left.ContainsEmitWithAwait () || Right.ContainsEmitWithAwait ();
629                 }
630
631                 public override Expression CreateExpressionTree (ResolveContext rc)
632                 {
633                         if (UserOperator != null) {
634                                 Arguments args = new Arguments (2);
635                                 args.Add (new Argument (Binary.Left));
636                                 args.Add (new Argument (Binary.Right));
637
638                                 var method = new UserOperatorCall (UserOperator, args, Binary.CreateExpressionTree, loc);
639                                 return method.CreateExpressionTree (rc);
640                         }
641
642                         return Binary.CreateExpressionTree (rc);
643                 }
644
645                 protected override Expression DoResolve (ResolveContext rc)
646                 {
647                         if (rc.IsRuntimeBinder) {
648                                 if (UnwrapLeft == null && !Left.Type.IsNullableType)
649                                         Left = Wrap.Create (Left, rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { Left.Type }));
650
651                                 if (UnwrapRight == null && !Right.Type.IsNullableType)
652                                         Right = Wrap.Create (Right, rc.Module.PredefinedTypes.Nullable.TypeSpec.MakeGenericType (rc.Module, new[] { Right.Type }));
653                         } else {
654                                 if (UnwrapLeft == null && Left != null && Left.Type.IsNullableType) {
655                                         Left = Unwrap.CreateUnwrapped (Left);
656                                         UnwrapLeft = Left as Unwrap;
657                                 }
658
659                                 if (UnwrapRight == null && Right != null && Right.Type.IsNullableType) {
660                                         Right = Unwrap.CreateUnwrapped (Right);
661                                         UnwrapRight = Right as Unwrap;
662                                 }
663                         }
664
665                         type = Binary.Type;
666                         eclass = Binary.eclass; 
667
668                         return this;
669                 }
670
671                 public override void Emit (EmitContext ec)
672                 {
673                         if (IsBitwiseBoolean && UserOperator == null) {
674                                 EmitBitwiseBoolean (ec);
675                                 return;
676                         }
677
678                         if ((Binary.Oper & Binary.Operator.EqualityMask) != 0) {
679                                 EmitEquality (ec);
680                                 return;
681                         }
682
683                         Label is_null_label = ec.DefineLabel ();
684                         Label end_label = ec.DefineLabel ();
685
686                         if (ec.HasSet (BuilderContext.Options.AsyncBody) && Right.ContainsEmitWithAwait ()) {
687                                 Left = Left.EmitToField (ec);
688                                 Right = Right.EmitToField (ec);
689                         }
690
691                         if (UnwrapLeft != null) {
692                                 UnwrapLeft.EmitCheck (ec);
693                         }
694
695                         //
696                         // Don't emit HasValue check when left and right expressions are same
697                         //
698                         if (UnwrapRight != null && !Binary.Left.Equals (Binary.Right)) {
699                                 UnwrapRight.EmitCheck (ec);
700                                 if (UnwrapLeft != null) {
701                                         ec.Emit (OpCodes.And);
702                                 }
703                         }
704
705                         ec.Emit (OpCodes.Brfalse, is_null_label);
706
707                         if (UserOperator != null) {
708                                 var args = new Arguments (2);
709                                 args.Add (new Argument (Left));
710                                 args.Add (new Argument (Right));
711
712                                 var call = new CallEmitter ();
713                                 call.EmitPredefined (ec, UserOperator, args);
714                         } else {
715                                 Binary.EmitOperator (ec, Left, Right);
716                         }
717
718                         //
719                         // Wrap the result when the operator return type is nullable type
720                         //
721                         if (type.IsNullableType)
722                                 ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
723
724                         ec.Emit (OpCodes.Br_S, end_label);
725                         ec.MarkLabel (is_null_label);
726
727                         if ((Binary.Oper & Binary.Operator.ComparisonMask) != 0) {
728                                 ec.EmitInt (0);
729                         } else {
730                                 LiftedNull.Create (type, loc).Emit (ec);
731                         }
732
733                         ec.MarkLabel (end_label);
734                 }
735
736                 void EmitBitwiseBoolean (EmitContext ec)
737                 {
738                         Label load_left = ec.DefineLabel ();
739                         Label load_right = ec.DefineLabel ();
740                         Label end_label = ec.DefineLabel ();
741                         Label is_null_label = ec.DefineLabel ();
742
743                         bool or = Binary.Oper == Binary.Operator.BitwiseOr;
744
745                         //
746                         // Both operands are bool? types
747                         //
748                         if (UnwrapLeft != null && UnwrapRight != null) {
749                                 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Binary.Right.ContainsEmitWithAwait ()) {
750                                         Left = Left.EmitToField (ec);
751                                         Right = Right.EmitToField (ec);
752                                 }
753
754                                 Left.Emit (ec);
755                                 ec.Emit (OpCodes.Brtrue_S, load_right);
756
757                                 Right.Emit (ec);
758                                 ec.Emit (OpCodes.Brtrue_S, load_left);
759
760                                 UnwrapLeft.EmitCheck (ec);
761                                 ec.Emit (OpCodes.Brfalse_S, load_right);
762
763                                 // load left
764                                 ec.MarkLabel (load_left);
765                                 if (or)
766                                         UnwrapRight.Load (ec);
767                                 else
768                                         UnwrapLeft.Load (ec);
769
770                                 ec.Emit (OpCodes.Br_S, end_label);
771
772                                 // load right
773                                 ec.MarkLabel (load_right);
774                                 if (or)
775                                         UnwrapLeft.Load (ec);
776                                 else
777                                         UnwrapRight.Load (ec);
778
779                                 ec.MarkLabel (end_label);
780                                 return;
781                         }
782
783                         //
784                         // Faster version when one operand is bool
785                         //
786                         if (UnwrapLeft == null) {
787                                 //
788                                 // (bool, bool?)
789                                 //
790                                 // Optimizes remaining (false & bool?), (true | bool?) which are not easy to handle
791                                 // in binary expression reduction
792                                 //
793                                 var c = Left as BoolConstant;
794                                 if (c != null) {
795                                         // Keep evaluation order
796                                         UnwrapRight.Store (ec);
797
798                                         ec.EmitInt (or ? 1 : 0);
799                                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
800                                 } else if (Left.IsNull) {
801                                         UnwrapRight.Emit (ec);
802                                         ec.Emit (or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, is_null_label);
803
804                                         UnwrapRight.Load (ec);
805                                         ec.Emit (OpCodes.Br_S, end_label);
806
807                                         ec.MarkLabel (is_null_label);
808                                         LiftedNull.Create (type, loc).Emit (ec);
809                                 } else {
810                                         Left.Emit (ec);
811                                         ec.Emit (or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, load_right);
812
813                                         ec.EmitInt (or ? 1 : 0);
814                                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
815
816                                         ec.Emit (OpCodes.Br_S, end_label);
817
818                                         ec.MarkLabel (load_right);
819                                         UnwrapRight.Original.Emit (ec);
820                                 }
821                         } else {
822                                 //
823                                 // (bool?, bool)
824                                 //
825                                 // Keep left-right evaluation order
826                                 UnwrapLeft.Store (ec);
827
828                                 //
829                                 // Optimizes remaining (bool? & false), (bool? | true) which are not easy to handle
830                                 // in binary expression reduction
831                                 //
832                                 var c = Right as BoolConstant;
833                                 if (c != null) {
834                                         ec.EmitInt (or ? 1 : 0);
835                                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
836                                 } else if (Right.IsNull) {
837                                         UnwrapLeft.Emit (ec);
838                                         ec.Emit (or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, is_null_label);
839
840                                         UnwrapLeft.Load (ec);
841                                         ec.Emit (OpCodes.Br_S, end_label);
842
843                                         ec.MarkLabel (is_null_label);
844                                         LiftedNull.Create (type, loc).Emit (ec);
845                                 } else {
846                                         Right.Emit (ec);
847                                         ec.Emit (or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, load_right);
848
849                                         ec.EmitInt (or ? 1 : 0);
850                                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
851
852                                         ec.Emit (OpCodes.Br_S, end_label);
853
854                                         ec.MarkLabel (load_right);
855
856                                         UnwrapLeft.Load (ec);
857                                 }
858                         }
859
860                         ec.MarkLabel (end_label);
861                 }
862
863                 //
864                 // Emits optimized equality or inequality operator when possible
865                 //
866                 void EmitEquality (EmitContext ec)
867                 {
868                         //
869                         // Either left or right is null
870                         // 
871                         if (UnwrapLeft != null && Binary.Right.IsNull) { // TODO: Optimize for EmitBranchable
872                                 //
873                                 // left.HasValue == false 
874                                 //
875                                 UnwrapLeft.EmitCheck (ec);
876                                 if (Binary.Oper == Binary.Operator.Equality) {
877                                         ec.EmitInt (0);
878                                         ec.Emit (OpCodes.Ceq);
879                                 }
880                                 return;
881                         }
882
883                         if (UnwrapRight != null && Binary.Left.IsNull) {
884                                 //
885                                 // right.HasValue == false 
886                                 //
887                                 UnwrapRight.EmitCheck (ec);
888                                 if (Binary.Oper == Binary.Operator.Equality) {
889                                         ec.EmitInt (0);
890                                         ec.Emit (OpCodes.Ceq);
891                                 }
892                                 return;
893                         }
894
895                         Label dissimilar_label = ec.DefineLabel ();
896                         Label end_label = ec.DefineLabel ();
897
898                         if (UserOperator != null) {
899                                 var left = Left;
900
901                                 if (UnwrapLeft != null) {
902                                         UnwrapLeft.EmitCheck (ec);
903                                 } else {
904                                         // Keep evaluation order same
905                                         if (!(Left is VariableReference)) {
906                                                 Left.Emit (ec);
907                                                 var lt = new LocalTemporary (Left.Type);
908                                                 lt.Store (ec);
909                                                 left = lt;
910                                         }
911                                 }
912
913                                 if (UnwrapRight != null) {
914                                         UnwrapRight.EmitCheck (ec);
915
916                                         if (UnwrapLeft != null) {
917                                                 ec.Emit (OpCodes.Bne_Un, dissimilar_label);
918
919                                                 Label compare_label = ec.DefineLabel ();
920                                                 UnwrapLeft.EmitCheck (ec);
921                                                 ec.Emit (OpCodes.Brtrue, compare_label);
922
923                                                 if (Binary.Oper == Binary.Operator.Equality)
924                                                         ec.EmitInt (1);
925                                                 else
926                                                         ec.EmitInt (0);
927
928                                                 ec.Emit (OpCodes.Br, end_label);
929
930                                                 ec.MarkLabel (compare_label);
931                                         } else {
932                                                 ec.Emit (OpCodes.Brfalse, dissimilar_label);
933                                         }
934                                 } else {
935                                         ec.Emit (OpCodes.Brfalse, dissimilar_label);
936                                 }
937
938                                 var args = new Arguments (2);
939                                 args.Add (new Argument (left));
940                                 args.Add (new Argument (Right));
941
942                                 var call = new CallEmitter ();
943                                 call.EmitPredefined (ec, UserOperator, args);
944                         } else {
945                                 if (ec.HasSet (BuilderContext.Options.AsyncBody) && Binary.Right.ContainsEmitWithAwait ()) {
946                                         Left = Left.EmitToField (ec);
947                                         Right = Right.EmitToField (ec);
948                                 }
949
950                                 //
951                                 // Emit underlying value comparison first.
952                                 //
953                                 // For this code: int? a = 1; bool b = a == 1;
954                                 //
955                                 // We emit something similar to this. Expressions with side effects have local
956                                 // variable created by Unwrap expression
957                                 //
958                                 //      left.GetValueOrDefault ()
959                                 //      right
960                                 //      bne.un.s   dissimilar_label
961                                 //  left.HasValue
962                                 //      br.s       end_label
963                                 // dissimilar_label:
964                                 //      ldc.i4.0
965                                 // end_label:
966                                 //
967
968                                 Left.Emit (ec);
969                                 Right.Emit (ec);
970
971                                 ec.Emit (OpCodes.Bne_Un_S, dissimilar_label);
972
973                                 //
974                                 // Check both left and right expressions for Unwrap call in which
975                                 // case we need to run get_HasValue() check because the type is
976                                 // nullable and could have null value
977                                 //
978                                 if (UnwrapLeft != null)
979                                         UnwrapLeft.EmitCheck (ec);
980
981                                 if (UnwrapRight != null)
982                                         UnwrapRight.EmitCheck (ec);
983
984                                 if (UnwrapLeft != null && UnwrapRight != null) {
985                                         if (Binary.Oper == Binary.Operator.Inequality)
986                                                 ec.Emit (OpCodes.Xor);
987                                         else
988                                                 ec.Emit (OpCodes.Ceq);
989                                 } else {
990                                         if (Binary.Oper == Binary.Operator.Inequality) {
991                                                 ec.EmitInt (0);
992                                                 ec.Emit (OpCodes.Ceq);
993                                         }
994                                 }
995                         }
996
997                         ec.Emit (OpCodes.Br_S, end_label);
998
999                         ec.MarkLabel (dissimilar_label);
1000                         if (Binary.Oper == Binary.Operator.Inequality)
1001                                 ec.EmitInt (1);
1002                         else
1003                                 ec.EmitInt (0);
1004
1005                         ec.MarkLabel (end_label);
1006                 }
1007
1008                 public override SLE.Expression MakeExpression (BuilderContext ctx)
1009                 {
1010                         Console.WriteLine (":{0} x {1}", Left.GetType (), Right.GetType ());
1011
1012                         return Binary.MakeExpression (ctx, Left, Right);
1013                 }
1014         }
1015
1016         public class NullCoalescingOperator : Expression
1017         {
1018                 Expression left, right;
1019                 Unwrap unwrap;
1020
1021                 public NullCoalescingOperator (Expression left, Expression right)
1022                 {
1023                         this.left = left;
1024                         this.right = right;
1025                         this.loc = left.Location;
1026                 }
1027
1028                 public Expression LeftExpression {
1029                         get {
1030                                 return left;
1031                         }
1032                 }
1033
1034                 public Expression RightExpression {
1035                         get {
1036                                 return right;
1037                         }
1038                 }
1039                 
1040                 public override Expression CreateExpressionTree (ResolveContext ec)
1041                 {
1042                         if (left is NullLiteral)
1043                                 ec.Report.Error (845, loc, "An expression tree cannot contain a coalescing operator with null left side");
1044
1045                         UserCast uc = left as UserCast;
1046                         Expression conversion = null;
1047                         if (uc != null) {
1048                                 left = uc.Source;
1049
1050                                 Arguments c_args = new Arguments (2);
1051                                 c_args.Add (new Argument (uc.CreateExpressionTree (ec)));
1052                                 c_args.Add (new Argument (left.CreateExpressionTree (ec)));
1053                                 conversion = CreateExpressionFactoryCall (ec, "Lambda", c_args);
1054                         }
1055
1056                         Arguments args = new Arguments (3);
1057                         args.Add (new Argument (left.CreateExpressionTree (ec)));
1058                         args.Add (new Argument (right.CreateExpressionTree (ec)));
1059                         if (conversion != null)
1060                                 args.Add (new Argument (conversion));
1061                         
1062                         return CreateExpressionFactoryCall (ec, "Coalesce", args);
1063                 }
1064
1065                 Expression ConvertExpression (ResolveContext ec)
1066                 {
1067                         // TODO: ImplicitConversionExists should take care of this
1068                         if (left.eclass == ExprClass.MethodGroup)
1069                                 return null;
1070
1071                         TypeSpec ltype = left.Type;
1072
1073                         //
1074                         // If left is a nullable type and an implicit conversion exists from right to underlying type of left,
1075                         // the result is underlying type of left
1076                         //
1077                         if (ltype.IsNullableType) {
1078                                 unwrap = Unwrap.Create (left, false);
1079                                 if (unwrap == null)
1080                                         return null;
1081
1082                                 //
1083                                 // Reduce (left ?? null) to left
1084                                 //
1085                                 if (right.IsNull)
1086                                         return ReducedExpression.Create (left, this);
1087
1088                                 if (Convert.ImplicitConversionExists (ec, right, unwrap.Type)) {
1089                                         left = unwrap;
1090                                         ltype = left.Type;
1091
1092                                         //
1093                                         // If right is a dynamic expression, the result type is dynamic
1094                                         //
1095                                         if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1096                                                 type = right.Type;
1097
1098                                                 // Need to box underlying value type
1099                                                 left = Convert.ImplicitBoxingConversion (left, ltype, type);
1100                                                 return this;
1101                                         }
1102
1103                                         right = Convert.ImplicitConversion (ec, right, ltype, loc);
1104                                         type = ltype;
1105                                         return this;
1106                                 }
1107                         } else if (TypeSpec.IsReferenceType (ltype)) {
1108                                 if (Convert.ImplicitConversionExists (ec, right, ltype)) {
1109                                         //
1110                                         // If right is a dynamic expression, the result type is dynamic
1111                                         //
1112                                         if (right.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
1113                                                 type = right.Type;
1114                                                 return this;
1115                                         }
1116
1117                                         //
1118                                         // Reduce ("foo" ?? expr) to expression
1119                                         //
1120                                         Constant lc = left as Constant;
1121                                         if (lc != null && !lc.IsDefaultValue)
1122                                                 return ReducedExpression.Create (lc, this);
1123
1124                                         //
1125                                         // Reduce (left ?? null) to left OR (null-constant ?? right) to right
1126                                         //
1127                                         if (right.IsNull || lc != null)
1128                                                 return ReducedExpression.Create (lc != null ? right : left, this);
1129
1130                                         right = Convert.ImplicitConversion (ec, right, ltype, loc);
1131                                         type = ltype;
1132                                         return this;
1133                                 }
1134
1135                                 //
1136                                 // Special case null ?? null
1137                                 //
1138                                 if (ltype == right.Type) {
1139                                         type = ltype;
1140                                         return this;
1141                                 }
1142                         } else {
1143                                 return null;
1144                         }
1145
1146                         TypeSpec rtype = right.Type;
1147                         if (!Convert.ImplicitConversionExists (ec, unwrap != null ? unwrap : left, rtype) || right.eclass == ExprClass.MethodGroup)
1148                                 return null;
1149
1150                         //
1151                         // Reduce (null ?? right) to right
1152                         //
1153                         if (left.IsNull)
1154                                 return ReducedExpression.Create (right, this).Resolve (ec);
1155
1156                         left = Convert.ImplicitConversion (ec, unwrap != null ? unwrap : left, rtype, loc);
1157                         type = rtype;
1158                         return this;
1159                 }
1160
1161                 public override bool ContainsEmitWithAwait ()
1162                 {
1163                         if (unwrap != null)
1164                                 return unwrap.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
1165
1166                         return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
1167                 }
1168
1169                 protected override Expression DoResolve (ResolveContext ec)
1170                 {
1171                         left = left.Resolve (ec);
1172                         right = right.Resolve (ec);
1173
1174                         if (left == null || right == null)
1175                                 return null;
1176
1177                         eclass = ExprClass.Value;
1178
1179                         Expression e = ConvertExpression (ec);
1180                         if (e == null) {
1181                                 Binary.Error_OperatorCannotBeApplied (ec, left, right, "??", loc);
1182                                 return null;
1183                         }
1184
1185                         return e;
1186                 }
1187
1188                 public override void Emit (EmitContext ec)
1189                 {
1190                         Label end_label = ec.DefineLabel ();
1191
1192                         if (unwrap != null) {
1193                                 Label is_null_label = ec.DefineLabel ();
1194
1195                                 unwrap.EmitCheck (ec);
1196                                 ec.Emit (OpCodes.Brfalse, is_null_label);
1197
1198                                 left.Emit (ec);
1199                                 ec.Emit (OpCodes.Br, end_label);
1200
1201                                 ec.MarkLabel (is_null_label);
1202                                 right.Emit (ec);
1203
1204                                 ec.MarkLabel (end_label);
1205                                 return;
1206                         }
1207
1208                         left.Emit (ec);
1209                         ec.Emit (OpCodes.Dup);
1210
1211                         // Only to make verifier happy
1212                         if (left.Type.IsGenericParameter)
1213                                 ec.Emit (OpCodes.Box, left.Type);
1214
1215                         ec.Emit (OpCodes.Brtrue, end_label);
1216
1217                         ec.Emit (OpCodes.Pop);
1218                         right.Emit (ec);
1219
1220                         ec.MarkLabel (end_label);
1221                 }
1222
1223                 protected override void CloneTo (CloneContext clonectx, Expression t)
1224                 {
1225                         NullCoalescingOperator target = (NullCoalescingOperator) t;
1226
1227                         target.left = left.Clone (clonectx);
1228                         target.right = right.Clone (clonectx);
1229                 }
1230                 
1231                 public override object Accept (StructuralVisitor visitor)
1232                 {
1233                         return visitor.Visit (this);
1234                 }
1235         }
1236
1237         class LiftedUnaryMutator : UnaryMutator
1238         {
1239                 public LiftedUnaryMutator (Mode mode, Expression expr, Location loc)
1240                         : base (mode, expr, loc)
1241                 {
1242                 }
1243
1244                 protected override Expression DoResolve (ResolveContext ec)
1245                 {
1246                         var orig_expr = expr;
1247
1248                         expr = Unwrap.Create (expr);
1249
1250                         var res = base.DoResolveOperation (ec);
1251
1252                         expr = orig_expr;
1253                         type = expr.Type;
1254
1255                         return res;
1256                 }
1257
1258                 protected override void EmitOperation (EmitContext ec)
1259                 {
1260                         Label is_null_label = ec.DefineLabel ();
1261                         Label end_label = ec.DefineLabel ();
1262
1263                         LocalTemporary lt = new LocalTemporary (type);
1264
1265                         // Value is on the stack
1266                         lt.Store (ec);
1267
1268                         var call = new CallEmitter ();
1269                         call.InstanceExpression = lt;
1270                         call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null);
1271
1272                         ec.Emit (OpCodes.Brfalse, is_null_label);
1273
1274                         call = new CallEmitter ();
1275                         call.InstanceExpression = lt;
1276                         call.EmitPredefined (ec, NullableInfo.GetGetValueOrDefault (expr.Type), null);
1277
1278                         lt.Release (ec);
1279
1280                         base.EmitOperation (ec);
1281
1282                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
1283                         ec.Emit (OpCodes.Br_S, end_label);
1284
1285                         ec.MarkLabel (is_null_label);
1286                         LiftedNull.Create (type, loc).Emit (ec);
1287
1288                         ec.MarkLabel (end_label);
1289                 }
1290         }
1291 }
1292