Example #1
0
        public override void Emit(EmitContext ec)
        {
            Label is_null_label = ec.DefineLabel();
            Label end_label     = ec.DefineLabel();

            unwrap.EmitCheck(ec);
            ec.Emit(OpCodes.Brfalse, is_null_label);

            if (user_operator != null)
            {
                user_operator.Emit(ec);
            }
            else
            {
                EmitOperator(ec, NullableInfo.GetUnderlyingType(type));
            }

            ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type));
            ec.Emit(OpCodes.Br_S, end_label);

            ec.MarkLabel(is_null_label);
            LiftedNull.Create(type, loc).Emit(ec);

            ec.MarkLabel(end_label);
        }
Example #2
0
        public override void Emit(EmitContext ec)
        {
            ILGenerator ig            = ec.ig;
            Label       is_null_label = ig.DefineLabel();
            Label       end_label     = ig.DefineLabel();

            unwrap.EmitCheck(ec);
            ig.Emit(OpCodes.Brfalse, is_null_label);

            NullableInfo ni = new NullableInfo(type);

            if (user_operator != null)
            {
                user_operator.Emit(ec);
            }
            else
            {
                EmitOperator(ec, ni.UnderlyingType);
            }

            ig.Emit(OpCodes.Newobj, ni.Constructor);
            ig.Emit(OpCodes.Br_S, end_label);

            ig.MarkLabel(is_null_label);
            LiftedNull.Create(type, loc).Emit(ec);

            ig.MarkLabel(end_label);
        }
Example #3
0
        public override void Emit(EmitContext ec)
        {
            var call = new CallEmitter();

            call.InstanceExpression = Child;
            call.EmitPredefined(ec, NullableInfo.GetValue(Child.Type), null);
        }
Example #4
0
        protected override void EmitOperation(EmitContext ec)
        {
            Label is_null_label = ec.DefineLabel();
            Label end_label     = ec.DefineLabel();

            LocalTemporary lt = new LocalTemporary(type);

            // Value is on the stack
            lt.Store(ec);

            var call = new CallEmitter();

            call.InstanceExpression = lt;
            call.EmitPredefined(ec, NullableInfo.GetHasValue(expr.Type), null);

            ec.Emit(OpCodes.Brfalse, is_null_label);

            call = new CallEmitter();
            call.InstanceExpression = lt;
            call.EmitPredefined(ec, NullableInfo.GetGetValueOrDefault(expr.Type), null);

            lt.Release(ec);

            base.EmitOperation(ec);

            ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type));
            ec.Emit(OpCodes.Br_S, end_label);

            ec.MarkLabel(is_null_label);
            LiftedNull.Create(type, loc).Emit(ec);

            ec.MarkLabel(end_label);
        }
Example #5
0
        protected override Expression DoResolve(ResolveContext rc)
        {
            base.DoResolve (rc);

            if (type != null)
                type = NullableInfo.GetUnderlyingType (type);

            return this;
        }
Example #6
0
            public InternalWrap(Expression expr, NullableInfo info, Location loc)
            {
                this.expr = expr;
                this.info = info;
                this.loc  = loc;

                type   = info.Type;
                eclass = ExprClass.Value;
            }
Example #7
0
        protected Unwrap(Expression expr)
        {
            this.expr = expr;
            this.loc  = expr.Location;

            info   = new NullableInfo(expr.Type);
            type   = info.UnderlyingType;
            eclass = expr.eclass;
        }
Example #8
0
        public void EmitCheck(EmitContext ec)
        {
            Store (ec);

            var call = new CallEmitter ();
            call.InstanceExpression = this;

            call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null);
        }
Example #9
0
        public Unwrap(Expression expr, bool useDefaultValue = true)
        {
            this.expr            = expr;
            this.loc             = expr.Location;
            this.useDefaultValue = useDefaultValue;

            type   = NullableInfo.GetUnderlyingType(expr.Type);
            eclass = expr.eclass;
        }
