예제 #1
0
        private BoundExpression MakeLiteral(CSharpSyntaxNode syntax, ConstantValue constantValue, TypeSymbol type, BoundLiteral oldNodeOpt = null)
        {
            Debug.Assert(constantValue != null);

            if (constantValue.IsDecimal)
            {
                //  Rewrite decimal literal
                Debug.Assert((object)type != null);
                Debug.Assert(type.SpecialType == SpecialType.System_Decimal);

                return MakeDecimalLiteral(syntax, constantValue);
            }
            else if (constantValue.IsDateTime)
            {
                // C# does not support DateTime constants but VB does; we might have obtained a 
                // DateTime constant by calling a method with an optional parameter with a DateTime
                // for its default value.
                Debug.Assert((object)type != null);
                Debug.Assert(type.SpecialType == SpecialType.System_DateTime);
                return MakeDateTimeLiteral(syntax, constantValue);
            }
            else if (oldNodeOpt != null)
            {
                return oldNodeOpt.Update(constantValue, type);
            }
            else
            {
                return new BoundLiteral(syntax, constantValue, type, hasErrors: constantValue.IsBad);
            }
        }
예제 #2
0
        /// <summary>
        /// Finds the GetResult method of an Awaiter type.
        /// </summary>
        /// <remarks>
        /// Spec 7.7.7.1:
        /// An Awaiter A has an accessible instance method GetResult with no parameters and no type parameters.
        /// </remarks>
        private bool GetGetResultMethod(TypeSymbol awaiterType, CSharpSyntaxNode node, TypeSymbol awaitedExpressionType, DiagnosticBag diagnostics, out MethodSymbol getResultMethod)
        {
            var receiver = new BoundLiteral(node, ConstantValue.Null, awaiterType);
            var getResultCall = MakeInvocationExpression(node, receiver, WellKnownMemberNames.GetResult, ImmutableArray<BoundExpression>.Empty, diagnostics);
            if (getResultCall.HasAnyErrors)
            {
                getResultMethod = null;
                return false;
            }

            if (getResultCall.Kind != BoundKind.Call)
            {
                Error(diagnostics, ErrorCode.ERR_NoSuchMember, node, awaiterType, WellKnownMemberNames.GetResult);
                getResultMethod = null;
                return false;
            }

            getResultMethod = ((BoundCall)getResultCall).Method;
            if (getResultMethod.IsExtensionMethod)
            {
                Error(diagnostics, ErrorCode.ERR_NoSuchMember, node, awaiterType, WellKnownMemberNames.GetResult);
                getResultMethod = null;
                return false;
            }

            if (HasOptionalOrVariableParameters(getResultMethod) || getResultMethod.IsConditional)
            {
                Error(diagnostics, ErrorCode.ERR_BadAwaiterPattern, node, awaiterType, awaitedExpressionType);
                getResultMethod = null;
                return false;
            }

            // The lack of a GetResult method will be reported by ValidateGetResult().
            return true;
        }
