コード例 #1
0
        public override void Emit(EmitContext ec)
        {
            var call = new CallEmitter();

            call.InstanceExpression = Child;
            call.EmitPredefined(ec, NullableInfo.GetValue(Child.Type), null);
        }
コード例 #2
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);
        }
コード例 #3
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);
        }
コード例 #4
0
        Unwrap(Expression expr, bool useDefaultValue)
        {
            this.expr            = expr;
            this.loc             = expr.Location;
            this.useDefaultValue = useDefaultValue;

            type   = NullableInfo.GetUnderlyingType(expr.Type);
            eclass = expr.eclass;
        }
コード例 #5
0
        public void EmitCheck(EmitContext ec)
        {
            Store(ec);

            var call = new CallEmitter();

            call.InstanceExpression = this;

            call.EmitPredefined(ec, NullableInfo.GetHasValue(expr.Type), null);
        }
コード例 #6
0
        protected override Expression DoResolve(ResolveContext rc)
        {
            base.DoResolve(rc);

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

            return(this);
        }
コード例 #7
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));
        }
コード例 #8
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);
        }
コード例 #9
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);
            }
        }
コード例 #10
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, 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);
        }
コード例 #11
0
 public override void Emit(EmitContext ec)
 {
     child.Emit(ec);
     ec.Emit(OpCodes.Newobj, NullableInfo.GetConstructor(type));
 }
コード例 #12
0
        Expression LiftResult(ResolveContext ec, Expression res_expr)
        {
            TypeSpec 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).ResolveAsType(ec);
                if (lifted_type == null)
                {
                    return(null);
                }

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

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

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

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

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

                wrap_ctor = NullableInfo.GetConstructor(lifted_type);
                type      = res_expr.Type = lifted_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);
        }