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