8e2dc682bbc0fbbfc2403f8ed3842c0c87c11dd4
[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 using System.Reflection;
16 using System.Reflection.Emit;
17         
18 namespace Mono.CSharp.Nullable
19 {
20         public class NullableType : TypeExpr
21         {
22                 TypeExpr underlying;
23
24                 public NullableType (TypeExpr underlying, Location l)
25                 {
26                         this.underlying = underlying;
27                         loc = l;
28
29                         eclass = ExprClass.Type;
30                 }
31
32                 public NullableType (TypeSpec type, Location loc)
33                         : this (new TypeExpression (type, loc), loc)
34                 { }
35
36                 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
37                 {
38                         if (TypeManager.generic_nullable_type == null) {
39                                 TypeManager.generic_nullable_type = TypeManager.CoreLookupType (ec.Compiler,
40                                         "System", "Nullable", 1, MemberKind.Struct, true);
41                         }
42
43                         TypeArguments args = new TypeArguments (underlying);
44                         GenericTypeExpr ctype = new GenericTypeExpr (TypeManager.generic_nullable_type, args, loc);
45                         return ctype.ResolveAsTypeTerminal (ec, false);
46                 }
47         }
48
49         static class NullableInfo
50         {
51                 public static MethodSpec GetConstructor (TypeSpec nullableType)
52                 {
53                         return TypeManager.GetPredefinedConstructor (nullableType, Location.Null, GetUnderlyingType (nullableType));
54                 }
55
56                 public static MethodSpec GetHasValue (TypeSpec nullableType)
57                 {
58                         return (MethodSpec) MemberCache.FindMember (nullableType,
59                                 MemberFilter.Method ("get_HasValue", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.None);
60                 }
61
62                 public static MethodSpec GetGetValueOrDefault (TypeSpec nullableType)
63                 {
64                         return (MethodSpec) MemberCache.FindMember (nullableType,
65                                 MemberFilter.Method ("GetValueOrDefault", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.None);
66                 }
67
68                 public static MethodSpec GetValue (TypeSpec nullableType)
69                 {
70                         return (MethodSpec) MemberCache.FindMember (nullableType,
71                                 MemberFilter.Method ("get_Value", 0, ParametersCompiled.EmptyReadOnlyParameters, null), BindingRestriction.None);
72                 }
73
74                 public static TypeSpec GetUnderlyingType (TypeSpec nullableType)
75                 {
76                         return ((InflatedTypeSpec) nullableType).TypeArguments[0];
77                 }
78
79                 public static bool IsNullableType (TypeSpec type)
80                 {
81                         throw new NotImplementedException ("net");
82                 }
83         }
84
85         public class Unwrap : Expression, IMemoryLocation, IAssignMethod
86         {
87                 Expression expr;
88
89                 LocalTemporary temp;
90                 readonly bool useDefaultValue;
91
92                 Unwrap (Expression expr, bool useDefaultValue)
93                 {
94                         this.expr = expr;
95                         this.loc = expr.Location;
96                         this.useDefaultValue = useDefaultValue;
97
98                         type = NullableInfo.GetUnderlyingType (expr.Type);
99                         eclass = expr.eclass;
100                 }
101
102                 public static Expression Create (Expression expr)
103                 {
104                         //
105                         // Avoid unwraping and wraping of same type
106                         //
107                         Wrap wrap = expr as Wrap;
108                         if (wrap != null)
109                                 return wrap.Child;
110
111                         return Create (expr, false);
112                 }
113
114                 public static Unwrap Create (Expression expr, bool useDefaultValue)
115                 {
116                         return new Unwrap (expr, useDefaultValue);
117                 }
118                 
119                 public override Expression CreateExpressionTree (ResolveContext ec)
120                 {
121                         return expr.CreateExpressionTree (ec);
122                 }
123
124                 protected override Expression DoResolve (ResolveContext ec)
125                 {
126                         return this;
127                 }
128
129                 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
130                 {
131                         return DoResolve (ec);
132                 }
133
134                 public override void Emit (EmitContext ec)
135                 {
136                         Store (ec);
137                         if (useDefaultValue)
138                                 Invocation.EmitCall (ec, false, this, NullableInfo.GetGetValueOrDefault (expr.Type), null, loc);
139                         else
140                                 Invocation.EmitCall (ec, false, this, NullableInfo.GetValue (expr.Type), null, loc);
141                 }
142
143                 public void EmitCheck (EmitContext ec)
144                 {
145                         Store (ec);
146                         Invocation.EmitCall (ec, false, 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         public class Wrap : TypeCast
264         {
265                 private Wrap (Expression expr, TypeSpec type)
266                         : base (expr, type)
267                 {
268                         eclass = ExprClass.Value;
269                 }
270
271                 public override Expression CreateExpressionTree (ResolveContext ec)
272                 {
273                         TypeCast child_cast = child as TypeCast;
274                         if (child_cast != null) {
275                                 child.Type = type;
276                                 return child_cast.CreateExpressionTree (ec);
277                         }
278
279                         return base.CreateExpressionTree (ec);
280                 }
281
282                 public static Expression Create (Expression expr, TypeSpec type)
283                 {
284                         //
285                         // Avoid unwraping and wraping of the same type
286                         //
287                         Unwrap unwrap = expr as Unwrap;
288                         if (unwrap != null && TypeManager.IsEqual (expr.Type, NullableInfo.GetUnderlyingType (type)))
289                                 return unwrap.Original;
290                 
291                         return new Wrap (expr, type);
292                 }
293                 
294                 public override void Emit (EmitContext ec)
295                 {
296                         child.Emit (ec);
297                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
298                 }
299         }
300
301         //
302         // Represents null literal lifted to nullable type
303         //
304         public class LiftedNull : NullConstant, IMemoryLocation
305         {
306                 private LiftedNull (TypeSpec nullable_type, Location loc)
307                         : base (nullable_type, loc)
308                 {
309                         eclass = ExprClass.Value;
310                 }
311
312                 public static Constant Create (TypeSpec nullable, Location loc)
313                 {
314                         return new LiftedNull (nullable, loc);
315                 }
316
317                 public static Expression CreateFromExpression (ResolveContext ec, Expression e)
318                 {
319                         ec.Report.Warning (458, 2, e.Location, "The result of the expression is always `null' of type `{0}'",
320                                 TypeManager.CSharpName (e.Type));
321
322                         return ReducedExpression.Create (Create (e.Type, e.Location), e);
323                 }
324
325                 public override void Emit (EmitContext ec)
326                 {
327                         // TODO: generate less temporary variables
328                         LocalTemporary value_target = new LocalTemporary (type);
329
330                         value_target.AddressOf (ec, AddressOp.Store);
331                         ec.Emit (OpCodes.Initobj, type);
332                         value_target.Emit (ec);
333                 }
334
335                 public void AddressOf (EmitContext ec, AddressOp Mode)
336                 {
337                         LocalTemporary value_target = new LocalTemporary (type);
338                                 
339                         value_target.AddressOf (ec, AddressOp.Store);
340                         ec.Emit (OpCodes.Initobj, type);
341                         ((IMemoryLocation) value_target).AddressOf (ec, Mode);
342                 }
343         }
344
345         //
346         // Generic lifting expression, supports all S/S? -> T/T? cases
347         //
348         public class Lifted : Expression, IMemoryLocation
349         {
350                 Expression expr, null_value;
351                 Unwrap unwrap;
352
353                 public Lifted (Expression expr, Unwrap unwrap, TypeSpec type)
354                 {
355                         this.expr = expr;
356                         this.unwrap = unwrap;
357                         this.loc = expr.Location;
358                         this.type = type;
359                 }
360
361                 public Lifted (Expression expr, Expression unwrap, TypeSpec type)
362                         : this (expr, unwrap as Unwrap, type)
363                 {
364                 }
365                 
366                 public override Expression CreateExpressionTree (ResolveContext ec)
367                 {
368                         return expr.CreateExpressionTree (ec);
369                 }                       
370
371                 protected override Expression DoResolve (ResolveContext ec)
372                 {
373                         //
374                         // It's null when lifting non-nullable type
375                         //
376                         if (unwrap == null) {
377                                 // S -> T? is wrap only
378                                 if (TypeManager.IsNullableType (type))
379                                         return Wrap.Create (expr, type);
380
381                                 // S -> T can be simplified
382                                 return expr;
383                         }
384
385                         // Wrap target for T?
386                         if (TypeManager.IsNullableType (type)) {
387                                 expr = Wrap.Create (expr, type);
388                                 if (expr == null)
389                                         return null;
390
391                                 null_value = LiftedNull.Create (type, loc);
392                         } else {
393                                 null_value = new NullConstant (type, loc);
394                         }
395
396                         eclass = ExprClass.Value;
397                         return this;
398                 }
399
400                 public override void Emit (EmitContext ec)
401                 {
402                         Label is_null_label = ec.DefineLabel ();
403                         Label end_label = ec.DefineLabel ();
404
405                         unwrap.EmitCheck (ec);
406                         ec.Emit (OpCodes.Brfalse, is_null_label);
407
408                         expr.Emit (ec);
409
410                         ec.Emit (OpCodes.Br, end_label);
411                         ec.MarkLabel (is_null_label);
412
413                         null_value.Emit (ec);
414                         ec.MarkLabel (end_label);
415                 }
416
417                 public void AddressOf (EmitContext ec, AddressOp mode)
418                 {
419                         unwrap.AddressOf (ec, mode);
420                 }
421         }
422
423         public class LiftedUnaryOperator : Unary, IMemoryLocation
424         {
425                 Unwrap unwrap;
426                 Expression user_operator;
427
428                 public LiftedUnaryOperator (Unary.Operator op, Expression expr, Location loc)
429                         : base (op, expr, loc)
430                 {
431                 }
432
433                 public void AddressOf (EmitContext ec, AddressOp mode)
434                 {
435                         unwrap.AddressOf (ec, mode);
436                 }
437
438                 public override Expression CreateExpressionTree (ResolveContext ec)
439                 {
440                         if (user_operator != null)
441                                 return user_operator.CreateExpressionTree (ec);
442
443                         if (Oper == Operator.UnaryPlus)
444                                 return Expr.CreateExpressionTree (ec);
445
446                         return base.CreateExpressionTree (ec);
447                 }
448
449                 protected override Expression DoResolve (ResolveContext ec)
450                 {
451                         unwrap = Unwrap.Create (Expr, false);
452                         if (unwrap == null)
453                                 return null;
454
455                         Expression res = base.ResolveOperator (ec, unwrap);
456                         if (res != this) {
457                                 if (user_operator == null)
458                                         return res;
459                         } else {
460                                 res = Expr = LiftExpression (ec, Expr);
461                         }
462
463                         if (res == null)
464                                 return null;
465
466                         eclass = ExprClass.Value;
467                         type = res.Type;
468                         return this;
469                 }
470
471                 public override void Emit (EmitContext ec)
472                 {
473                         Label is_null_label = ec.DefineLabel ();
474                         Label end_label = ec.DefineLabel ();
475
476                         unwrap.EmitCheck (ec);
477                         ec.Emit (OpCodes.Brfalse, is_null_label);
478
479                         if (user_operator != null) {
480                                 user_operator.Emit (ec);
481                         } else {
482                                 EmitOperator (ec, NullableInfo.GetUnderlyingType (type));
483                         }
484
485                         ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
486                         ec.Emit (OpCodes.Br_S, end_label);
487
488                         ec.MarkLabel (is_null_label);
489                         LiftedNull.Create (type, loc).Emit (ec);
490
491                         ec.MarkLabel (end_label);
492                 }
493
494                 Expression LiftExpression (ResolveContext ec, Expression expr)
495                 {
496                         TypeExpr lifted_type = new NullableType (expr.Type, expr.Location);
497                         lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false);
498                         if (lifted_type == null)
499                                 return null;
500
501                         expr.Type = lifted_type.Type;
502                         return expr;
503                 }
504
505                 protected override Expression ResolveEnumOperator (ResolveContext ec, Expression expr)
506                 {
507                         expr = base.ResolveEnumOperator (ec, expr);
508                         if (expr == null)
509                                 return null;
510
511                         Expr = LiftExpression (ec, Expr);
512                         return LiftExpression (ec, expr);
513                 }
514
515                 protected override Expression ResolveUserOperator (ResolveContext ec, Expression expr)
516                 {
517                         expr = base.ResolveUserOperator (ec, expr);
518                         if (expr == null)
519                                 return null;
520
521                         //
522                         // When a user operator is of non-nullable type
523                         //
524                         if (Expr is Unwrap) {
525                                 user_operator = LiftExpression (ec, expr);
526                                 return user_operator;
527                         }
528
529                         return expr;
530                 }
531         }
532
533         public class LiftedBinaryOperator : Binary
534         {
535                 Unwrap left_unwrap, right_unwrap;
536                 bool left_null_lifted, right_null_lifted;
537                 Expression left_orig, right_orig;
538                 Expression user_operator;
539                 MethodSpec wrap_ctor;
540
541                 public LiftedBinaryOperator (Binary.Operator op, Expression left, Expression right, Location loc)
542                         : base (op, left, right, loc)
543                 {
544                 }
545
546                 public override Expression CreateExpressionTree (ResolveContext ec)
547                 {
548                         if (user_operator != null)
549                                 return user_operator.CreateExpressionTree (ec);
550
551                         return base.CreateExpressionTree (ec);
552                 }
553
554                 //
555                 // CSC 2 has this behavior, it allows structs to be compared
556                 // with the null literal *outside* of a generics context and
557                 // inlines that as true or false.
558                 //
559                 Expression CreateNullConstant (ResolveContext ec, Expression expr)
560                 {
561                         // FIXME: Handle side effect constants
562                         Constant c = new BoolConstant (Oper == Operator.Inequality, loc).Resolve (ec);
563
564                         if ((Oper & Operator.EqualityMask) != 0) {
565                                 ec.Report.Warning (472, 2, loc, "The result of comparing value type `{0}' with null is `{1}'",
566                                         TypeManager.CSharpName (expr.Type), c.AsString ());
567                         } else {
568                                 ec.Report.Warning (464, 2, loc, "The result of comparing type `{0}' with null is always `{1}'",
569                                         TypeManager.CSharpName (expr.Type), c.AsString ());
570                         }
571
572                         return ReducedExpression.Create (c, this);
573                 }
574
575                 protected override Expression DoResolve (ResolveContext ec)
576                 {
577                         if ((Oper & Operator.LogicalMask) != 0) {
578                                 Error_OperatorCannotBeApplied (ec, left, right);
579                                 return null;
580                         }
581
582                         bool use_default_call = (Oper & (Operator.BitwiseMask | Operator.EqualityMask)) != 0;
583                         left_orig = left;
584                         if (TypeManager.IsNullableType (left.Type)) {
585                                 left = left_unwrap = Unwrap.Create (left, use_default_call);
586                                 if (left == null)
587                                         return null;
588                         }
589
590                         right_orig = right;
591                         if (TypeManager.IsNullableType (right.Type)) {
592                                 right = right_unwrap = Unwrap.Create (right, use_default_call);
593                                 if (right == null)
594                                         return null;
595                         }
596
597                         //
598                         // Some details are in 6.4.2, 7.2.7
599                         // Arguments can be lifted for equal operators when the return type is bool and both
600                         // arguments are of same type
601                         //      
602                         if (left_orig.IsNull) {
603                                 left = right;
604                                 left_null_lifted = true;
605                                 type = TypeManager.bool_type;
606                         }
607
608                         if (right_orig.IsNull) {
609                                 right = left;
610                                 right_null_lifted = true;
611                                 type = TypeManager.bool_type;
612                         }
613
614                         eclass = ExprClass.Value;
615                         return DoResolveCore (ec, left_orig, right_orig);
616                 }
617
618                 void EmitBitwiseBoolean (EmitContext ec)
619                 {
620                         Label load_left = ec.DefineLabel ();
621                         Label load_right = ec.DefineLabel ();
622                         Label end_label = ec.DefineLabel ();
623
624                         left_unwrap.Emit (ec);
625                         ec.Emit (OpCodes.Brtrue_S, load_right);
626
627                         right_unwrap.Emit (ec);
628                         ec.Emit (OpCodes.Brtrue_S, load_left);
629
630                         left_unwrap.EmitCheck (ec);
631                         ec.Emit (OpCodes.Brfalse_S, load_right);
632
633                         // load left
634                         ec.MarkLabel (load_left);
635
636                         if (Oper == Operator.BitwiseAnd) {
637                                 left_unwrap.Load (ec);
638                         } else {
639                                 right_unwrap.Load (ec);
640                                 right_unwrap = left_unwrap;
641                         }
642                         ec.Emit (OpCodes.Br_S, end_label);
643
644                         // load right
645                         ec.MarkLabel (load_right);
646                         right_unwrap.Load (ec);
647
648                         ec.MarkLabel (end_label);
649                 }
650
651                 //
652                 // Emits optimized equality or inequality operator when possible
653                 //
654                 void EmitEquality (EmitContext ec)
655                 {
656                         //
657                         // Either left or right is null
658                         //
659                         if (left_unwrap != null && (right_null_lifted || right.IsNull)) {
660                                 left_unwrap.EmitCheck (ec);
661                                 if (Oper == Binary.Operator.Equality) {
662                                         ec.Emit (OpCodes.Ldc_I4_0);
663                                         ec.Emit (OpCodes.Ceq);
664                                 }
665                                 return;
666                         }
667
668                         if (right_unwrap != null && (left_null_lifted || left.IsNull)) {
669                                 right_unwrap.EmitCheck (ec);
670                                 if (Oper == Binary.Operator.Equality) {
671                                         ec.Emit (OpCodes.Ldc_I4_0);
672                                         ec.Emit (OpCodes.Ceq);
673                                 }
674                                 return;
675                         }
676
677                         Label dissimilar_label = ec.DefineLabel ();
678                         Label end_label = ec.DefineLabel ();
679
680                         if (user_operator != null) {
681                                 user_operator.Emit (ec);
682                                 ec.Emit (Oper == Operator.Equality ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, dissimilar_label);
683                         } else {
684                                 left.Emit (ec);
685                                 right.Emit (ec);
686
687                                 ec.Emit (OpCodes.Bne_Un_S, dissimilar_label);
688                         }
689
690                         if (left_unwrap != null)
691                                 left_unwrap.EmitCheck (ec);
692
693                         if (right_unwrap != null)
694                                 right_unwrap.EmitCheck (ec);
695
696                         if (left_unwrap != null && right_unwrap != null) {
697                                 if (Oper == Operator.Inequality)
698                                         ec.Emit (OpCodes.Xor);
699                                 else
700                                         ec.Emit (OpCodes.Ceq);
701                         } else {
702                                 if (Oper == Operator.Inequality) {
703                                         ec.Emit (OpCodes.Ldc_I4_0);
704                                         ec.Emit (OpCodes.Ceq);
705                                 }
706                         }
707
708                         ec.Emit (OpCodes.Br_S, end_label);
709
710                         ec.MarkLabel (dissimilar_label);
711                         if (Oper == Operator.Inequality)
712                                 ec.Emit (OpCodes.Ldc_I4_1);
713                         else
714                                 ec.Emit (OpCodes.Ldc_I4_0);
715
716                         ec.MarkLabel (end_label);
717                 }
718                 
719                 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
720                 {
721                         Emit (ec);
722                         ec.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
723                 }                       
724
725                 public override void Emit (EmitContext ec)
726                 {
727                         //
728                         // Optimize same expression operation
729                         //
730                         if (right_unwrap != null && right.Equals (left))
731                                 right_unwrap = left_unwrap;
732
733                         if (user_operator == null && IsBitwiseBoolean) {
734                                 EmitBitwiseBoolean (ec);
735                                 return;
736                         }
737
738                         if ((Oper & Operator.EqualityMask) != 0) {
739                                 EmitEquality (ec);
740                                 return;
741                         }
742
743                         Label is_null_label = ec.DefineLabel ();
744                         Label end_label = ec.DefineLabel ();
745
746                         if (left_unwrap != null) {
747                                 left_unwrap.EmitCheck (ec);
748                                 ec.Emit (OpCodes.Brfalse, is_null_label);
749                         }
750
751                         //
752                         // Don't emit HasValue check when left and right expressions are same
753                         //
754                         if (right_unwrap != null && !left.Equals (right)) {
755                                 right_unwrap.EmitCheck (ec);
756                                 ec.Emit (OpCodes.Brfalse, is_null_label);
757                         }
758
759                         EmitOperator (ec, left.Type);
760
761                         if (wrap_ctor != null)
762                                 ec.Emit (OpCodes.Newobj, wrap_ctor);
763
764                         ec.Emit (OpCodes.Br_S, end_label);
765                         ec.MarkLabel (is_null_label);
766
767                         if ((Oper & Operator.ComparisonMask) != 0) {
768                                 ec.Emit (OpCodes.Ldc_I4_0);
769                         } else {
770                                 LiftedNull.Create (type, loc).Emit (ec);
771                         }
772
773                         ec.MarkLabel (end_label);
774                 }
775
776                 protected override void EmitOperator (EmitContext ec, TypeSpec l)
777                 {
778                         if (user_operator != null) {
779                                 user_operator.Emit (ec);
780                                 return;
781                         }
782
783                         if (TypeManager.IsNullableType (l))
784                                 l = TypeManager.GetTypeArguments (l) [0];
785
786                         base.EmitOperator (ec, l);
787                 }
788
789                 bool IsBitwiseBoolean {
790                         get {
791                                 return (Oper & Operator.BitwiseMask) != 0 && left_unwrap != null && right_unwrap != null &&
792                                 left_unwrap.Type == TypeManager.bool_type && right_unwrap.Type == TypeManager.bool_type;
793                         }
794                 }
795
796                 Expression LiftResult (ResolveContext ec, Expression res_expr)
797                 {
798                         TypeExpr lifted_type;
799
800                         //
801                         // Avoid double conversion
802                         //
803                         if (left_unwrap == null || left_null_lifted || !TypeManager.IsEqual (left_unwrap.Type, left.Type) || (left_unwrap != null && right_null_lifted)) {
804                                 lifted_type = new NullableType (left.Type, loc);
805                                 lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false);
806                                 if (lifted_type == null)
807                                         return null;
808
809                                 if (left is UserCast || left is TypeCast)
810                                         left.Type = lifted_type.Type;
811                                 else
812                                         left = EmptyCast.Create (left, lifted_type.Type);
813                         }
814
815                         if (right_unwrap == null || right_null_lifted || !TypeManager.IsEqual (right_unwrap.Type, right.Type) || (right_unwrap != null && left_null_lifted)) {
816                                 lifted_type = new NullableType (right.Type, loc);
817                                 lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false);
818                                 if (lifted_type == null)
819                                         return null;
820
821                                 if (right is UserCast || right is TypeCast)
822                                         right.Type = lifted_type.Type;
823                                 else
824                                         right = EmptyCast.Create (right, lifted_type.Type);
825                         }
826
827                         if ((Oper & Operator.ComparisonMask) == 0) {
828                                 lifted_type = new NullableType (res_expr.Type, loc);
829                                 lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false);
830                                 if (lifted_type == null)
831                                         return null;
832
833                                 wrap_ctor = NullableInfo.GetConstructor (lifted_type.Type);
834                                 type = res_expr.Type = lifted_type.Type;
835                         }
836
837                         if (left_null_lifted) {
838                                 left = LiftedNull.Create (right.Type, left.Location);
839
840                                 if ((Oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0)
841                                         return LiftedNull.CreateFromExpression (ec, res_expr);
842
843                                 //
844                                 // Value types and null comparison
845                                 //
846                                 if (right_unwrap == null || (Oper & Operator.RelationalMask) != 0)
847                                         return CreateNullConstant (ec, right_orig).Resolve (ec);
848                         }
849
850                         if (right_null_lifted) {
851                                 right = LiftedNull.Create (left.Type, right.Location);
852
853                                 if ((Oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0)
854                                         return LiftedNull.CreateFromExpression (ec, res_expr);
855
856                                 //
857                                 // Value types and null comparison
858                                 //
859                                 if (left_unwrap == null || (Oper & Operator.RelationalMask) != 0)
860                                         return CreateNullConstant (ec, left_orig);
861                         }
862
863                         return res_expr;
864                 }
865
866                 protected override Expression ResolveOperatorPredefined (ResolveContext ec, Binary.PredefinedOperator [] operators, bool primitives_only, TypeSpec enum_type)
867                 {
868                         Expression e = base.ResolveOperatorPredefined (ec, operators, primitives_only, enum_type);
869
870                         if (e == this || enum_type != null)
871                                 return LiftResult (ec, e);
872
873                         //
874                         // 7.9.9 Equality operators and null
875                         //
876                         // The == and != operators permit one operand to be a value of a nullable type and
877                         // the other to be the null literal, even if no predefined or user-defined operator
878                         // (in unlifted or lifted form) exists for the operation.
879                         //
880                         if (e == null && (Oper & Operator.EqualityMask) != 0) {
881                                 if ((left_null_lifted && right_unwrap != null) || (right_null_lifted && left_unwrap != null))
882                                         return LiftResult (ec, this);
883                         }
884
885                         return e;
886                 }
887
888                 protected override Expression ResolveUserOperator (ResolveContext ec, TypeSpec l, TypeSpec r)
889                 {
890                         Expression expr = base.ResolveUserOperator (ec, l, r);
891                         if (expr == null)
892                                 return null;
893
894                         expr = LiftResult (ec, expr);
895                         if (expr is Constant)
896                                 return expr;
897
898                         type = expr.Type;
899                         user_operator = expr;
900                         return this;
901                 }
902         }
903
904         public class NullCoalescingOperator : Expression
905         {
906                 Expression left, right;
907                 Unwrap unwrap;
908
909                 public NullCoalescingOperator (Expression left, Expression right, Location loc)
910                 {
911                         this.left = left;
912                         this.right = right;
913                         this.loc = loc;
914                 }
915                 
916                 public override Expression CreateExpressionTree (ResolveContext ec)
917                 {
918                         if (left.Type == TypeManager.null_type)
919                                 ec.Report.Error (845, loc, "An expression tree cannot contain a coalescing operator with null left side");
920
921                         UserCast uc = left as UserCast;
922                         Expression conversion = null;
923                         if (uc != null) {
924                                 left = uc.Source;
925
926                                 Arguments c_args = new Arguments (2);
927                                 c_args.Add (new Argument (uc.CreateExpressionTree (ec)));
928                                 c_args.Add (new Argument (left.CreateExpressionTree (ec)));
929                                 conversion = CreateExpressionFactoryCall (ec, "Lambda", c_args);
930                         }
931
932                         Arguments args = new Arguments (3);
933                         args.Add (new Argument (left.CreateExpressionTree (ec)));
934                         args.Add (new Argument (right.CreateExpressionTree (ec)));
935                         if (conversion != null)
936                                 args.Add (new Argument (conversion));
937                         
938                         return CreateExpressionFactoryCall (ec, "Coalesce", args);
939                 }
940
941                 Expression ConvertExpression (ResolveContext ec)
942                 {
943                         // TODO: ImplicitConversionExists should take care of this
944                         if (left.eclass == ExprClass.MethodGroup)
945                                 return null;
946
947                         TypeSpec ltype = left.Type;
948
949                         //
950                         // If left is a nullable type and an implicit conversion exists from right to underlying type of left,
951                         // the result is underlying type of left
952                         //
953                         if (TypeManager.IsNullableType (ltype)) {
954                                 unwrap = Unwrap.Create (left, false);
955                                 if (unwrap == null)
956                                         return null;
957
958                                 if (Convert.ImplicitConversionExists (ec, right, unwrap.Type)) {
959                                         left = unwrap;
960                                         type = left.Type;
961                                         right = Convert.ImplicitConversion (ec, right, type, loc);
962                                         return this;
963                                 }
964                         } else if (TypeManager.IsReferenceType (ltype)) {
965                                 if (Convert.ImplicitConversionExists (ec, right, ltype)) {
966                                         //
967                                         // Reduce (constant ?? expr) to constant
968                                         //
969                                         Constant lc = left as Constant;
970                                         if (lc != null && !lc.IsDefaultValue)
971                                                 return new SideEffectConstant (lc, right, loc).Resolve (ec);
972
973                                         //
974                                         // Reduce (left ?? null) to left OR (null-constant ?? right) to right
975                                         //
976                                         if (right.IsNull || lc != null)
977                                                 return ReducedExpression.Create (lc != null ? right : left, this);
978
979                                         right = Convert.ImplicitConversion (ec, right, ltype, loc);
980                                         type = left.Type;
981                                         return this;
982                                 }
983                         } else {
984                                 return null;
985                         }
986
987                         TypeSpec rtype = right.Type;
988                         if (!Convert.ImplicitConversionExists (ec, unwrap != null ? unwrap : left, rtype) || right.eclass == ExprClass.MethodGroup)
989                                 return null;
990
991                         //
992                         // Reduce (null ?? right) to right
993                         //
994                         if (left.IsNull)
995                                 return ReducedExpression.Create (right, this);
996
997                         left = Convert.ImplicitConversion (ec, unwrap != null ? unwrap : left, rtype, loc);
998                         type = rtype;
999                         return this;
1000                 }
1001
1002                 protected override Expression DoResolve (ResolveContext ec)
1003                 {
1004                         left = left.Resolve (ec);
1005                         right = right.Resolve (ec);
1006
1007                         if (left == null || right == null)
1008                                 return null;
1009
1010                         eclass = ExprClass.Value;
1011
1012                         Expression e = ConvertExpression (ec);
1013                         if (e == null) {
1014                                 Binary.Error_OperatorCannotBeApplied (ec, left, right, "??", loc);
1015                                 return null;
1016                         }
1017
1018                         return e;
1019                 }
1020
1021                 public override void Emit (EmitContext ec)
1022                 {
1023                         Label end_label = ec.DefineLabel ();
1024
1025                         if (unwrap != null) {
1026                                 Label is_null_label = ec.DefineLabel ();
1027
1028                                 unwrap.EmitCheck (ec);
1029                                 ec.Emit (OpCodes.Brfalse, is_null_label);
1030
1031                                 left.Emit (ec);
1032                                 ec.Emit (OpCodes.Br, end_label);
1033
1034                                 ec.MarkLabel (is_null_label);
1035                                 right.Emit (ec);
1036
1037                                 ec.MarkLabel (end_label);
1038                                 return;
1039                         }
1040
1041                         left.Emit (ec);
1042
1043                         ec.Emit (OpCodes.Dup);
1044                         ec.Emit (OpCodes.Brtrue, end_label);
1045
1046                         ec.Emit (OpCodes.Pop);
1047                         right.Emit (ec);
1048
1049                         ec.MarkLabel (end_label);
1050                 }
1051
1052                 protected override void CloneTo (CloneContext clonectx, Expression t)
1053                 {
1054                         NullCoalescingOperator target = (NullCoalescingOperator) t;
1055
1056                         target.left = left.Clone (clonectx);
1057                         target.right = right.Clone (clonectx);
1058                 }
1059         }
1060
1061         public class LiftedUnaryMutator : ExpressionStatement
1062         {
1063                 public readonly UnaryMutator.Mode Mode;
1064                 Expression expr;
1065                 UnaryMutator underlying;
1066                 Unwrap unwrap;
1067
1068                 public LiftedUnaryMutator (UnaryMutator.Mode mode, Expression expr, Location loc)
1069                 {
1070                         this.expr = expr;
1071                         this.Mode = mode;
1072                         this.loc = loc;
1073                 }
1074
1075                 public override Expression CreateExpressionTree (ResolveContext ec)
1076                 {
1077                         return new SimpleAssign (this, this).CreateExpressionTree (ec);
1078                 }
1079
1080                 protected override Expression DoResolve (ResolveContext ec)
1081                 {
1082                         expr = expr.Resolve (ec);
1083                         if (expr == null)
1084                                 return null;
1085
1086                         unwrap = Unwrap.Create (expr, false);
1087                         if (unwrap == null)
1088                                 return null;
1089
1090                         underlying = (UnaryMutator) new UnaryMutator (Mode, unwrap, loc).Resolve (ec);
1091                         if (underlying == null)
1092                                 return null;
1093
1094
1095                         eclass = ExprClass.Value;
1096                         type = expr.Type;
1097                         return this;
1098                 }
1099
1100                 void DoEmit (EmitContext ec, bool is_expr)
1101                 {
1102                         Label is_null_label = ec.DefineLabel ();
1103                         Label end_label = ec.DefineLabel ();
1104
1105                         unwrap.EmitCheck (ec);
1106                         ec.Emit (OpCodes.Brfalse, is_null_label);
1107
1108                         if (is_expr) {
1109                                 underlying.Emit (ec);
1110                                 ec.Emit (OpCodes.Br_S, end_label);
1111                         } else {
1112                                 underlying.EmitStatement (ec);
1113                         }
1114
1115                         ec.MarkLabel (is_null_label);
1116                         if (is_expr)
1117                                 LiftedNull.Create (type, loc).Emit (ec);
1118
1119                         ec.MarkLabel (end_label);
1120                 }
1121
1122                 public override void Emit (EmitContext ec)
1123                 {
1124                         DoEmit (ec, true);
1125                 }
1126
1127                 public override void EmitStatement (EmitContext ec)
1128                 {
1129                         DoEmit (ec, false);
1130                 }
1131         }
1132 }
1133