2 // nullable.cs: Nullable types support
4 // Authors: Martin Baulig (martin@ximian.com)
5 // Miguel de Icaza (miguel@ximian.com)
6 // Marek Safar (marek.safar@gmail.com)
8 // Licensed under the terms of the GNU GPL
10 // (C) 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
11 // (C) 2004 Novell, Inc
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Collections;
19 namespace Mono.CSharp.Nullable
21 public class NullableType : TypeExpr
23 Expression underlying;
25 public NullableType (Expression underlying, Location l)
27 this.underlying = underlying;
30 eclass = ExprClass.Type;
33 public NullableType (Type type, Location loc)
34 : this (new TypeExpression (type, loc), loc)
37 public override string Name {
38 get { return underlying.ToString () + "?"; }
41 public override string FullName {
42 get { return underlying.ToString () + "?"; }
45 protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
47 TypeArguments args = new TypeArguments (loc);
48 args.Add (underlying);
50 if (TypeManager.generic_nullable_type == null) {
51 TypeManager.generic_nullable_type = TypeManager.CoreLookupType (
52 "System", "Nullable`1", Kind.Struct, true);
55 ConstructedType ctype = new ConstructedType (TypeManager.generic_nullable_type, args, loc);
56 return ctype.ResolveAsTypeTerminal (ec, false);
60 public sealed class NullableInfo
62 public readonly Type Type;
63 public readonly Type UnderlyingType;
64 public readonly MethodInfo HasValue;
65 public readonly MethodInfo Value;
66 public readonly MethodInfo GetValueOrDefault;
67 public readonly ConstructorInfo Constructor;
69 public NullableInfo (Type type)
72 UnderlyingType = TypeManager.GetTypeArguments (type) [0];
74 PropertyInfo has_value_pi = TypeManager.GetPredefinedProperty (type, "HasValue", Location.Null);
75 PropertyInfo value_pi = TypeManager.GetPredefinedProperty (type, "Value", Location.Null);
76 GetValueOrDefault = TypeManager.GetPredefinedMethod (type, "GetValueOrDefault", Location.Null, Type.EmptyTypes);
78 HasValue = has_value_pi.GetGetMethod (false);
79 Value = value_pi.GetGetMethod (false);
81 if (UnderlyingType.Module == CodeGen.Module.Builder) {
82 Type o_type = TypeManager.DropGenericTypeArguments (type);
83 Constructor = TypeBuilder.GetConstructor (type,
84 TypeManager.GetPredefinedConstructor (o_type, Location.Null, o_type.GetGenericArguments ()));
88 Constructor = type.GetConstructor (new Type[] { UnderlyingType });
92 public class HasValue : Expression
97 private HasValue (Expression expr)
102 public static Expression Create (Expression expr, EmitContext ec)
104 return new HasValue (expr).Resolve (ec);
107 public override void Emit (EmitContext ec)
109 IMemoryLocation memory_loc = expr as IMemoryLocation;
110 if (memory_loc == null) {
111 LocalTemporary temp = new LocalTemporary (expr.Type);
116 memory_loc.AddressOf (ec, AddressOp.LoadStore);
117 ec.ig.EmitCall (OpCodes.Call, info.HasValue, null);
120 public override Expression DoResolve (EmitContext ec)
122 this.info = new NullableInfo (expr.Type);
124 type = TypeManager.bool_type;
125 eclass = expr.eclass;
130 public class Unwrap : Expression, IMemoryLocation, IAssignMethod
138 protected Unwrap (Expression expr)
141 this.loc = expr.Location;
144 public static Unwrap Create (Expression expr, EmitContext ec)
146 return new Unwrap (expr).Resolve (ec) as Unwrap;
149 public override Expression CreateExpressionTree (EmitContext ec)
151 return expr.CreateExpressionTree (ec);
154 public override Expression DoResolve (EmitContext ec)
159 temp = new LocalTemporary (expr.Type);
161 info = new NullableInfo (expr.Type);
162 type = info.UnderlyingType;
163 eclass = expr.eclass;
167 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
169 return DoResolve (ec);
172 public override void Emit (EmitContext ec)
174 AddressOf (ec, AddressOp.LoadStore);
175 ec.ig.EmitCall (OpCodes.Call, info.Value, null);
178 public void EmitCheck (EmitContext ec)
180 AddressOf (ec, AddressOp.LoadStore);
181 ec.ig.EmitCall (OpCodes.Call, info.HasValue, null);
184 public void EmitGetValueOrDefault (EmitContext ec)
186 AddressOf (ec, AddressOp.LoadStore);
187 ec.ig.EmitCall (OpCodes.Call, info.GetValueOrDefault, null);
190 public override bool Equals (object obj)
192 Unwrap uw = obj as Unwrap;
193 return uw != null && expr.Equals (uw.expr);
196 public Expression Original {
202 public override int GetHashCode ()
204 return expr.GetHashCode ();
207 public override bool IsNull {
213 public void Store (EmitContext ec)
218 void create_temp (EmitContext ec)
220 if ((temp != null) && !has_temp) {
227 public void LoadTemporary (EmitContext ec)
232 public void AddressOf (EmitContext ec, AddressOp mode)
236 temp.AddressOf (ec, AddressOp.LoadStore);
238 ((IMemoryLocation) expr).AddressOf (ec, AddressOp.LoadStore);
241 public void Emit (EmitContext ec, bool leave_copy)
254 public void EmitAssign (EmitContext ec, Expression source,
255 bool leave_copy, bool prepare_for_load)
257 InternalWrap wrap = new InternalWrap (source, info, loc);
258 ((IAssignMethod) expr).EmitAssign (ec, wrap, leave_copy, false);
261 protected class InternalWrap : Expression
263 public Expression expr;
264 public NullableInfo info;
266 public InternalWrap (Expression expr, NullableInfo info, Location loc)
273 eclass = ExprClass.Value;
276 public override Expression DoResolve (EmitContext ec)
281 public override void Emit (EmitContext ec)
284 ec.ig.Emit (OpCodes.Newobj, info.Constructor);
289 public class Wrap : EmptyCast
291 readonly NullableInfo info;
293 protected Wrap (Expression expr, Type type)
296 info = new NullableInfo (type);
297 eclass = ExprClass.Value;
300 public static new Expression Create (Expression expr, Type type)
302 return new Wrap (expr, type);
305 public override void Emit (EmitContext ec)
308 ec.ig.Emit (OpCodes.Newobj, info.Constructor);
312 class LiftedWrap : Wrap
314 public LiftedWrap (Expression expr, Type type)
319 public override Expression CreateExpressionTree (EmitContext ec)
321 return child.CreateExpressionTree (ec);
326 // Represents null literal lifted to nullable type
328 public class LiftedNull : EmptyConstantCast, IMemoryLocation
330 private LiftedNull (Type nullable_type, Location loc)
331 : base (new NullLiteral (loc), nullable_type)
333 eclass = ExprClass.Value;
336 public static Constant Create (Type nullable, Location loc)
338 return new LiftedNull (nullable, loc);
341 public static Expression CreateFromExpression (Expression e)
343 Report.Warning (458, 2, e.Location, "The result of the expression is always `null' of type `{0}'",
344 TypeManager.CSharpName (e.Type));
346 return ReducedExpression.Create (Create (e.Type, e.Location) , e);
349 public override Expression CreateExpressionTree (EmitContext ec)
351 ArrayList args = new ArrayList (2);
352 args.Add (new Argument (this));
353 args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
355 return CreateExpressionFactoryCall ("Constant", args);
358 public override void Emit (EmitContext ec)
360 // TODO: generate less temporary variables
361 LocalTemporary value_target = new LocalTemporary (type);
363 value_target.AddressOf (ec, AddressOp.Store);
364 ec.ig.Emit (OpCodes.Initobj, type);
365 value_target.Emit (ec);
368 public void AddressOf (EmitContext ec, AddressOp Mode)
370 LocalTemporary value_target = new LocalTemporary (type);
372 value_target.AddressOf (ec, AddressOp.Store);
373 ec.ig.Emit (OpCodes.Initobj, type);
374 ((IMemoryLocation) value_target).AddressOf (ec, Mode);
378 public abstract class Lifted : Expression, IMemoryLocation
380 Expression expr, underlying, wrap, null_value;
383 protected Lifted (Expression expr, Location loc)
389 public override Expression CreateExpressionTree (EmitContext ec)
391 return underlying.CreateExpressionTree (ec);
394 public override Expression DoResolve (EmitContext ec)
396 expr = expr.Resolve (ec);
400 unwrap = Unwrap.Create (expr, ec);
404 underlying = ResolveUnderlying (unwrap, ec);
405 if (underlying == null)
408 TypeExpr target_type = new NullableType (underlying.Type, loc);
409 target_type = target_type.ResolveAsTypeTerminal (ec, false);
410 if (target_type == null)
413 wrap = Wrap.Create (underlying, target_type.Type);
417 null_value = LiftedNull.Create (wrap.Type, loc);
420 eclass = ExprClass.Value;
424 protected abstract Expression ResolveUnderlying (Expression unwrap, EmitContext ec);
426 public override void Emit (EmitContext ec)
428 ILGenerator ig = ec.ig;
429 Label is_null_label = ig.DefineLabel ();
430 Label end_label = ig.DefineLabel ();
432 unwrap.EmitCheck (ec);
433 ig.Emit (OpCodes.Brfalse, is_null_label);
436 ig.Emit (OpCodes.Br, end_label);
438 ig.MarkLabel (is_null_label);
439 null_value.Emit (ec);
441 ig.MarkLabel (end_label);
444 public void AddressOf (EmitContext ec, AddressOp mode)
446 unwrap.AddressOf (ec, mode);
450 public class LiftedConversion : Lifted
452 public readonly bool IsUser;
453 public readonly bool IsExplicit;
454 public readonly Type TargetType;
456 public LiftedConversion (Expression expr, Type target_type, bool is_user,
457 bool is_explicit, Location loc)
460 this.IsUser = is_user;
461 this.IsExplicit = is_explicit;
462 this.TargetType = target_type;
465 protected override Expression ResolveUnderlying (Expression unwrap, EmitContext ec)
467 Type type = TypeManager.GetTypeArguments (TargetType) [0];
470 return Convert.UserDefinedConversion (ec, unwrap, type, loc, IsExplicit);
473 return Convert.ExplicitConversion (ec, unwrap, type, loc);
475 return Convert.ImplicitConversion (ec, unwrap, type, loc);
480 public class LiftedUnaryOperator : Lifted
482 public readonly Unary.Operator Oper;
484 public LiftedUnaryOperator (Unary.Operator op, Expression expr, Location loc)
490 protected override Expression ResolveUnderlying (Expression unwrap, EmitContext ec)
492 return new Unary (Oper, unwrap, loc).Resolve (ec);
496 public class LiftedBinaryOperator : Binary
498 Unwrap left_unwrap, right_unwrap;
499 bool left_null_lifted, right_null_lifted;
500 Expression left_orig, right_orig;
502 public LiftedBinaryOperator (Binary.Operator op, Expression left, Expression right,
504 : base (op, left, right)
510 // CSC 2 has this behavior, it allows structs to be compared
511 // with the null literal *outside* of a generics context and
512 // inlines that as true or false.
514 Expression CreateNullConstant (Expression expr)
516 // FIXME: Handle side effect constants
517 Constant c = new BoolConstant (Oper == Operator.Inequality, loc);
519 if ((Oper & Operator.EqualityMask) != 0) {
520 Report.Warning (472, 2, loc, "The result of comparing `{0}' against null is always `{1}'. " +
521 "This operation is undocumented and it is temporary supported for compatibility reasons only",
522 expr.GetSignatureForError (), c.AsString ());
524 Report.Warning (464, 2, loc, "The result of comparing type `{0}' against null is always `{1}'",
525 expr.GetSignatureForError (), c.AsString ());
528 return ReducedExpression.Create (c, this);
531 public override Expression DoResolve (EmitContext ec)
533 if (eclass != ExprClass.Invalid)
536 // TODO: How does it work with use-operators?
537 if ((Oper == Binary.Operator.LogicalAnd) ||
538 (Oper == Binary.Operator.LogicalOr)) {
539 Error_OperatorCannotBeApplied (left, right);
544 if (TypeManager.IsNullableType (left.Type)) {
545 left = left_unwrap = Unwrap.Create (left, ec);
551 if (TypeManager.IsNullableType (right.Type)) {
552 right = right_unwrap = Unwrap.Create (right, ec);
558 // Some details are in 6.4.2, 7.2.7
559 // Arguments can be lifted for equal operators when the return type is bool and both
560 // arguments are of same type
562 if (left is NullLiteral) {
564 left_null_lifted = true;
565 type = TypeManager.bool_type;
568 if (right is NullLiteral) {
570 right_null_lifted = true;
571 type = TypeManager.bool_type;
574 eclass = ExprClass.Value;
575 Expression expr = DoResolveCore (ec, left_orig, right_orig);
576 if (expr != this || (Oper & Operator.ComparisonMask) != 0)
579 TypeExpr target_type = new NullableType (type, loc);
580 target_type = target_type.ResolveAsTypeTerminal (ec, false);
581 if (target_type == null)
584 type = target_type.Type;
588 void EmitBitwiseBoolean (EmitContext ec)
590 ILGenerator ig = ec.ig;
592 Label load_left = ig.DefineLabel ();
593 Label load_right = ig.DefineLabel ();
594 Label end_label = ig.DefineLabel ();
596 left_unwrap.EmitGetValueOrDefault (ec);
597 ig.Emit (OpCodes.Brtrue_S, load_right);
599 right_unwrap.EmitGetValueOrDefault (ec);
600 ig.Emit (OpCodes.Brtrue_S, load_left);
602 left_unwrap.EmitCheck (ec);
603 ig.Emit (OpCodes.Brfalse_S, load_right);
606 ig.MarkLabel (load_left);
608 if (Oper == Operator.BitwiseAnd) {
609 left_unwrap.LoadTemporary (ec);
611 right_unwrap.LoadTemporary (ec);
612 right_unwrap = left_unwrap;
614 ig.Emit (OpCodes.Br_S, end_label);
617 ig.MarkLabel (load_right);
618 right_unwrap.LoadTemporary (ec);
620 ig.MarkLabel (end_label);
623 void EmitEquality (EmitContext ec)
625 ILGenerator ig = ec.ig;
627 Label both_have_value_label = ig.DefineLabel ();
628 Label end_label = ig.DefineLabel ();
631 // Both are nullable types
633 if (left_unwrap != null && right_unwrap != null && !right.IsNull && !left.IsNull) {
634 Label dissimilar_label = ig.DefineLabel ();
636 left_unwrap.EmitGetValueOrDefault (ec);
637 right_unwrap.EmitGetValueOrDefault (ec);
638 ig.Emit (OpCodes.Bne_Un_S, dissimilar_label);
640 left_unwrap.EmitCheck (ec);
641 right_unwrap.EmitCheck (ec);
642 if (Oper == Operator.Inequality)
643 ig.Emit (OpCodes.Xor);
645 ig.Emit (OpCodes.Ceq);
647 ig.Emit (OpCodes.Br_S, end_label);
649 ig.MarkLabel (dissimilar_label);
650 if (Oper == Operator.Inequality)
651 ig.Emit (OpCodes.Ldc_I4_1);
653 ig.Emit (OpCodes.Ldc_I4_0);
655 ig.MarkLabel (end_label);
660 // Either left or right is nullable
662 if (left_unwrap != null) {
663 left_unwrap.EmitCheck (ec);
665 if (Oper == Binary.Operator.Equality) {
666 ig.Emit (OpCodes.Ldc_I4_0);
667 ig.Emit (OpCodes.Ceq);
671 ig.Emit (OpCodes.Brtrue_S, both_have_value_label);
673 right_unwrap.EmitCheck (ec);
675 if (Oper == Binary.Operator.Equality) {
676 ig.Emit (OpCodes.Ldc_I4_0);
677 ig.Emit (OpCodes.Ceq);
681 ig.Emit (OpCodes.Brtrue_S, both_have_value_label);
684 if (Oper == Binary.Operator.Equality)
685 ig.Emit (OpCodes.Ldc_I4_0);
687 ig.Emit (OpCodes.Ldc_I4_1);
688 ig.Emit (OpCodes.Br, end_label);
690 ig.MarkLabel (both_have_value_label);
693 ig.MarkLabel (end_label);
696 void EmitComparision (EmitContext ec)
698 ILGenerator ig = ec.ig;
700 Label is_null_label = ig.DefineLabel ();
701 Label end_label = ig.DefineLabel ();
703 if (left_unwrap != null) {
704 left_unwrap.EmitCheck (ec);
705 ig.Emit (OpCodes.Brfalse, is_null_label);
708 if (right_unwrap != null) {
709 right_unwrap.EmitCheck (ec);
710 ig.Emit (OpCodes.Brfalse, is_null_label);
714 ig.Emit (OpCodes.Br_S, end_label);
716 ig.MarkLabel (is_null_label);
717 ig.Emit (OpCodes.Ldc_I4_0);
719 ig.MarkLabel (end_label);
722 public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
725 ec.ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
728 public override void Emit (EmitContext ec)
730 if (left_unwrap != null)
731 left_unwrap.Store (ec);
732 if (right_unwrap != null)
733 right_unwrap.Store (ec);
735 if (IsBitwiseBoolean) {
736 EmitBitwiseBoolean (ec);
740 if ((Oper & Operator.EqualityMask) != 0) {
745 if ((Oper & Operator.ComparisonMask) != 0) {
746 EmitComparision (ec);
750 ILGenerator ig = ec.ig;
752 Label is_null_label = ig.DefineLabel ();
753 Label end_label = ig.DefineLabel ();
755 if (left_unwrap != null) {
756 left_unwrap.EmitCheck (ec);
757 ig.Emit (OpCodes.Brfalse, is_null_label);
760 if (right_unwrap != null) {
761 right_unwrap.EmitCheck (ec);
762 ig.Emit (OpCodes.Brfalse, is_null_label);
765 base.EmitOperator (ec);
767 ig.Emit (OpCodes.Br_S, end_label);
768 ig.MarkLabel (is_null_label);
769 LiftedNull.Create (type, loc).Emit (ec);
771 ig.MarkLabel (end_label);
774 bool IsBitwiseBoolean {
776 return (Oper & Operator.BitwiseMask) != 0 && left_unwrap != null && right_unwrap != null &&
777 left_unwrap.Type == TypeManager.bool_type && right_unwrap.Type == TypeManager.bool_type;
781 Expression LiftResult (EmitContext ec, Expression res_expr)
783 TypeExpr lifted_type;
786 // Avoid double conversion
788 if (left_unwrap == null || left_null_lifted || !TypeManager.IsEqual (left_unwrap.Type, left.Type)) {
789 lifted_type = new NullableType (left.Type, loc);
790 lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false);
791 if (lifted_type == null)
794 left = EmptyCast.Create (left, lifted_type.Type);
797 if (right_unwrap == null || right_null_lifted || !TypeManager.IsEqual (right_unwrap.Type, right.Type)) {
798 lifted_type = new NullableType (right.Type, loc);
799 lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false);
800 if (lifted_type == null)
803 right = EmptyCast.Create (right, lifted_type.Type);
806 // TODO: Handle bitwise bool
807 if ((Oper & Operator.ComparisonMask) == 0 && !IsBitwiseBoolean) {
808 lifted_type = new NullableType (res_expr.Type, loc);
809 lifted_type = lifted_type.ResolveAsTypeTerminal (ec, false);
810 if (lifted_type == null)
813 res_expr = new LiftedWrap (res_expr, lifted_type.Type).Resolve (ec);
816 if (left_null_lifted) {
817 left = LiftedNull.Create (right.Type, left.Location);
820 // Value types and null comparison
822 if (right_unwrap == null || (Oper & Operator.RelationalMask) != 0)
823 return CreateNullConstant (right_orig).Resolve (ec);
825 if ((Oper & Operator.ArithmeticMask) != 0)
826 return LiftedNull.CreateFromExpression (res_expr);
829 if (right_null_lifted) {
830 right = LiftedNull.Create (left.Type, right.Location);
833 // Value types and null comparison
835 if (left_unwrap == null || (Oper & Operator.RelationalMask) != 0)
836 return CreateNullConstant (left_orig).Resolve (ec);
838 if ((Oper & Operator.ArithmeticMask) != 0)
839 return LiftedNull.CreateFromExpression (res_expr);
845 protected override Expression ResolveOperatorPredefined (EmitContext ec, Binary.PredefinedOperator [] operators, bool primitives_only)
847 Expression e = base.ResolveOperatorPredefined (ec, operators, primitives_only);
850 return LiftResult (ec, e);
853 // 7.9.9 Equality operators and null
855 // The == and != operators permit one operand to be a value of a nullable type and
856 // the other to be the null literal, even if no predefined or user-defined operator
857 // (in unlifted or lifted form) exists for the operation.
859 if (e == null && (Oper & Operator.EqualityMask) != 0) {
860 if ((left_null_lifted && right_unwrap != null) || (right_null_lifted && left_unwrap != null))
861 return LiftResult (ec, this);
867 protected override Expression ResolveUserOperator (EmitContext ec, Type l, Type r)
869 Expression expr = base.ResolveUserOperator (ec, l, r);
874 // When lifting null literal and user operator exists, no call is made
876 if (left_null_lifted || right_null_lifted)
877 expr = ReducedExpression.Create (this, expr).Resolve (ec);
879 return LiftResult (ec, expr);
883 public class NullCoalescingOperator : Expression
885 Expression left, right;
888 public NullCoalescingOperator (Expression left, Expression right, Location loc)
895 public override Expression CreateExpressionTree (EmitContext ec)
897 UserCast uc = left as UserCast;
898 Expression conversion = null;
902 ArrayList c_args = new ArrayList (2);
903 c_args.Add (new Argument (uc.CreateExpressionTree (ec)));
904 c_args.Add (new Argument (left.CreateExpressionTree (ec)));
905 conversion = CreateExpressionFactoryCall ("Lambda", c_args);
908 ArrayList args = new ArrayList (3);
909 args.Add (new Argument (left.CreateExpressionTree (ec)));
910 args.Add (new Argument (right.CreateExpressionTree (ec)));
911 if (conversion != null)
912 args.Add (new Argument (conversion));
914 return CreateExpressionFactoryCall ("Coalesce", args);
917 public override Expression DoResolve (EmitContext ec)
922 left = left.Resolve (ec);
923 right = right.Resolve (ec);
925 if (left == null || right == null)
928 eclass = ExprClass.Value;
929 Type ltype = left.Type, rtype = right.Type;
932 if (TypeManager.IsNullableType (ltype)) {
933 NullableInfo info = new NullableInfo (ltype);
935 unwrap = Unwrap.Create (left, ec);
939 expr = Convert.ImplicitConversion (ec, right, info.UnderlyingType, loc);
946 } else if (!TypeManager.IsReferenceType (ltype)) {
947 Binary.Error_OperatorCannotBeApplied (loc, "??", ltype, rtype);
951 expr = Convert.ImplicitConversion (ec, right, ltype, loc);
958 Expression left_null = unwrap != null ? unwrap : left;
959 expr = Convert.ImplicitConversion (ec, left_null, rtype, loc);
966 Binary.Error_OperatorCannotBeApplied (loc, "??", ltype, rtype);
970 public override void Emit (EmitContext ec)
972 ILGenerator ig = ec.ig;
974 Label is_null_label = ig.DefineLabel ();
975 Label end_label = ig.DefineLabel ();
977 if (unwrap != null) {
978 unwrap.EmitCheck (ec);
979 ig.Emit (OpCodes.Brfalse, is_null_label);
982 ig.Emit (OpCodes.Br, end_label);
984 ig.MarkLabel (is_null_label);
987 ig.MarkLabel (end_label);
990 ig.Emit (OpCodes.Dup);
991 ig.Emit (OpCodes.Brtrue, end_label);
993 ig.MarkLabel (is_null_label);
995 ig.Emit (OpCodes.Pop);
998 ig.MarkLabel (end_label);
1001 protected override void CloneTo (CloneContext clonectx, Expression t)
1003 NullCoalescingOperator target = (NullCoalescingOperator) t;
1005 target.left = left.Clone (clonectx);
1006 target.right = right.Clone (clonectx);
1010 public class LiftedUnaryMutator : ExpressionStatement
1012 public readonly UnaryMutator.Mode Mode;
1013 Expression expr, null_value;
1014 UnaryMutator underlying;
1017 public LiftedUnaryMutator (UnaryMutator.Mode mode, Expression expr, Location loc)
1023 eclass = ExprClass.Value;
1026 public override Expression DoResolve (EmitContext ec)
1028 expr = expr.Resolve (ec);
1032 unwrap = Unwrap.Create (expr, ec);
1036 underlying = (UnaryMutator) new UnaryMutator (Mode, unwrap, loc).Resolve (ec);
1037 if (underlying == null)
1041 null_value = LiftedNull.Create (type, loc);
1045 void DoEmit (EmitContext ec, bool is_expr)
1047 ILGenerator ig = ec.ig;
1048 Label is_null_label = ig.DefineLabel ();
1049 Label end_label = ig.DefineLabel ();
1051 unwrap.EmitCheck (ec);
1052 ig.Emit (OpCodes.Brfalse, is_null_label);
1055 underlying.Emit (ec);
1057 underlying.EmitStatement (ec);
1058 ig.Emit (OpCodes.Br, end_label);
1060 ig.MarkLabel (is_null_label);
1062 null_value.Emit (ec);
1064 ig.MarkLabel (end_label);
1067 public override void Emit (EmitContext ec)
1072 public override void EmitStatement (EmitContext ec)