public override BoundNode VisitConversion(BoundConversion node)
        {
            BoundExpression operand = (BoundExpression)this.Visit(node.Operand);
            TypeSymbol      type    = this.VisitType(node.Type);

            if (operand.Kind != BoundKind.SpillSequence)
            {
                return(node.Update(operand, node.ConversionKind, node.SymbolOpt, node.Checked, node.ExplicitCastInCode, node.IsExtensionMethod, node.IsArrayIndex, node.ConstantValueOpt, node.ResultKind, type));
            }

            var spill = (BoundSpillSequence)operand;

            return(RewriteSpillSequence(spill,
                                        node.Update(
                                            spill.Value,
                                            node.ConversionKind,
                                            node.SymbolOpt,
                                            node.Checked,
                                            node.ExplicitCastInCode,
                                            node.IsExtensionMethod,
                                            node.IsArrayIndex,
                                            node.ConstantValueOpt,
                                            node.ResultKind,
                                            type)));
        }
        public override BoundNode VisitConversion(BoundConversion node)
        {
            BoundSpillSequence2 ss = null;
            var operand            = VisitExpression(ref ss, node.Operand);

            return(UpdateExpression(ss, node.Update(operand, node.ConversionKind, node.SymbolOpt, node.Checked, node.ExplicitCastInCode, node.IsExtensionMethod, node.IsArrayIndex, node.ConstantValueOpt, node.ResultKind, node.Type)));
        }
Beispiel #3
0
        public override BoundNode VisitConversion(BoundConversion node)
        {
            BoundSpillSequenceBuilder builder = null;
            var operand = VisitExpression(ref builder, node.Operand);

            return(UpdateExpression(
                       builder,
                       node.Update(
                           operand,
                           node.Conversion,
                           isBaseConversion: node.IsBaseConversion,
                           @checked: node.Checked,
                           explicitCastInCode: node.ExplicitCastInCode,
                           constantValueOpt: node.ConstantValueOpt,
                           type: node.Type)));
        }
Beispiel #4
0
        public override BoundNode VisitConversion(BoundConversion node)
        {
            BoundSpillSequenceBuilder builder = null;
            var operand = VisitExpression(ref builder, node.Operand);

            return(UpdateExpression(
                       builder,
                       node.Update(
                           operand,
                           node.ConversionKind,
                           node.ResultKind,
                           isBaseConversion: node.IsBaseConversion,
                           symbolOpt: node.SymbolOpt,
                           @checked: node.Checked,
                           explicitCastInCode: node.ExplicitCastInCode,
                           isExtensionMethod: node.IsExtensionMethod,
                           isArrayIndex: node.IsArrayIndex,
                           constantValueOpt: node.ConstantValueOpt,
                           type: node.Type)));
        }
