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