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