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