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