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