Example #10
0
        Unwrap(Expression expr, bool useDefaultValue)
        {
            this.expr            = expr;
            this.loc             = expr.Location;
            this.useDefaultValue = useDefaultValue;

            info   = new NullableInfo(expr.Type);
            type   = info.UnderlyingType;
            eclass = expr.eclass;
        }
Example #11
0
        public static Expression Create(Expression expr, TypeSpec type)
        {
            //
            // Avoid unwraping and wraping of the same type
            //
            Unwrap unwrap = expr as Unwrap;
            if (unwrap != null && expr.Type == NullableInfo.GetUnderlyingType (type))
                return unwrap.Original;

            return new Wrap (expr, type);
        }
Example #12
0
 public override void Emit(EmitContext ec)
 {
     Store(ec);
     if (useDefaultValue)
     {
         Invocation.EmitCall(ec, this, NullableInfo.GetGetValueOrDefault(expr.Type), null, loc);
     }
     else
     {
         Invocation.EmitCall(ec, this, NullableInfo.GetValue(expr.Type), null, loc);
     }
 }
Example #13
0
        Expression LiftOperand(ResolveContext rc, Expression expr)
        {
            TypeSpec type;
            if (expr.IsNull) {
                type = Left.IsNull ? Right.Type : Left.Type;
            } else {
                type = expr.Type;
            }

            if (!type.IsNullableType)
                type = NullableInfo.MakeType (rc.Module, type);

            return Wrap.Create (expr, type);
        }
Example #14
0
        public override void Emit(EmitContext ec)
        {
            Label end_label = ec.DefineLabel();

            if (unwrap != null)
            {
                Label is_null_label = ec.DefineLabel();

                unwrap.EmitCheck(ec);
                ec.Emit(OpCodes.Brfalse, is_null_label);

                //
                // When both expressions are nullable the unwrap
                // is needed only for null check not for value uwrap
                //
                if (type.IsNullableType && TypeSpecComparer.IsEqual(NullableInfo.GetUnderlyingType(type), unwrap.Type))
                {
                    unwrap.Load(ec);
                }
                else
                {
                    left.Emit(ec);
                }

                ec.Emit(OpCodes.Br, end_label);

                ec.MarkLabel(is_null_label);
                right.Emit(ec);

                ec.MarkLabel(end_label);
                return;
            }

            left.Emit(ec);
            ec.Emit(OpCodes.Dup);

            // Only to make verifier happy
            if (left.Type.IsGenericParameter)
            {
                ec.Emit(OpCodes.Box, left.Type);
            }

            ec.Emit(OpCodes.Brtrue, end_label);

            ec.Emit(OpCodes.Pop);
            right.Emit(ec);

            ec.MarkLabel(end_label);
        }
Example #15
0
        public override void Emit(EmitContext ec)
        {
            Store(ec);

            var call = new CallEmitter();

            call.InstanceExpression = this;

            if (useDefaultValue)
            {
                call.EmitPredefined(ec, NullableInfo.GetGetValueOrDefault(expr.Type), null);
            }
            else
            {
                call.EmitPredefined(ec, NullableInfo.GetValue(expr.Type), null);
            }
        }
Example #16
0
        public override void Emit(EmitContext ec)
        {
            Store (ec);

            var call = new CallEmitter ();
            call.InstanceExpression = this;

            //
            // Using GetGetValueOrDefault is prefered because JIT can possibly
            // inline it whereas Value property contains a throw which is very
            // unlikely to be inlined
            //
            if (useDefaultValue)
                call.EmitPredefined (ec, NullableInfo.GetGetValueOrDefault (expr.Type), null);
            else
                call.EmitPredefined (ec, NullableInfo.GetValue (expr.Type), null);
        }
Example #17
0
        protected override void EmitOperator(EmitContext ec, TypeSpec l)
        {
            if (user_operator != null)
            {
                user_operator.Emit(ec);
                return;
            }

            if (left.Type.IsNullableType)
            {
                l    = NullableInfo.GetUnderlyingType(left.Type);
                left = EmptyCast.Create(left, l);
            }

            if (right.Type.IsNullableType)
            {
                right = EmptyCast.Create(right, NullableInfo.GetUnderlyingType(right.Type));
            }

            base.EmitOperator(ec, l);
        }
