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