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