Example #18
0
			public InternalWrap (Expression expr, NullableInfo info, Location loc)
			{
				this.expr = expr;
				this.info = info;
				this.loc = loc;

				type = info.Type;
				eclass = ExprClass.Value;
			}
Example #19
0
        void EmitBitwiseBoolean(EmitContext ec)
        {
            Label load_left  = ec.DefineLabel();
            Label load_right = ec.DefineLabel();
            Label end_label  = ec.DefineLabel();

            // null & value, null | value
            if (left_unwrap == null)
            {
                left_unwrap  = right_unwrap;
                right_unwrap = null;
                right        = left;
            }

            left_unwrap.Emit(ec);
            ec.Emit(OpCodes.Brtrue_S, load_right);

            // value & null, value | null
            if (right_unwrap != null)
            {
                right_unwrap.Emit(ec);
                ec.Emit(OpCodes.Brtrue_S, load_left);
            }

            left_unwrap.EmitCheck(ec);
            ec.Emit(OpCodes.Brfalse_S, load_right);

            // load left
            ec.MarkLabel(load_left);

            if (Oper == Operator.BitwiseAnd)
            {
                left_unwrap.Load(ec);
            }
            else
            {
                if (right_unwrap == null)
                {
                    right.Emit(ec);
                    if (right is EmptyConstantCast || right is EmptyCast)
                    {
                        ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type));
                    }
                }
                else
                {
                    right_unwrap.Load(ec);
                    right_unwrap = left_unwrap;
                }
            }
            ec.Emit(OpCodes.Br_S, end_label);

            // load right
            ec.MarkLabel(load_right);
            if (right_unwrap == null)
            {
                if (Oper == Operator.BitwiseAnd)
                {
                    right.Emit(ec);
                    if (right is EmptyConstantCast || right is EmptyCast)
                    {
                        ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type));
                    }
                }
                else
                {
                    left_unwrap.Load(ec);
                }
            }
            else
            {
                right_unwrap.Load(ec);
            }

            ec.MarkLabel(end_label);
        }
Example #20
0
 public override void Emit(EmitContext ec)
 {
     Invocation.EmitCall(ec, Child, NullableInfo.GetValue(Child.Type), null, loc);
 }
Example #21
0
 public void EmitCheck(EmitContext ec)
 {
     Store(ec);
     Invocation.EmitCall(ec, this, NullableInfo.GetHasValue(expr.Type), null, loc);
 }
