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