예제 #3
0
        /// <summary>
        /// Finds the IsCompleted property of an Awaiter type.
        /// </summary>
        /// <remarks>
        /// Spec 7.7.7.1:
        /// An Awaiter A has an accessible, readable instance property IsCompleted of type bool.
        /// </remarks>
        private bool GetIsCompletedProperty(TypeSymbol awaiterType, CSharpSyntaxNode node, TypeSymbol awaitedExpressionType, DiagnosticBag diagnostics, out PropertySymbol isCompletedProperty)
        {
            var receiver = new BoundLiteral(node, ConstantValue.Null, awaiterType);
            var name = WellKnownMemberNames.IsCompleted;
            var qualified = BindInstanceMemberAccess(node, node, receiver, name, 0, default(SeparatedSyntaxList<TypeSyntax>), default(ImmutableArray<TypeSymbol>), false, diagnostics);
            if (qualified.HasAnyErrors)
            {
                isCompletedProperty = null;
                return false;
            }

            if (qualified.Kind != BoundKind.PropertyAccess)
            {
                Error(diagnostics, ErrorCode.ERR_NoSuchMember, node, awaiterType, WellKnownMemberNames.IsCompleted);
                isCompletedProperty = null;
                return false;
            }

            isCompletedProperty = ((BoundPropertyAccess)qualified).PropertySymbol;
            if (isCompletedProperty.IsWriteOnly)
            {
                Error(diagnostics, ErrorCode.ERR_PropertyLacksGet, node, isCompletedProperty);
                isCompletedProperty = null;
                return false;
            }

            if (isCompletedProperty.Type.SpecialType != SpecialType.System_Boolean)
            {
                Error(diagnostics, ErrorCode.ERR_BadAwaiterPattern, node, awaiterType, awaitedExpressionType);
                isCompletedProperty = null;
                return false;
            }

            return true;
        }
 /// <summary>
 /// Finds the GetResult method of an Awaiter type.
 /// </summary>
 /// <remarks>
 /// Spec 7.7.7.1:
 /// An Awaiter A has an accessible instance method GetResult with no parameters and no type parameters.
 /// </remarks>
 private bool GetGetResultMethod(TypeSymbol type, CSharpSyntaxNode node, DiagnosticBag diagnostics, out MethodSymbol getResultMethod)
 {
     var receiver = new BoundLiteral(node, ConstantValue.Null, type);
     var getResultCall = MakeInvocationExpression(node, receiver, WellKnownMemberNames.GetResult, ImmutableArray<BoundExpression>.Empty, diagnostics);
     getResultMethod = (getResultCall.Kind != BoundKind.Call) ? null : ((BoundCall)getResultCall).Method;
     return !getResultCall.HasAnyErrors;
 }
        /// <summary>
        /// Finds the IsCompleted property of an Awaiter type.
        /// </summary>
        /// <remarks>
        /// Spec 7.7.7.1:
        /// An Awaiter A has an accessible, readable instance property IsCompleted of type bool.
        /// </remarks>
        private bool GetIsCompletedProperty(TypeSymbol type, CSharpSyntaxNode node, DiagnosticBag diagnostics, out PropertySymbol isCompletedProperty)
        {
            isCompletedProperty = null;
            var receiver = new BoundLiteral(node, ConstantValue.Null, type);
            var name = WellKnownMemberNames.IsCompleted;
            var qualified = BindInstanceMemberAccess(node, node, receiver, name, 0, default(SeparatedSyntaxList<TypeSyntax>), default(ImmutableArray<TypeSymbol>), false, diagnostics);
            if (qualified.Kind == BoundKind.PropertyAccess)
            {
                var property = (BoundPropertyAccess)qualified;
                isCompletedProperty = property.PropertySymbol;
            }

            return !qualified.HasAnyErrors;
        }
예제 #6
0
        private BoundExpression BindInterpolatedString(InterpolatedStringExpressionSyntax node, DiagnosticBag diagnostics)
        {
            var builder = ArrayBuilder<BoundExpression>.GetInstance();
            var stringType = GetSpecialType(SpecialType.System_String, diagnostics, node);
            var objectType = GetSpecialType(SpecialType.System_Object, diagnostics, node);
            var intType = GetSpecialType(SpecialType.System_Int32, diagnostics, node);
            foreach (var content in node.Contents)
            {
                switch (content.Kind())
                {
                    case SyntaxKind.Interpolation:
                        {
                            var interpolation = (InterpolationSyntax)content;
                            var value = BindValue(interpolation.Expression, diagnostics, Binder.BindValueKind.RValue);
                            // We need to ensure the argument is not a lambda, method group, etc. It isn't nice to wait until lowering,
                            // when we perform overload resolution, to report a problem. So we do that check by calling
                            // GenerateConversionForAssignment with objectType. However we want to preserve the original expression's
                            // natural type so that overload resolution may select a specialized implementation of string.Format,
                            // so we discard the result of that call and only preserve its diagnostics.
                            var discarded = GenerateConversionForAssignment(objectType, value, diagnostics);
                            BoundExpression alignment = null, format = null;
                            if (interpolation.AlignmentClause != null)
                            {
                                alignment = GenerateConversionForAssignment(intType, BindValue(interpolation.AlignmentClause.Value, diagnostics, Binder.BindValueKind.RValue), diagnostics);
                                var alignmentConstant = alignment.ConstantValue;
                                if (alignmentConstant != null && !alignmentConstant.IsBad)
                                {
                                    const int magnitudeLimit = 32767;
                                    // check that the magnitude of the alignment is "in range".
                                    int alignmentValue = alignmentConstant.Int32Value;
                                    //  We do the arithmetic using negative numbers because the largest negative int has no corresponding positive (absolute) value.
                                    alignmentValue = (alignmentValue > 0) ? -alignmentValue : alignmentValue;
                                    if (alignmentValue < -magnitudeLimit)
                                    {
                                        diagnostics.Add(ErrorCode.WRN_AlignmentMagnitude, alignment.Syntax.Location, alignmentConstant.Int32Value, magnitudeLimit);
                                    }
                                }
                                else if (!alignment.HasErrors)
                                {
                                    diagnostics.Add(ErrorCode.ERR_ConstantExpected, interpolation.AlignmentClause.Value.Location);
                                }
                            }

                            if (interpolation.FormatClause != null)
                            {
                                var text = interpolation.FormatClause.FormatStringToken.ValueText;
                                char lastChar;
                                bool hasErrors = false;
                                if (text.Length == 0)
                                {
                                    diagnostics.Add(ErrorCode.ERR_EmptyFormatSpecifier, interpolation.FormatClause.Location);
                                    hasErrors = true;
                                }
                                else if (SyntaxFacts.IsWhitespace(lastChar = text[text.Length - 1]) || SyntaxFacts.IsNewLine(lastChar))
                                {
                                    diagnostics.Add(ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier, interpolation.FormatClause.Location);
                                    hasErrors = true;
                                }

                                format = new BoundLiteral(interpolation.FormatClause, ConstantValue.Create(text), stringType, hasErrors);
                            }

                            builder.Add(new BoundStringInsert(interpolation, value, alignment, format, null));
                            continue;
                        }
                    case SyntaxKind.InterpolatedStringText:
                        {
                            var text = ((InterpolatedStringTextSyntax)content).TextToken.ValueText;
                            builder.Add(new BoundLiteral(content, ConstantValue.Create(text, SpecialType.System_String), stringType));
                            continue;
                        }
                    default:
                        throw ExceptionUtilities.UnexpectedValue(content.Kind());
                }
            }

            return new BoundInterpolatedString(node, builder.ToImmutableAndFree(), stringType);
        }