Example #22
0
        Expression LiftResult(ResolveContext ec, Expression res_expr)
        {
            TypeExpr lifted_type;

            //
            // Avoid double conversion
            //
            if (left_unwrap == null || IsLeftNullLifted || left_unwrap.Type != left.Type || (left_unwrap != null && IsRightNullLifted))
            {
                lifted_type = new NullableType(left.Type, loc);
                lifted_type = lifted_type.ResolveAsTypeTerminal(ec, false);
                if (lifted_type == null)
                {
                    return(null);
                }

                if (left is UserCast || left is TypeCast)
                {
                    left.Type = lifted_type.Type;
                }
                else
                {
                    left = EmptyCast.Create(left, lifted_type.Type);
                }
            }

            if (left != right && (right_unwrap == null || IsRightNullLifted || right_unwrap.Type != right.Type || (right_unwrap != null && IsLeftNullLifted)))
            {
                lifted_type = new NullableType(right.Type, loc);
                lifted_type = lifted_type.ResolveAsTypeTerminal(ec, false);
                if (lifted_type == null)
                {
                    return(null);
                }

                var r = right;
                if (r is ReducedExpression)
                {
                    r = ((ReducedExpression)r).OriginalExpression;
                }

                if (r is UserCast || r is TypeCast)
                {
                    r.Type = lifted_type.Type;
                }
                else
                {
                    right = EmptyCast.Create(right, lifted_type.Type);
                }
            }

            if ((Oper & Operator.ComparisonMask) == 0)
            {
                lifted_type = new NullableType(res_expr.Type, loc);
                lifted_type = lifted_type.ResolveAsTypeTerminal(ec, false);
                if (lifted_type == null)
                {
                    return(null);
                }

                wrap_ctor = NullableInfo.GetConstructor(lifted_type.Type);
                type      = res_expr.Type = lifted_type.Type;
            }

            if (IsLeftNullLifted)
            {
                left = LiftedNull.Create(right.Type, left.Location);

                //
                // Special case for bool?, the result depends on both null right side and left side value
                //
                if ((Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) && NullableInfo.GetUnderlyingType(type).BuiltinType == BuiltinTypeSpec.Type.Bool)
                {
                    return(res_expr);
                }

                if ((Oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0)
                {
                    return(LiftedNull.CreateFromExpression(ec, res_expr));
                }

                //
                // Value types and null comparison
                //
                if (right_unwrap == null || (Oper & Operator.RelationalMask) != 0)
                {
                    return(CreateNullConstant(ec, right_orig));
                }
            }

            if (IsRightNullLifted)
            {
                right = LiftedNull.Create(left.Type, right.Location);

                //
                // Special case for bool?, the result depends on both null right side and left side value
                //
                if ((Oper == Operator.BitwiseAnd || Oper == Operator.BitwiseOr) && NullableInfo.GetUnderlyingType(type).BuiltinType == BuiltinTypeSpec.Type.Bool)
                {
                    return(res_expr);
                }

                if ((Oper & (Operator.ArithmeticMask | Operator.ShiftMask | Operator.BitwiseMask)) != 0)
                {
                    return(LiftedNull.CreateFromExpression(ec, res_expr));
                }

                //
                // Value types and null comparison
                //
                if (left_unwrap == null || (Oper & Operator.RelationalMask) != 0)
                {
                    return(CreateNullConstant(ec, left_orig));
                }
            }

            return(res_expr);
        }
Example #23
0
		protected Unwrap (Expression expr)
		{
			this.expr = expr;
			this.loc = expr.Location;

			info = new NullableInfo (expr.Type);
			type = info.UnderlyingType;
			eclass = expr.eclass;
		}
Example #24
0
		public override void Emit (EmitContext ec)
		{
			ILGenerator ig = ec.ig;
			Label is_null_label = ig.DefineLabel ();
			Label end_label = ig.DefineLabel ();

			unwrap.EmitCheck (ec);
			ig.Emit (OpCodes.Brfalse, is_null_label);

			NullableInfo ni = new NullableInfo (type);

			if (user_operator != null) {
				user_operator.Emit (ec);
			} else {
				EmitOperator (ec, ni.UnderlyingType);
			}

			ig.Emit (OpCodes.Newobj, ni.Constructor);
			ig.Emit (OpCodes.Br_S, end_label);

			ig.MarkLabel (is_null_label);
			LiftedNull.Create (type, loc).Emit (ec);

			ig.MarkLabel (end_label);
		}
Example #25
0
 protected Wrap(Expression expr, Type type)
     : base(expr, type)
 {
     info   = new NullableInfo(type);
     eclass = ExprClass.Value;
 }
Example #26
0
        public override void Emit(EmitContext ec)
        {
            if (IsBitwiseBoolean && UserOperator == null)
            {
                EmitBitwiseBoolean(ec);
                return;
            }

            if ((Binary.Oper & Binary.Operator.EqualityMask) != 0)
            {
                EmitEquality(ec);
                return;
            }

            Label is_null_label = ec.DefineLabel();
            Label end_label     = ec.DefineLabel();

            if (ec.HasSet(BuilderContext.Options.AsyncBody) && Right.ContainsEmitWithAwait())
            {
                Left  = Left.EmitToField(ec);
                Right = Right.EmitToField(ec);
            }

            if (UnwrapLeft != null)
            {
                UnwrapLeft.EmitCheck(ec);
            }

            //
            // Don't emit HasValue check when left and right expressions are same
            //
            if (UnwrapRight != null && !Binary.Left.Equals(Binary.Right))
            {
                UnwrapRight.EmitCheck(ec);
                if (UnwrapLeft != null)
                {
                    ec.Emit(OpCodes.And);
                }
            }

            ec.Emit(OpCodes.Brfalse, is_null_label);

            if (UserOperator != null)
            {
                var args = new Arguments(2);
                args.Add(new Argument(Left));
                args.Add(new Argument(Right));

                var call = new CallEmitter();
                call.EmitPredefined(ec, UserOperator, args);
            }
            else
            {
                Binary.EmitOperator(ec, Left, Right);
            }

            //
            // Wrap the result when the operator return type is nullable type
            //
            if (type.IsNullableType)
            {
                ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type));
            }

            ec.Emit(OpCodes.Br_S, end_label);
            ec.MarkLabel(is_null_label);

            if ((Binary.Oper & Binary.Operator.ComparisonMask) != 0)
            {
                ec.EmitInt(0);
            }
            else
            {
                LiftedNull.Create(type, loc).Emit(ec);
            }

            ec.MarkLabel(end_label);
        }
