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