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); } }
/// <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; }
/// <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; }
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); }
/// <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; }
public override BoundNode VisitLiteral(BoundLiteral node) { return(MakeLiteral(node.Syntax, node.ConstantValue, node.Type, oldNodeOpt: node)); }
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 }))
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)); } }
public override BoundNode VisitLiteral(BoundLiteral node) { Debug.Assert(node.ConstantValue is { });
// 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); }
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); }
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()); }
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); }
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())); }