Example #27
0
        public override void Emit(EmitContext ec)
        {
            Label end_label = ec.DefineLabel();

            if (unwrap != null)
            {
                Label is_null_label = ec.DefineLabel();

                unwrap.EmitCheck(ec);
                ec.Emit(OpCodes.Brfalse, is_null_label);

                //
                // When both expressions are nullable the unwrap
                // is needed only for null check not for value uwrap
                //
                if (type.IsNullableType && TypeSpecComparer.IsEqual(NullableInfo.GetUnderlyingType(type), unwrap.Type))
                {
                    unwrap.Load(ec);
                }
                else
                {
                    left.Emit(ec);
                }

                ec.Emit(OpCodes.Br, end_label);

                ec.MarkLabel(is_null_label);
                right.Emit(ec);

                ec.MarkLabel(end_label);
                return;
            }

            //
            // Null check is done on original expression not after expression is converted to
            // result type. This is in most cases same but when user conversion is involved
            // we can end up in situation when user operator does the null handling which is
            // not what the operator is supposed to do.
            // There is tricky case where cast of left expression is meant to be cast of
            // whole source expression (null check is done on it) and cast from right-to-left
            // conversion needs to do null check on unconverted source expression.
            //
            if (user_conversion_left)
            {
                var op_expr = (UserCast)left;

                op_expr.Source.Emit(ec);
                LocalTemporary temp;

                // TODO: More load kinds can be special cased
                if (!(op_expr.Source is VariableReference))
                {
                    temp = new LocalTemporary(op_expr.Source.Type);
                    temp.Store(ec);
                    temp.Emit(ec);
                    op_expr.Source = temp;
                }
                else
                {
                    temp = null;
                }

                var right_label = ec.DefineLabel();
                ec.Emit(OpCodes.Brfalse_S, right_label);
                left.Emit(ec);
                ec.Emit(OpCodes.Br, end_label);
                ec.MarkLabel(right_label);

                if (temp != null)
                {
                    temp.Release(ec);
                }
            }
            else
            {
                //
                // Common case where expression is not modified before null check and
                // we generate better/smaller code
                //
                left.Emit(ec);
                ec.Emit(OpCodes.Dup);

                // Only to make verifier happy
                if (left.Type.IsGenericParameter)
                {
                    ec.Emit(OpCodes.Box, left.Type);
                }

                ec.Emit(OpCodes.Brtrue, end_label);

                ec.Emit(OpCodes.Pop);
            }

            right.Emit(ec);

            ec.MarkLabel(end_label);
        }
Example #28
0
 public override void Emit(EmitContext ec)
 {
     child.Emit(ec);
     ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type));
 }
Example #29
0
		protected Wrap (Expression expr, Type type)
			: base (expr, type)
		{
			info = new NullableInfo (type);
			eclass = ExprClass.Value;
		}
