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