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