Example #30
0
        void EmitBitwiseBoolean(EmitContext ec)
        {
            Label load_left     = ec.DefineLabel();
            Label load_right    = ec.DefineLabel();
            Label end_label     = ec.DefineLabel();
            Label is_null_label = ec.DefineLabel();

            bool or = Binary.Oper == Binary.Operator.BitwiseOr;

            //
            // Both operands are bool? types
            //
            if ((UnwrapLeft != null && !Left.IsNull) && (UnwrapRight != null && !Right.IsNull))
            {
                if (ec.HasSet(BuilderContext.Options.AsyncBody) && Binary.Right.ContainsEmitWithAwait())
                {
                    Left  = Left.EmitToField(ec);
                    Right = Right.EmitToField(ec);
                }
                else
                {
                    UnwrapLeft.Store(ec);
                    UnwrapRight.Store(ec);
                }

                Left.Emit(ec);
                ec.Emit(OpCodes.Brtrue_S, load_right);

                Right.Emit(ec);
                ec.Emit(OpCodes.Brtrue_S, load_left);

                UnwrapLeft.EmitCheck(ec);
                ec.Emit(OpCodes.Brfalse_S, load_right);

                // load left
                ec.MarkLabel(load_left);
                if (or)
                {
                    UnwrapRight.Load(ec);
                }
                else
                {
                    UnwrapLeft.Load(ec);
                }

                ec.Emit(OpCodes.Br_S, end_label);

                // load right
                ec.MarkLabel(load_right);
                if (or)
                {
                    UnwrapLeft.Load(ec);
                }
                else
                {
                    UnwrapRight.Load(ec);
                }

                ec.MarkLabel(end_label);
                return;
            }

            //
            // Faster version when one operand is bool
            //
            if (UnwrapLeft == null)
            {
                //
                // (bool, bool?)
                //
                // Optimizes remaining (false & bool?), (true | bool?) which are not easy to handle
                // in binary expression reduction
                //
                var c = Left as BoolConstant;
                if (c != null)
                {
                    // Keep evaluation order
                    UnwrapRight.Store(ec);

                    ec.EmitInt(or ? 1 : 0);
                    ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type));
                }
                else if (Left.IsNull)
                {
                    UnwrapRight.Emit(ec);
                    ec.Emit(or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, is_null_label);

                    UnwrapRight.Load(ec);
                    ec.Emit(OpCodes.Br_S, end_label);

                    ec.MarkLabel(is_null_label);
                    LiftedNull.Create(type, loc).Emit(ec);
                }
                else
                {
                    Left.Emit(ec);
                    UnwrapRight.Store(ec);

                    ec.Emit(or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, load_right);

                    ec.EmitInt(or ? 1 : 0);
                    ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type));

                    ec.Emit(OpCodes.Br_S, end_label);

                    ec.MarkLabel(load_right);
                    UnwrapRight.Load(ec);
                }
            }
            else
            {
                //
                // (bool?, bool)
                //
                // Keep left-right evaluation order
                UnwrapLeft.Store(ec);

                //
                // Optimizes remaining (bool? & false), (bool? | true) which are not easy to handle
                // in binary expression reduction
                //
                var c = Right as BoolConstant;
                if (c != null)
                {
                    ec.EmitInt(or ? 1 : 0);
                    ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type));
                }
                else if (Right.IsNull)
                {
                    UnwrapLeft.Emit(ec);
                    ec.Emit(or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, is_null_label);

                    UnwrapLeft.Load(ec);
                    ec.Emit(OpCodes.Br_S, end_label);

                    ec.MarkLabel(is_null_label);
                    LiftedNull.Create(type, loc).Emit(ec);
                }
                else
                {
                    Right.Emit(ec);
                    ec.Emit(or ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, load_left);

                    ec.EmitInt(or ? 1 : 0);
                    ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type));

                    ec.Emit(OpCodes.Br_S, end_label);

                    ec.MarkLabel(load_left);

                    UnwrapLeft.Load(ec);
                }
            }

            ec.MarkLabel(end_label);
        }
		Unwrap (Expression expr, bool useDefaultValue)
		{
			this.expr = expr;
			this.loc = expr.Location;
			this.useDefaultValue = useDefaultValue;

			info = new NullableInfo (expr.Type);
			type = info.UnderlyingType;
			eclass = expr.eclass;
		}