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