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