예제 #7
0
        /// <summary>
        /// Finds the IsCompleted property of an Awaiter type.
        /// </summary>
        /// <remarks>
        /// Spec 7.7.7.1:
        /// An Awaiter A has an accessible, readable instance property IsCompleted of type bool.
        /// </remarks>
        private bool GetIsCompletedProperty(
            TypeSymbol awaiterType,
            SyntaxNode node,
            TypeSymbol awaitedExpressionType,
            BindingDiagnosticBag diagnostics,
            [NotNullWhen(true)] out PropertySymbol?isCompletedProperty
            )
        {
            var receiver  = new BoundLiteral(node, ConstantValue.Null, awaiterType);
            var name      = WellKnownMemberNames.IsCompleted;
            var qualified = BindInstanceMemberAccess(
                node,
                node,
                receiver,
                name,
                0,
                default(SeparatedSyntaxList <TypeSyntax>),
                default(ImmutableArray <TypeWithAnnotations>),
                invoked: false,
                indexed: false,
                diagnostics
                );

            if (qualified.HasAnyErrors)
            {
                isCompletedProperty = null;
                return(false);
            }

            if (qualified.Kind != BoundKind.PropertyAccess)
            {
                Error(
                    diagnostics,
                    ErrorCode.ERR_NoSuchMember,
                    node,
                    awaiterType,
                    WellKnownMemberNames.IsCompleted
                    );
                isCompletedProperty = null;
                return(false);
            }

            isCompletedProperty = ((BoundPropertyAccess)qualified).PropertySymbol;
            if (isCompletedProperty.IsWriteOnly)
            {
                Error(diagnostics, ErrorCode.ERR_PropertyLacksGet, node, isCompletedProperty);
                isCompletedProperty = null;
                return(false);
            }

            if (isCompletedProperty.Type.SpecialType != SpecialType.System_Boolean)
            {
                Error(
                    diagnostics,
                    ErrorCode.ERR_BadAwaiterPattern,
                    node,
                    awaiterType,
                    awaitedExpressionType
                    );
                isCompletedProperty = null;
                return(false);
            }

            return(true);
        }
 public BoundExpression Null(TypeSymbol type)
 {
     BoundExpression nullLiteral = new BoundLiteral(Syntax, ConstantValue.Null, type) { WasCompilerGenerated = true };
     return type.IsPointerType()
         ? BoundConversion.SynthesizedNonUserDefined(Syntax, nullLiteral, ConversionKind.NullToPointer, type)
         : nullLiteral;
 }
예제 #9
0
 public override BoundNode VisitLiteral(BoundLiteral node)
 {
     return(MakeLiteral(node.Syntax, node.ConstantValue, node.Type, oldNodeOpt: node));
 }
