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