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