예제 #10
0
        private BoundExpression BindInterpolatedString(InterpolatedStringExpressionSyntax node, BindingDiagnosticBag diagnostics)
        {
            var builder = ArrayBuilder <BoundExpression> .GetInstance();

            var           stringType       = GetSpecialType(SpecialType.System_String, diagnostics, node);
            ConstantValue?resultConstant   = null;
            bool          isResultConstant = true;

            if (node.Contents.Count == 0)
            {
                resultConstant = ConstantValue.Create(string.Empty);
            }
            else
            {
                var intType = GetSpecialType(SpecialType.System_Int32, diagnostics, node);
                foreach (var content in node.Contents)
                {
                    switch (content.Kind())
                    {
                    case SyntaxKind.Interpolation:
                    {
                        var interpolation = (InterpolationSyntax)content;
                        var value         = BindValue(interpolation.Expression, diagnostics, BindValueKind.RValue);

                        // We need to ensure the argument is not a lambda, method group, etc. It isn't nice to wait until lowering,
                        // when we perform overload resolution, to report a problem. So we do that check by calling
                        // GenerateConversionForAssignment with objectType. However we want to preserve the original expression's
                        // natural type so that overload resolution may select a specialized implementation of string.Format,
                        // so we discard the result of that call and only preserve its diagnostics.
                        BoundExpression?alignment = null;
                        BoundLiteral?   format    = null;
                        if (interpolation.AlignmentClause != null)
                        {
                            alignment = GenerateConversionForAssignment(intType, BindValue(interpolation.AlignmentClause.Value, diagnostics, Binder.BindValueKind.RValue), diagnostics);
                            var alignmentConstant = alignment.ConstantValue;
                            if (alignmentConstant != null && !alignmentConstant.IsBad)
                            {
                                const int magnitudeLimit = 32767;
                                // check that the magnitude of the alignment is "in range".
                                int alignmentValue = alignmentConstant.Int32Value;
                                //  We do the arithmetic using negative numbers because the largest negative int has no corresponding positive (absolute) value.
                                alignmentValue = (alignmentValue > 0) ? -alignmentValue : alignmentValue;
                                if (alignmentValue < -magnitudeLimit)
                                {
                                    diagnostics.Add(ErrorCode.WRN_AlignmentMagnitude, alignment.Syntax.Location, alignmentConstant.Int32Value, magnitudeLimit);
                                }
                            }
                            else if (!alignment.HasErrors)
                            {
                                diagnostics.Add(ErrorCode.ERR_ConstantExpected, interpolation.AlignmentClause.Value.Location);
                            }
                        }

                        if (interpolation.FormatClause != null)
                        {
                            var  text = interpolation.FormatClause.FormatStringToken.ValueText;
                            char lastChar;
                            bool hasErrors = false;
                            if (text.Length == 0)
                            {
                                diagnostics.Add(ErrorCode.ERR_EmptyFormatSpecifier, interpolation.FormatClause.Location);
                                hasErrors = true;
                            }
                            else if (SyntaxFacts.IsWhitespace(lastChar = text[text.Length - 1]) || SyntaxFacts.IsNewLine(lastChar))
                            {
                                diagnostics.Add(ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier, interpolation.FormatClause.Location);
                                hasErrors = true;
                            }

                            format = new BoundLiteral(interpolation.FormatClause, ConstantValue.Create(text), stringType, hasErrors);
                        }

                        builder.Add(new BoundStringInsert(interpolation, value, alignment, format, isInterpolatedStringHandlerAppendCall: false));
                        if (!isResultConstant ||
                            value.ConstantValue == null ||
                            !(interpolation is { FormatClause: null, AlignmentClause: null }) ||
                            !(value.ConstantValue is { IsString: true, IsBad: false }))
예제 #11
0
        private BoundExpression MakeLiteral(CSharpSyntaxNode syntax, ConstantValue constantValue, TypeSymbol type, BoundLiteral oldNodeOpt = null)
        {
            Debug.Assert(constantValue != null);

            if (constantValue.IsDecimal)
            {
                //  Rewrite decimal literal
                Debug.Assert((object)type != null);
                Debug.Assert(type.SpecialType == SpecialType.System_Decimal);

                return(MakeDecimalLiteral(syntax, constantValue));
            }
            else if (constantValue.IsDateTime)
            {
                // C# does not support DateTime constants but VB does; we might have obtained a
                // DateTime constant by calling a method with an optional parameter with a DateTime
                // for its default value.
                Debug.Assert((object)type != null);
                Debug.Assert(type.SpecialType == SpecialType.System_DateTime);
                return(MakeDateTimeLiteral(syntax, constantValue));
            }
            else if (oldNodeOpt != null)
            {
                return(oldNodeOpt.Update(constantValue, type));
            }
            else
            {
                return(new BoundLiteral(syntax, constantValue, type, hasErrors: constantValue.IsBad));
            }
        }
예제 #12
0
 public override BoundNode VisitLiteral(BoundLiteral node)
 {
     Debug.Assert(node.ConstantValue is { });
예제 #13
0
            // For switch statements, we have an option of completely rewriting the switch header
            // and switch sections into simpler constructs, i.e. we can rewrite the switch header
            // using bound conditional goto statements and the rewrite the switch sections into
            // bound labeled statements.
            //
            // However, all the logic for emitting the switch jump tables is language agnostic
            // and includes IL optimizations. Hence we delay the switch jump table generation
            // till the emit phase. This way we also get additional benefit of sharing this code
            // between both VB and C# compilers.
            //
            // For string switch statements, we need to determine if we are generating a hash
            // table based jump table or a non hash jump table, i.e. linear string comparisons
            // with each case label. We use the Dev10 Heuristic to determine this
            // (see SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch() for details).
            // If we are generating a hash table based jump table, we use a simple
            // hash function to hash the string constants corresponding to the case labels.
            // See SwitchStringJumpTableEmitter.ComputeStringHash().
            // We need to emit this same function to compute the hash value into the compiler generated
            // <PrivateImplementationDetails> class.
            // If we have at least one string switch statement in a module that needs a
            // hash table based jump table, we generate a single public string hash synthesized method
            // that is shared across the module.
            private void LowerBasicSwitch(DecisionTree.ByValue byValue)
            {
                var switchSections = ArrayBuilder <BoundSwitchSection> .GetInstance();

                var noValueMatches       = _factory.GenerateLabel("noValueMatches");
                var underlyingSwitchType = byValue.Type.IsEnumType() ? byValue.Type.GetEnumUnderlyingType() : byValue.Type;

                foreach (var vd in byValue.ValueAndDecision)
                {
                    var value              = vd.Key;
                    var decision           = vd.Value;
                    var constantValue      = ConstantValue.Create(value, underlyingSwitchType.SpecialType);
                    var constantExpression = new BoundLiteral(_factory.Syntax, constantValue, underlyingSwitchType);
                    var label              = _factory.GenerateLabel("case+" + value);
                    var switchLabel        = new BoundSwitchLabel(_factory.Syntax, label, constantExpression, constantValue);
                    var forValue           = ArrayBuilder <BoundStatement> .GetInstance();

                    LowerDecisionTree(byValue.Expression, decision, forValue);
                    if (!decision.MatchIsComplete)
                    {
                        forValue.Add(_factory.Goto(noValueMatches));
                    }

                    var section = new BoundSwitchSection(_factory.Syntax, ImmutableArray.Create(switchLabel), forValue.ToImmutableAndFree());
                    switchSections.Add(section);
                }

                var          rewrittenSections = switchSections.ToImmutableAndFree();
                MethodSymbol stringEquality    = null;

                if (underlyingSwitchType.SpecialType == SpecialType.System_String)
                {
                    _localRewriter.EnsureStringHashFunction(rewrittenSections, _factory.Syntax);
                    stringEquality = _localRewriter.GetSpecialTypeMethod(_factory.Syntax, SpecialMember.System_String__op_Equality);
                }

                // The BoundSwitchStatement requires a constant target when there are no sections, so we accomodate that here.
                var constantTarget  = rewrittenSections.IsEmpty ? noValueMatches : null;
                var switchStatement = new BoundSwitchStatement(
                    _factory.Syntax, null, _factory.Convert(underlyingSwitchType, byValue.Expression),
                    constantTarget,
                    ImmutableArray <LocalSymbol> .Empty, ImmutableArray <LocalFunctionSymbol> .Empty,
                    rewrittenSections, noValueMatches, stringEquality);

                // The bound switch statement implicitly defines the label noValueMatches at the end, so we do not add it explicitly.

                switch (underlyingSwitchType.SpecialType)
                {
                case SpecialType.System_Boolean:
                    // boolean switch is handled in LowerBooleanSwitch, not here.
                    throw ExceptionUtilities.Unreachable;

                case SpecialType.System_String:
                case SpecialType.System_Byte:
                case SpecialType.System_Char:
                case SpecialType.System_Int16:
                case SpecialType.System_Int32:
                case SpecialType.System_Int64:
                case SpecialType.System_SByte:
                case SpecialType.System_UInt16:
                case SpecialType.System_UInt32:
                case SpecialType.System_UInt64:
                {
                    // emit knows how to efficiently generate code for these kinds of switches.
                    _loweredDecisionTree.Add(switchStatement);
                    break;
                }

                default:
                {
                    // other types, such as float, double, and decimal, are not currently
                    // handled by emit and must be lowered here.
                    _loweredDecisionTree.Add(LowerNonprimitiveSwitch(switchStatement));
                    break;
                }
                }

                LowerDecisionTree(byValue.Expression, byValue.Default);
            }
예제 #14
0
        private BoundExpression BindCodeblock(SyntaxNode syntax, UnboundLambda unboundLambda, Conversion conversion, bool isCast, TypeSymbol destination, DiagnosticBag diagnostics)
        {
            if (!Compilation.Options.HasRuntime)
            {
                return(null);
            }
            var isCodeblock = syntax.XIsCodeBlock;

            if (!isCodeblock)
            {
                isCodeblock = !destination.IsDelegateType() && !destination.IsExpressionTree();
            }
            if (!isCodeblock)
            {
                return(null);
            }

            Conversion conv = Conversion.ImplicitReference;

            if (destination != Compilation.CodeBlockType() && !destination.IsObjectType())
            {
                HashSet <DiagnosticInfo> useSiteDiagnostics = null;
                conv = Conversions.ClassifyConversionFromType(Compilation.CodeBlockType(), destination, ref useSiteDiagnostics);
                diagnostics.Add(syntax, useSiteDiagnostics);
            }
            if (Compilation.Options.HasRuntime)
            {
                Debug.Assert(destination == Compilation.CodeBlockType() || conv.Exists);
            }
            if (!syntax.XIsCodeBlock && !Compilation.Options.MacroScript && !syntax.XNode.IsAliasExpression())
            {
                Error(diagnostics, ErrorCode.ERR_CodeblockWithLambdaSyntax, syntax);
            }

            AnonymousTypeManager manager = this.Compilation.AnonymousTypeManager;
            var delegateSignature        = new TypeSymbol[unboundLambda.ParameterCount + 1];
            var usualType = this.Compilation.UsualType();

            for (int i = 0; i < delegateSignature.Length; i++)
            {
                delegateSignature[i] = usualType;
            }
            NamedTypeSymbol cbType       = manager.ConstructCodeblockTypeSymbol(delegateSignature, syntax.Location);
            var             delType      = manager.GetCodeblockDelegateType(cbType);
            var             _boundLambda = unboundLambda.Bind(delType);

            diagnostics.AddRange(_boundLambda.Diagnostics);
            var cbDel = new BoundConversion(
                syntax,
                _boundLambda,
                conversion,
                @checked: false,
                explicitCastInCode: false,
                constantValueOpt: ConstantValue.NotAvailable,
                type: delType)
            {
                WasCompilerGenerated = unboundLambda.WasCompilerGenerated
            };
            var             cbSrc  = new BoundLiteral(syntax, ConstantValue.Create(syntax.XCodeBlockSource), Compilation.GetSpecialType(SpecialType.System_String));
            BoundExpression cbInst = new BoundAnonymousObjectCreationExpression(syntax,
                                                                                cbType.InstanceConstructors[0],
                                                                                new BoundExpression[] { cbDel, cbSrc }.ToImmutableArrayOrEmpty(),
                                                                                System.Collections.Immutable.ImmutableArray <BoundAnonymousPropertyDeclaration> .Empty, cbType)
            {
                WasCompilerGenerated = unboundLambda.WasCompilerGenerated
            };;

            if (conv != Conversion.ImplicitReference)
            {
                cbInst = new BoundConversion(syntax, cbInst, Conversion.ImplicitReference, false, false, ConstantValue.NotAvailable, Compilation.CodeBlockType())
                {
                    WasCompilerGenerated = unboundLambda.WasCompilerGenerated
                };;
            }
            if (!conv.IsValid || (!isCast && conv.IsExplicit))
            {
                GenerateImplicitConversionError(diagnostics, syntax, conv, cbInst, destination);

                return(new BoundConversion(
                           syntax,
                           cbInst,
                           conv,
                           false,
                           explicitCastInCode: isCast,
                           constantValueOpt: ConstantValue.NotAvailable,
                           type: destination,
                           hasErrors: true)
                {
                    WasCompilerGenerated = unboundLambda.WasCompilerGenerated
                });
            }
            return(new BoundConversion(
                       syntax,
                       cbInst,
                       conv,
                       false,
                       explicitCastInCode: isCast,
                       constantValueOpt: ConstantValue.NotAvailable,
                       type: destination)
            {
                WasCompilerGenerated = unboundLambda.WasCompilerGenerated
            });
        }
            // For switch statements, we have an option of completely rewriting the switch header
            // and switch sections into simpler constructs, i.e. we can rewrite the switch header
            // using bound conditional goto statements and the rewrite the switch sections into
            // bound labeled statements.
            //
            // However, all the logic for emitting the switch jump tables is language agnostic
            // and includes IL optimizations. Hence we delay the switch jump table generation
            // till the emit phase. This way we also get additional benefit of sharing this code
            // between both VB and C# compilers.
            //
            // For string switch statements, we need to determine if we are generating a hash
            // table based jump table or a non hash jump table, i.e. linear string comparisons
            // with each case label. We use the Dev10 Heuristic to determine this
            // (see SwitchStringJumpTableEmitter.ShouldGenerateHashTableSwitch() for details).
            // If we are generating a hash table based jump table, we use a simple
            // hash function to hash the string constants corresponding to the case labels.
            // See SwitchStringJumpTableEmitter.ComputeStringHash().
            // We need to emit this same function to compute the hash value into the compiler generated
            // <PrivateImplementationDetails> class.
            // If we have at least one string switch statement in a module that needs a
            // hash table based jump table, we generate a single public string hash synthesized method
            // that is shared across the module.
            private void LowerBasicSwitch(DecisionTree.ByValue byValue)
            {
                var switchSections = ArrayBuilder<BoundSwitchSection>.GetInstance();
                var noValueMatches = _factory.GenerateLabel("noValueMatches");
                var underlyingSwitchType = byValue.Type.IsEnumType() ? byValue.Type.GetEnumUnderlyingType() : byValue.Type;
                foreach (var vd in byValue.ValueAndDecision)
                {
                    var value = vd.Key;
                    var decision = vd.Value;
                    var constantValue = ConstantValue.Create(value, underlyingSwitchType.SpecialType);
                    var constantExpression = new BoundLiteral(_factory.Syntax, constantValue, underlyingSwitchType);
                    var label = _factory.GenerateLabel("case+" + value);
                    var switchLabel = new BoundSwitchLabel(_factory.Syntax, label, constantExpression, constantValue);
                    var forValue = ArrayBuilder<BoundStatement>.GetInstance();
                    LowerDecisionTree(byValue.Expression, decision, forValue);
                    if (!decision.MatchIsComplete)
                    {
                        forValue.Add(_factory.Goto(noValueMatches));
                    }

                    var section = new BoundSwitchSection(_factory.Syntax, ImmutableArray.Create(switchLabel), forValue.ToImmutableAndFree());
                    switchSections.Add(section);
                }

                var rewrittenSections = switchSections.ToImmutableAndFree();
                MethodSymbol stringEquality = null;
                if (underlyingSwitchType.SpecialType == SpecialType.System_String)
                {
                    LocalRewriter.EnsureStringHashFunction(rewrittenSections, _factory.Syntax);
                    stringEquality = LocalRewriter.GetSpecialTypeMethod(_factory.Syntax, SpecialMember.System_String__op_Equality);
                }

                // The BoundSwitchStatement requires a constant target when there are no sections, so we accomodate that here.
                var constantTarget = rewrittenSections.IsEmpty ? noValueMatches : null;
                var switchStatement = new BoundSwitchStatement(
                    _factory.Syntax, null, _factory.Convert(underlyingSwitchType, byValue.Expression),
                    constantTarget,
                    ImmutableArray<LocalSymbol>.Empty, ImmutableArray<LocalFunctionSymbol>.Empty,
                    rewrittenSections, noValueMatches, stringEquality);
                // The bound switch statement implicitly defines the label noValueMatches at the end, so we do not add it explicitly.

                switch (underlyingSwitchType.SpecialType)
                {
                    case SpecialType.System_Boolean:
                        // boolean switch is handled in LowerBooleanSwitch, not here.
                        throw ExceptionUtilities.Unreachable;

                    case SpecialType.System_String:
                    case SpecialType.System_Byte:
                    case SpecialType.System_Char:
                    case SpecialType.System_Int16:
                    case SpecialType.System_Int32:
                    case SpecialType.System_Int64:
                    case SpecialType.System_SByte:
                    case SpecialType.System_UInt16:
                    case SpecialType.System_UInt32:
                    case SpecialType.System_UInt64:
                        {
                            // emit knows how to efficiently generate code for these kinds of switches.
                            _loweredDecisionTree.Add(switchStatement);
                            break;
                        }

                    default:
                        {
                            // other types, such as float, double, and decimal, are not currently
                            // handled by emit and must be lowered here.
                            _loweredDecisionTree.Add(LowerNonprimitiveSwitch(switchStatement));
                            break;
                        }
                }

                LowerDecisionTree(byValue.Expression, byValue.Default);
            }
예제 #16
0
        internal static BoundTypeOrInstanceInitializers Rewrite(ImmutableArray<BoundInitializer> boundInitializers, MethodSymbol method, TypeSymbol submissionResultTypeOpt)
        {
            Debug.Assert(!boundInitializers.IsDefault);
            Debug.Assert(method.IsSubmissionInitializer == ((object)submissionResultTypeOpt != null));

            var boundStatements = ArrayBuilder<BoundStatement>.GetInstance(boundInitializers.Length);
            BoundExpression submissionResult = null;

            for (int i = 0; i < boundInitializers.Length; i++)
            {
                var init = boundInitializers[i];

                switch (init.Kind)
                {
                    case BoundKind.FieldInitializer:
                        boundStatements.Add(RewriteFieldInitializer((BoundFieldInitializer)init));
                        break;

                    case BoundKind.GlobalStatementInitializer:
                        var statement = ((BoundGlobalStatementInitializer)init).Statement;
                        // The value of the last expression statement (if any) is returned from the submission initializer.
                        if ((object)submissionResultTypeOpt != null &&
                            i == boundInitializers.Length - 1 &&
                            statement.Kind == BoundKind.ExpressionStatement)
                        {
                            var expr = ((BoundExpressionStatement)statement).Expression;
                            if ((object)expr.Type != null && expr.Type.SpecialType != SpecialType.System_Void)
                            {
                                submissionResult = expr;
                                break;
                            }
                        }
                        boundStatements.Add(statement);
                        break;

                    default:
                        throw ExceptionUtilities.UnexpectedValue(init.Kind);
                }
            }

            var sourceMethod = method as SourceMethodSymbol;
            var syntax = ((object)sourceMethod != null) ? sourceMethod.SyntaxNode : method.GetNonNullSyntaxNode();

            if ((object)submissionResultTypeOpt != null)
            {
                if (submissionResult == null)
                {
                    // Return null if submission does not have a trailing expression.
                    Debug.Assert(submissionResultTypeOpt.IsReferenceType);
                    submissionResult = new BoundLiteral(syntax, ConstantValue.Null, submissionResultTypeOpt);
                }

                Debug.Assert((object)submissionResult.Type != null);
                Debug.Assert(submissionResult.Type.SpecialType != SpecialType.System_Void);

                // The expression is converted to the submission result type when the initializer is bound.
                boundStatements.Add(new BoundReturnStatement(submissionResult.Syntax, submissionResult));
            }

            return new BoundTypeOrInstanceInitializers(syntax, boundStatements.ToImmutableAndFree());
        }
예제 #17
0
 public override BoundNode VisitLiteral(BoundLiteral node)
 {
     return MakeLiteral(node.Syntax, node.ConstantValue, node.Type, oldNodeOpt: node);
 }
        internal Conversion GetCallerLineNumberConversion(TypeSymbol destination, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            var greenNode = new Syntax.InternalSyntax.LiteralExpressionSyntax(SyntaxKind.NumericLiteralExpression, new Syntax.InternalSyntax.SyntaxToken(SyntaxKind.NumericLiteralToken));
            var syntaxNode = new LiteralExpressionSyntax(greenNode, null, 0);

            TypeSymbol expectedAttributeType = corLibrary.GetSpecialType(SpecialType.System_Int32);
            BoundLiteral intMaxValueLiteral = new BoundLiteral(syntaxNode, ConstantValue.Create(int.MaxValue), expectedAttributeType);
            return ClassifyStandardImplicitConversion(intMaxValueLiteral, expectedAttributeType, destination, ref useSiteDiagnostics);
        }
예제 #19
0
        internal static BoundTypeOrInstanceInitializers Rewrite(ImmutableArray <BoundInitializer> boundInitializers, MethodSymbol method, TypeSymbol submissionResultTypeOpt)
        {
            Debug.Assert(!boundInitializers.IsDefault);
            Debug.Assert(method.IsSubmissionInitializer == ((object)submissionResultTypeOpt != null));

            var boundStatements = ArrayBuilder <BoundStatement> .GetInstance(boundInitializers.Length);

            BoundExpression submissionResult = null;

            for (int i = 0; i < boundInitializers.Length; i++)
            {
                var init = boundInitializers[i];

                switch (init.Kind)
                {
                case BoundKind.FieldInitializer:
                    boundStatements.Add(RewriteFieldInitializer((BoundFieldInitializer)init));
                    break;

                case BoundKind.GlobalStatementInitializer:
                    var statement = ((BoundGlobalStatementInitializer)init).Statement;
                    // The value of the last expression statement (if any) is returned from the submission initializer.
                    if ((object)submissionResultTypeOpt != null &&
                        i == boundInitializers.Length - 1 &&
                        statement.Kind == BoundKind.ExpressionStatement)
                    {
                        var expr = ((BoundExpressionStatement)statement).Expression;
                        if ((object)expr.Type != null && expr.Type.SpecialType != SpecialType.System_Void)
                        {
                            submissionResult = expr;
                            break;
                        }
                    }
                    boundStatements.Add(statement);
                    break;

                default:
                    throw ExceptionUtilities.UnexpectedValue(init.Kind);
                }
            }

            var sourceMethod = method as SourceMethodSymbol;
            var syntax       = ((object)sourceMethod != null) ? sourceMethod.SyntaxNode : method.GetNonNullSyntaxNode();

            if ((object)submissionResultTypeOpt != null)
            {
                if (submissionResult == null)
                {
                    // Return null if submission does not have a trailing expression.
                    Debug.Assert(submissionResultTypeOpt.IsReferenceType);
                    submissionResult = new BoundLiteral(syntax, ConstantValue.Null, submissionResultTypeOpt);
                }

                Debug.Assert((object)submissionResult.Type != null);
                Debug.Assert(submissionResult.Type.SpecialType != SpecialType.System_Void);

                // The expression is converted to the submission result type when the initializer is bound.
                boundStatements.Add(new BoundReturnStatement(submissionResult.Syntax, submissionResult));
            }

            return(new BoundTypeOrInstanceInitializers(syntax, boundStatements.ToImmutableAndFree()));
        }