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