Beispiel #5
0
 public override BoundNode VisitConversion(BoundConversion node)
 {
     BoundSpillSequence2 ss = null;
     var operand = VisitExpression(ref ss, node.Operand);
     return UpdateExpression(
         ss,
         node.Update(
             operand,
             node.ConversionKind,
             node.ResultKind,
             isBaseConversion: node.IsBaseConversion,
             symbolOpt: node.SymbolOpt,
             @checked: node.Checked,
             explicitCastInCode: node.ExplicitCastInCode,
             isExtensionMethod: node.IsExtensionMethod,
             isArrayIndex: node.IsArrayIndex,
             constantValueOpt: node.ConstantValueOpt,
             type: node.Type));
 }
        private BoundExpression RewriteIntPtrConversion(
            BoundConversion oldNode,
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenOperand,
            ConversionKind conversionKind,
            MethodSymbol symbolOpt,
            bool @checked,
            bool explicitCastInCode,
            bool isExtensionMethod,
            bool isArrayIndex,
            ConstantValue constantValueOpt,
            TypeSymbol rewrittenType)
        {
            Debug.Assert(rewrittenOperand != null);
            Debug.Assert((object)rewrittenType != null);

            TypeSymbol source = rewrittenOperand.Type;
            TypeSymbol target = rewrittenType;

            TypeSymbol t0 = target.StrippedType();
            TypeSymbol s0 = source.StrippedType();

            if (t0 != target && s0 != source)
            {
                // UNDONE: RewriteLiftedIntPtrConversion

                return oldNode != null ?
                    oldNode.Update(
                        rewrittenOperand,
                        conversionKind,
                        oldNode.ResultKind,
                        isBaseConversion: oldNode.IsBaseConversion,
                        symbolOpt: symbolOpt,
                        @checked: @checked,
                        explicitCastInCode: explicitCastInCode,
                        isExtensionMethod: isExtensionMethod,
                        isArrayIndex: isArrayIndex,
                        constantValueOpt: constantValueOpt,
                        type: rewrittenType) :
                    new BoundConversion(
                        syntax,
                        rewrittenOperand,
                        conversionKind,
                        LookupResultKind.Viable,
                        isBaseConversion: false,
                        symbolOpt: symbolOpt,
                        @checked: @checked,
                        explicitCastInCode: explicitCastInCode,
                        isExtensionMethod: isExtensionMethod,
                        isArrayIndex: isArrayIndex,
                        constantValueOpt: constantValueOpt,
                        type: rewrittenType);
            }

            SpecialMember member = GetIntPtrConversionMethod(source: rewrittenOperand.Type, target: rewrittenType);
            MethodSymbol method = GetSpecialTypeMethod(syntax, member);
            Debug.Assert(!method.ReturnsVoid);
            Debug.Assert(method.ParameterCount == 1);

            rewrittenOperand = MakeConversion(rewrittenOperand, method.ParameterTypes[0], @checked);

            var returnType = method.ReturnType;
            Debug.Assert((object)returnType != null);

            if (inExpressionLambda)
            {
                return BoundConversion.Synthesized(syntax, rewrittenOperand, new Conversion(conversionKind, method, false), @checked, explicitCastInCode, constantValueOpt, rewrittenType);
            }

            var rewrittenCall =
                inExpressionLambda && oldNode != null
                ? new BoundConversion(syntax, rewrittenOperand, new Conversion(conversionKind, method, false), @checked, explicitCastInCode, constantValueOpt, returnType)
                : MakeCall(
                    syntax: syntax,
                    rewrittenReceiver: null,
                    method: method,
                    rewrittenArguments: ImmutableArray.Create<BoundExpression>(rewrittenOperand),
                    type: returnType);

            return MakeConversion(rewrittenCall, rewrittenType, @checked);
        }
        /// <summary>
        /// Helper method to generate a lowered conversion.
        /// </summary>
        private BoundExpression MakeConversion(
            BoundConversion oldNode,
            CSharpSyntaxNode syntax,
            BoundExpression rewrittenOperand,
            ConversionKind conversionKind,
            MethodSymbol symbolOpt,
            bool @checked,
            bool explicitCastInCode,
            bool isExtensionMethod,
            bool isArrayIndex,
            ConstantValue constantValueOpt,
            TypeSymbol rewrittenType)
        {
            Debug.Assert(oldNode == null || oldNode.Syntax == syntax);
            Debug.Assert((object)rewrittenType != null);
            @checked = @checked &&
                (inExpressionLambda && (explicitCastInCode || DistinctSpecialTypes(rewrittenOperand.Type, rewrittenType)) ||
                NeedsChecked(rewrittenOperand.Type, rewrittenType));

            switch (conversionKind)
            {
                case ConversionKind.Identity:

                    // Spec 6.1.1:
                    //   An identity conversion converts from any type to the same type. 
                    //   This conversion exists such that an entity that already has a required type can be said to be convertible to that type.
                    //   Because object and dynamic are considered equivalent there is an identity conversion between object and dynamic, 
                    //   and between constructed types that are the same when replacing all occurrences of dynamic with object.

                    // Why ignoreDynamic: false?
                    // Lowering phase treats object and dynamic as equivalent types. So we don't need to produce any conversion here,
                    // but we need to change the Type property on the resulting BoundExpression to match the rewrittenType.
                    // This is necessary so that subsequent lowering transformations see that the expression is dynamic.

                    if (inExpressionLambda || !rewrittenOperand.Type.Equals(rewrittenType, ignoreCustomModifiers: false, ignoreDynamic: false))
                    {
                        break;
                    }

                    // 4.1.6 C# spec: To force a value of a floating point type to the exact precision of its type, an explicit cast can be used.
                    // If this is not an identity conversion of a float with unknown precision, strip away the identity conversion.
                    if (!(explicitCastInCode && IsFloatPointExpressionOfUnknownPrecision(rewrittenOperand)))
                    {
                        return rewrittenOperand;
                    }

                    break;

                case ConversionKind.ExplicitUserDefined:
                case ConversionKind.ImplicitUserDefined:
                    return RewriteUserDefinedConversion(
                        syntax: syntax,
                        rewrittenOperand: rewrittenOperand,
                        method: symbolOpt,
                        rewrittenType: rewrittenType,
                        conversionKind: conversionKind);

                case ConversionKind.IntPtr:
                    return RewriteIntPtrConversion(oldNode, syntax, rewrittenOperand, conversionKind, symbolOpt, @checked,
                        explicitCastInCode, isExtensionMethod, isArrayIndex, constantValueOpt, rewrittenType);

                case ConversionKind.ImplicitNullable:
                case ConversionKind.ExplicitNullable:
                    return RewriteNullableConversion(
                        syntax: syntax,
                        rewrittenOperand: rewrittenOperand,
                        conversionKind: conversionKind,
                        @checked: @checked,
                        explicitCastInCode: explicitCastInCode,
                        rewrittenType: rewrittenType);

                case ConversionKind.Boxing:

                    if (!inExpressionLambda)
                    {
                        // We can perform some optimizations if we have a nullable value type
                        // as the operand and we know its nullability:

                        // * (object)new int?() is the same as (object)null
                        // * (object)new int?(123) is the same as (object)123

                        if (NullableNeverHasValue(rewrittenOperand))
                        {
                            return new BoundDefaultOperator(syntax, rewrittenType);
                        }

                        BoundExpression nullableValue = NullableAlwaysHasValue(rewrittenOperand);
                        if (nullableValue != null)
                        {
                            // Recurse, eliminating the unnecessary ctor.
                            return MakeConversion(oldNode, syntax, nullableValue, conversionKind,
                                symbolOpt, @checked, explicitCastInCode, isExtensionMethod, isArrayIndex,
                                constantValueOpt, rewrittenType);
                        }
                    }
                    break;

                case ConversionKind.NullLiteral:
                    if (!inExpressionLambda || !explicitCastInCode)
                    {
                        return new BoundDefaultOperator(syntax, rewrittenType);
                    }

                    break;

                case ConversionKind.ImplicitReference:
                case ConversionKind.ExplicitReference:
                    if (rewrittenOperand.IsDefaultValue() && (!inExpressionLambda || !explicitCastInCode))
                    {
                        return new BoundDefaultOperator(syntax, rewrittenType);
                    }

                    break;

                case ConversionKind.ImplicitNumeric:
                case ConversionKind.ExplicitNumeric:
                    if (rewrittenOperand.IsDefaultValue() && (!inExpressionLambda || !explicitCastInCode))
                    {
                        return new BoundDefaultOperator(syntax, rewrittenType);
                    }

                    if (rewrittenType.SpecialType == SpecialType.System_Decimal || rewrittenOperand.Type.SpecialType == SpecialType.System_Decimal)
                    {
                        return RewriteDecimalConversion(oldNode, syntax, rewrittenOperand, rewrittenOperand.Type, rewrittenType);
                    }
                    break;

                case ConversionKind.ImplicitEnumeration:
                    // A conversion from constant zero to nullable is actually classified as an 
                    // implicit enumeration conversion, not an implicit nullable conversion. 
                    // Lower it to (E?)(E)0.
                    if (rewrittenType.IsNullableType())
                    {
                        var operand = MakeConversion(
                            oldNode,
                            syntax,
                            rewrittenOperand,
                            ConversionKind.ImplicitEnumeration,
                            symbolOpt,
                            @checked,
                            explicitCastInCode,
                            isExtensionMethod,
                            false,
                            constantValueOpt,
                            rewrittenType.GetNullableUnderlyingType());

                        return MakeConversion(
                            oldNode,
                            syntax,
                            operand,
                            ConversionKind.ImplicitNullable,
                            symbolOpt,
                            @checked,
                            explicitCastInCode,
                            isExtensionMethod,
                            isArrayIndex,
                            constantValueOpt,
                            rewrittenType);
                    }

                    goto case ConversionKind.ExplicitEnumeration;

                case ConversionKind.ExplicitEnumeration:
                    if (!rewrittenType.IsNullableType() &&
                        rewrittenOperand.IsDefaultValue() &&
                        (!inExpressionLambda || !explicitCastInCode))
                    {
                        return new BoundDefaultOperator(syntax, rewrittenType);
                    }

                    if (rewrittenType.SpecialType == SpecialType.System_Decimal)
                    {
                        Debug.Assert(rewrittenOperand.Type.IsEnumType());
                        var underlyingTypeFrom = rewrittenOperand.Type.GetEnumUnderlyingType();
                        rewrittenOperand = MakeConversion(rewrittenOperand, underlyingTypeFrom, false);
                        return RewriteDecimalConversion(oldNode, syntax, rewrittenOperand, underlyingTypeFrom, rewrittenType);
                    }
                    else if (rewrittenOperand.Type.SpecialType == SpecialType.System_Decimal)
                    {
                        // This is where we handle conversion from Decimal to Enum: e.g., E e = (E) d;
                        // where 'e' is of type Enum E and 'd' is of type Decimal.
                        // Conversion can be simply done by applying its underlying numeric type to RewriteDecimalConversion(). 

                        Debug.Assert(rewrittenType.IsEnumType());
                        var underlyingTypeTo = rewrittenType.GetEnumUnderlyingType();
                        var rewrittenNode = RewriteDecimalConversion(oldNode, syntax, rewrittenOperand, rewrittenOperand.Type, underlyingTypeTo);

                        // However, the type of the rewritten node becomes underlying numeric type, not Enum type,
                        // which violates the overall constraint saying the type cannot be changed during rewriting (see LocalRewriter.cs).

                        // Instead of loosening this constraint, we return BoundConversion from underlying numeric type to Enum type,
                        // which will be eliminated during emitting (see EmitEnumConversion): e.g., E e = (E)(int) d;

                        return new BoundConversion(
                            syntax,
                            rewrittenNode,
                            conversionKind,
                            LookupResultKind.Viable,
                            isBaseConversion: false,
                            symbolOpt: symbolOpt,
                            @checked: false,
                            explicitCastInCode: explicitCastInCode,
                            isExtensionMethod: isExtensionMethod,
                            isArrayIndex: false,
                            constantValueOpt: constantValueOpt,
                            type: rewrittenType);
                    }

                    break;

                case ConversionKind.ImplicitDynamic:
                case ConversionKind.ExplicitDynamic:
                    Debug.Assert((object)symbolOpt == null);
                    Debug.Assert(!isExtensionMethod);
                    Debug.Assert(constantValueOpt == null);
                    return dynamicFactory.MakeDynamicConversion(rewrittenOperand, explicitCastInCode || conversionKind == ConversionKind.ExplicitDynamic, isArrayIndex, @checked, rewrittenType).ToExpression();

                default:
                    break;
            }

            return oldNode != null ?
                oldNode.Update(
                    rewrittenOperand,
                    conversionKind,
                    oldNode.ResultKind,
                    isBaseConversion: oldNode.IsBaseConversion,
                    symbolOpt: symbolOpt,
                    @checked: @checked,
                    explicitCastInCode: explicitCastInCode,
                    isExtensionMethod: isExtensionMethod,
                    isArrayIndex: isArrayIndex,
                    constantValueOpt: constantValueOpt,
                    type: rewrittenType) :
                new BoundConversion(
                    syntax,
                    rewrittenOperand,
                    conversionKind,
                    LookupResultKind.Viable,
                    isBaseConversion: false,
                    symbolOpt: symbolOpt,
                    @checked: @checked,
                    explicitCastInCode: explicitCastInCode,
                    isExtensionMethod: isExtensionMethod,
                    isArrayIndex: isArrayIndex,
                    constantValueOpt: constantValueOpt,
                    type: rewrittenType);
        }
        private BoundExpression RewriteDecimalConversion(BoundConversion oldNode, CSharpSyntaxNode syntax, BoundExpression operand, TypeSymbol fromType, TypeSymbol toType)
        {
            Debug.Assert(fromType.SpecialType == SpecialType.System_Decimal || toType.SpecialType == SpecialType.System_Decimal);

            // call the method
            SpecialMember member = DecimalConversionMethod(fromType, toType);
            var method = (MethodSymbol)this.compilation.Assembly.GetSpecialTypeMember(member);
            Debug.Assert((object)method != null); // Should have been checked during Warnings pass

            if (inExpressionLambda && oldNode != null)
            {
                ConversionKind conversionKind = oldNode.ConversionKind.IsImplicitConversion() ? ConversionKind.ImplicitUserDefined : ConversionKind.ExplicitUserDefined;
                return oldNode.Update(
                    operand,
                    conversionKind,
                    oldNode.ResultKind,
                    isBaseConversion: oldNode.IsBaseConversion,
                    symbolOpt: method,
                    @checked: oldNode.Checked,
                    explicitCastInCode: oldNode.ExplicitCastInCode,
                    isExtensionMethod: oldNode.IsExtensionMethod,
                    isArrayIndex: oldNode.IsArrayIndex,
                    constantValueOpt: oldNode.ConstantValueOpt,
                    type: toType);
            }
            else
            {
                Debug.Assert(method.ReturnType == toType);
                return BoundCall.Synthesized(syntax, null, method, operand);
            }
        }
        public override BoundNode VisitConversion(BoundConversion node)
        {
            BoundExpression operand = (BoundExpression)this.Visit(node.Operand);
            TypeSymbol type = this.VisitType(node.Type);

            if (operand.Kind != BoundKind.SpillSequence)
            {
                return node.Update(operand, node.ConversionKind, node.SymbolOpt, node.Checked, node.ExplicitCastInCode, node.IsExtensionMethod, node.IsArrayIndex, node.ConstantValueOpt, node.ResultKind, type);
            }

            var spill = (BoundSpillSequence)operand;
            return RewriteSpillSequence(spill,
                node.Update(
                    spill.Value,
                    node.ConversionKind,
                    node.SymbolOpt,
                    node.Checked,
                    node.ExplicitCastInCode,
                    node.IsExtensionMethod,
                    node.IsArrayIndex,
                    node.ConstantValueOpt,
                    node.ResultKind,
                    type));
        }