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