/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Binding/Binder_Initializers.vb
672 строки
39 KB
AlekseyTs
Avoid cycle caused by calculation of ObsoleteState/ExperimentalState. (#70171)
11 окт 2023, 04:26
Не верифицирован
11 окт 2023, 04:26
d49b29e
Код
Авторство
О чём код?
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic Partial Friend Class Binder ''' <summary> ''' Used to store the bound field and property initializers and the associated list of ''' bound assignment statements because they are reused for multiple constructors ''' </summary> Friend NotInheritable Class ProcessedFieldOrPropertyInitializers Friend ReadOnly BoundInitializers As ImmutableArray(Of BoundInitializer) ''' <summary> ''' Indicate the fact that binding of initializers produced a tree with errors. ''' This property does not indicate whether or not a diagnostic was produced during the ''' binding of the initializers. ''' </summary> Friend ReadOnly HasAnyErrors As Boolean Private _loweredInitializers As ImmutableArray(Of BoundStatement) Friend Property InitializerStatements As ImmutableArray(Of BoundStatement) Get Return _loweredInitializers End Get Set(value As ImmutableArray(Of BoundStatement)) Debug.Assert(Not value.IsDefault) Debug.Assert(_loweredInitializers.IsDefault) _loweredInitializers = value End Set End Property Friend Shared ReadOnly Empty As ProcessedFieldOrPropertyInitializers = New ProcessedFieldOrPropertyInitializers() Private Sub New() Me.BoundInitializers = ImmutableArray(Of BoundInitializer).Empty Me.HasAnyErrors = False Me._loweredInitializers = ImmutableArray(Of BoundStatement).Empty End Sub Friend Sub New(boundInitializers As ImmutableArray(Of BoundInitializer)) Debug.Assert(Not boundInitializers.IsDefault) Me.BoundInitializers = boundInitializers Me.HasAnyErrors = boundInitializers.Any(Function(i) i.HasErrors) End Sub Private _analyzed As Boolean = False Friend Sub EnsureInitializersAnalyzed(method As MethodSymbol, diagnostics As DiagnosticBag) Debug.Assert(method IsNot Nothing) If Not _analyzed Then If Not Me.BoundInitializers.IsEmpty Then ' Create a dummy block Dim block As New BoundBlock(Me.BoundInitializers(0).Syntax, Nothing, ImmutableArray(Of LocalSymbol).Empty, StaticCast(Of BoundStatement).From(Me.BoundInitializers)) Analyzer.AnalyzeMethodBody(method, block, diagnostics) DiagnosticsPass.IssueDiagnostics(block, diagnostics, method) End If _analyzed = True End If End Sub End Class ''' <summary> ''' Binds all field initializers of a <see cref="SourceNamedTypeSymbol"/>. ''' </summary> ''' <param name="symbol">The named type symbol where the field initializers are declared.</param> ''' <param name="scriptInitializerOpt">Script initializer or Nothing if not binding top-level statements.</param> ''' <param name="initializers">The initializers itself. For each partial type declaration there is an array of ''' field initializers</param> ''' <param name="diagnostics">The diagnostics.</param> Friend Shared Function BindFieldAndPropertyInitializers( symbol As SourceMemberContainerTypeSymbol, initializers As ImmutableArray(Of ImmutableArray(Of FieldOrPropertyInitializer)), scriptInitializerOpt As SynthesizedInteractiveInitializerMethod, diagnostics As BindingDiagnosticBag ) As ImmutableArray(Of BoundInitializer) Debug.Assert((scriptInitializerOpt IsNot Nothing) = symbol.IsScriptClass) If initializers.IsDefaultOrEmpty Then Return ImmutableArray(Of BoundInitializer).Empty End If Dim moduleSymbol = DirectCast(symbol.ContainingModule, SourceModuleSymbol) Dim compilation = moduleSymbol.ContainingSourceAssembly.DeclaringCompilation Dim boundInitializers = ArrayBuilder(Of BoundInitializer).GetInstance() For i = 0 To initializers.Length - 1 Dim siblingInitializers = initializers(i) ' All sibling initializers share the same parent node and tree ' so we can reuse the parent binder across siblings. Dim parentBinder As Binder = Nothing For j = 0 To siblingInitializers.Length - 1 Dim initializer = siblingInitializers(j) If Not initializer.FieldsOrProperties.IsDefault AndAlso initializer.FieldsOrProperties.First.ContainingType.IsEnumType Then Continue For End If Dim syntaxRef = initializer.Syntax Dim syntaxTree = syntaxRef.SyntaxTree Dim initializerNode = DirectCast(syntaxRef.GetSyntax(), VisualBasicSyntaxNode) If parentBinder Is Nothing Then ' use binder for type, not ctor - no access to ctor parameters parentBinder = BinderBuilder.CreateBinderForType(moduleSymbol, syntaxTree, symbol) If scriptInitializerOpt IsNot Nothing Then parentBinder = New TopLevelCodeBinder(scriptInitializerOpt, parentBinder) End If Else Debug.Assert(parentBinder.SyntaxTree Is syntaxTree, "sibling initializer array contains initializers from two different syntax trees.") End If If initializer.FieldsOrProperties.IsDefault Then ' use the binder of the Script class for global statements Dim isLast = (i = initializers.Length - 1 AndAlso j = siblingInitializers.Length - 1) boundInitializers.Add(parentBinder.BindGlobalStatement(scriptInitializerOpt, DirectCast(initializerNode, StatementSyntax), diagnostics, isLast)) Continue For End If Dim firstFieldOrProperty = initializer.FieldsOrProperties.First Dim additionalSymbols = If(initializer.FieldsOrProperties.Length > 1, initializer.FieldsOrProperties.RemoveAt(0), ImmutableArray(Of Symbol).Empty) Dim initializerBinder = BinderBuilder.CreateBinderForInitializer(parentBinder, firstFieldOrProperty, additionalSymbols) If initializerNode.Kind = SyntaxKind.ModifiedIdentifier Then ' Array field with no explicit initializer. Debug.Assert(initializer.FieldsOrProperties.Length = 1) Debug.Assert(firstFieldOrProperty.Kind = SymbolKind.Field) Dim fieldSymbol = DirectCast(firstFieldOrProperty, SourceFieldSymbol) Debug.Assert(fieldSymbol.HasDeclaredType) Debug.Assert(fieldSymbol.Type.IsArrayType()) initializerBinder.BindArrayFieldImplicitInitializer(fieldSymbol, boundInitializers, diagnostics) ElseIf firstFieldOrProperty.Kind = SymbolKind.Field Then Dim fieldSymbol = DirectCast(firstFieldOrProperty, SourceFieldSymbol) If fieldSymbol.IsConst Then ' Bind constant to ensure diagnostics are captured, ' only generate a field initializer for decimals and dates, because they can't be compile time ' constant in CLR/IL. BindConstFieldInitializer(fieldSymbol, initializerNode, boundInitializers) If fieldSymbol.Type.SpecialType = SpecialType.System_DateTime Then ' report proper diagnostics for System_Runtime_CompilerServices_DateTimeConstantAttribute__ctor if needed initializerBinder.ReportUseSiteInfoForSynthesizedAttribute(WellKnownMember.System_Runtime_CompilerServices_DateTimeConstantAttribute__ctor, initializerNode, diagnostics) ElseIf fieldSymbol.Type.SpecialType = SpecialType.System_Decimal Then ' report proper diagnostics for System_Runtime_CompilerServices_DecimalConstantAttribute__ctor if needed initializerBinder.ReportUseSiteInfoForSynthesizedAttribute(WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctor, initializerNode, diagnostics) End If Else If fieldSymbol.Type.IsObjectType() AndAlso initializerBinder.OptionStrict <> VisualBasic.OptionStrict.On AndAlso fieldSymbol.Syntax IsNot Nothing AndAlso fieldSymbol.Syntax.Kind = SyntaxKind.ModifiedIdentifier Then Dim identifier = DirectCast(fieldSymbol.Syntax, ModifiedIdentifierSyntax) If identifier.Nullable.Node IsNot Nothing AndAlso identifier.Parent IsNot Nothing AndAlso identifier.Parent.Kind = SyntaxKind.VariableDeclarator AndAlso DirectCast(identifier.Parent, VariableDeclaratorSyntax).AsClause Is Nothing Then ReportDiagnostic(diagnostics, identifier, ERRID.ERR_NullableTypeInferenceNotSupported) End If End If initializerBinder.BindFieldInitializer(initializer.FieldsOrProperties.Cast(Of FieldSymbol).ToImmutableArray(), initializerNode, boundInitializers, diagnostics) End If Else initializerBinder.BindPropertyInitializer(initializer.FieldsOrProperties.Cast(Of PropertySymbol).ToImmutableArray(), initializerNode, boundInitializers, diagnostics) End If Next Next Return boundInitializers.ToImmutableAndFree() End Function Private Function BindGlobalStatement( scriptInitializerOpt As SynthesizedInteractiveInitializerMethod, statementNode As StatementSyntax, diagnostics As BindingDiagnosticBag, isLast As Boolean) As BoundInitializer Dim boundStatement As BoundStatement = Me.BindStatement(statementNode, diagnostics) If Me.Compilation.IsSubmission AndAlso isLast AndAlso boundStatement.Kind = BoundKind.ExpressionStatement AndAlso Not boundStatement.HasErrors Then ' insert an implicit conversion to the submission return type (if needed): Dim expression = (DirectCast(boundStatement, BoundExpressionStatement)).Expression If expression.Type Is Nothing OrElse expression.Type.SpecialType <> SpecialType.System_Void Then Dim submissionReturnType = scriptInitializerOpt.ResultType expression = ApplyImplicitConversion(expression.Syntax, submissionReturnType, expression, diagnostics) boundStatement = New BoundExpressionStatement(boundStatement.Syntax, expression, expression.HasErrors) End If End If Return New BoundGlobalStatementInitializer(statementNode, boundStatement) End Function ''' <summary> ''' Bind an initializer for an implicitly allocated array field (for example: Private F(2) As Object). ''' </summary> Public Sub BindArrayFieldImplicitInitializer( fieldSymbol As SourceFieldSymbol, boundInitializers As ArrayBuilder(Of BoundInitializer), diagnostics As BindingDiagnosticBag) Debug.Assert(fieldSymbol.Syntax.Kind = SyntaxKind.ModifiedIdentifier) Debug.Assert(fieldSymbol.Type.Kind = SymbolKind.ArrayType) Dim syntax = DirectCast(fieldSymbol.Syntax, ModifiedIdentifierSyntax) Debug.Assert(syntax.ArrayBounds IsNot Nothing) Dim arraySize = BindArrayBounds(syntax.ArrayBounds, diagnostics) Dim arrayCreation = New BoundArrayCreation(syntax, arraySize, Nothing, fieldSymbol.Type) arrayCreation.SetWasCompilerGenerated() Dim boundReceiver = If(fieldSymbol.IsShared, Nothing, CreateMeReference(syntax, isSynthetic:=True)) Dim boundFieldAccessExpression = New BoundFieldAccess(syntax, boundReceiver, fieldSymbol, True, fieldSymbol.Type) boundFieldAccessExpression.SetWasCompilerGenerated() Dim initializer = New BoundFieldInitializer(syntax, ImmutableArray.Create(Of FieldSymbol)(fieldSymbol), boundFieldAccessExpression, arrayCreation, binderOpt:=Nothing) boundInitializers.Add(initializer) End Sub ''' <summary> ''' Binds the field initializer. A bound field initializer contains the bound field access and bound init value. ''' </summary> ''' <param name="fieldSymbols">The field symbol.</param> ''' <param name="equalsValueOrAsNewSyntax">The syntax node for the optional initialization.</param> ''' <param name="boundInitializers">The array of bound initializers to add the newly bound ones to.</param> ''' <param name="diagnostics">The diagnostics.</param> Friend Sub BindFieldInitializer( fieldSymbols As ImmutableArray(Of FieldSymbol), equalsValueOrAsNewSyntax As SyntaxNode, boundInitializers As ArrayBuilder(Of BoundInitializer), diagnostics As BindingDiagnosticBag, Optional bindingForSemanticModel As Boolean = False ) Debug.Assert(Not fieldSymbols.IsEmpty) Dim firstFieldSymbol = DirectCast(fieldSymbols.First, SourceFieldSymbol) Debug.Assert(bindingForSemanticModel OrElse Not firstFieldSymbol.IsConst) Dim boundReceiver = If(firstFieldSymbol.IsShared, Nothing, CreateMeReference(firstFieldSymbol.Syntax, isSynthetic:=True)) ' Always generate a field access for the first symbol. In cases were we have multiple variables declared we will not ' use it (we don't store it in the bound initializer node), but we still need it for e.g. the data flow analysis ' (stored in the bound lvalue placeholder). Dim fieldAccess As BoundExpression = New BoundFieldAccess(firstFieldSymbol.Syntax, boundReceiver, firstFieldSymbol, True, firstFieldSymbol.Type) fieldAccess.SetWasCompilerGenerated() Dim boundInitExpression As BoundExpression = BindFieldInitializerExpression(equalsValueOrAsNewSyntax, firstFieldSymbol, diagnostics) Dim hasErrors = False ' In speculative semantic model scenarios equalsValueOrAsNewSyntax might have no parent. If equalsValueOrAsNewSyntax.Parent IsNot Nothing Then Debug.Assert(Me.IsSemanticModelBinder OrElse fieldSymbols.Length = DirectCast(equalsValueOrAsNewSyntax.Parent, VariableDeclaratorSyntax).Names.Count) If equalsValueOrAsNewSyntax.Kind() = SyntaxKind.AsNewClause Then For Each name In DirectCast(equalsValueOrAsNewSyntax.Parent, VariableDeclaratorSyntax).Names If Not (name.ArrayRankSpecifiers.IsEmpty AndAlso name.ArrayBounds Is Nothing) Then ' Arrays cannot be declared with AsNew syntax ReportDiagnostic(diagnostics, name, ERRID.ERR_AsNewArray) hasErrors = True End If Next End If End If boundInitializers.Add(New BoundFieldInitializer( equalsValueOrAsNewSyntax, fieldSymbols, If(fieldSymbols.Length = 1, fieldAccess, Nothing), boundInitExpression, Me, hasErrors)) End Sub Friend Function BindFieldInitializerExpression(equalsValueOrAsNewSyntax As SyntaxNode, fieldSymbol As FieldSymbol, diagnostics As BindingDiagnosticBag) As BoundExpression Dim asNewVariablePlaceholder As BoundWithLValueExpressionPlaceholder = Nothing If equalsValueOrAsNewSyntax.Kind = SyntaxKind.AsNewClause Then ' CONSIDER: using a bound field access directly instead of a placeholder for AsNew declarations ' with just one variable asNewVariablePlaceholder = New BoundWithLValueExpressionPlaceholder(equalsValueOrAsNewSyntax, fieldSymbol.Type) asNewVariablePlaceholder.SetWasCompilerGenerated() End If Dim boundInitExpression As BoundExpression = BindFieldOrPropertyInitializerExpression(equalsValueOrAsNewSyntax, fieldSymbol.Type, asNewVariablePlaceholder, diagnostics) Return boundInitExpression End Function Friend Sub BindPropertyInitializer( propertySymbols As ImmutableArray(Of PropertySymbol), initValueOrAsNewNode As SyntaxNode, boundInitializers As ArrayBuilder(Of BoundInitializer), diagnostics As BindingDiagnosticBag ) Dim propertySymbol = DirectCast(propertySymbols.First, PropertySymbol) Dim syntaxNode As SyntaxNode = initValueOrAsNewNode Dim boundReceiver = If(propertySymbol.IsShared, Nothing, CreateMeReference(syntaxNode, isSynthetic:=True)) ' If the property has parameters, BC36759 should have already ' been reported for the auto-implemented property. Dim hasError = propertySymbol.ParameterCount > 0 Dim boundPropertyOrFieldAccess As BoundExpression If propertySymbol.IsReadOnly AndAlso propertySymbol.AssociatedField IsNot Nothing Then ' For ReadOnly auto-implemented properties we have to write directly to the backing field. Debug.Assert(TypeSymbol.Equals(propertySymbol.Type, propertySymbol.AssociatedField.Type, TypeCompareKind.ConsiderEverything)) Debug.Assert(propertySymbols.Length = 1) boundPropertyOrFieldAccess = New BoundFieldAccess(syntaxNode, boundReceiver, propertySymbol.AssociatedField, isLValue:=True, type:=propertySymbol.Type, hasErrors:=hasError) Else boundPropertyOrFieldAccess = New BoundPropertyAccess(syntaxNode, propertySymbol, propertyGroupOpt:=Nothing, accessKind:=PropertyAccessKind.Set, isWriteable:=propertySymbol.HasSet, receiverOpt:=boundReceiver, arguments:=ImmutableArray(Of BoundExpression).Empty, hasErrors:=hasError) End If boundPropertyOrFieldAccess = BindAssignmentTarget(syntaxNode, boundPropertyOrFieldAccess, diagnostics) Dim isError As Boolean boundPropertyOrFieldAccess = AdjustAssignmentTarget(syntaxNode, boundPropertyOrFieldAccess, diagnostics, isError) boundPropertyOrFieldAccess.SetWasCompilerGenerated() Dim boundInitExpression As BoundExpression = BindPropertyInitializerExpression(initValueOrAsNewNode, propertySymbol, diagnostics) boundInitializers.Add(New BoundPropertyInitializer(initValueOrAsNewNode, propertySymbols, If(propertySymbols.Length = 1, boundPropertyOrFieldAccess, Nothing), boundInitExpression, Me)) End Sub Friend Function BindPropertyInitializerExpression(initValueOrAsNewNode As SyntaxNode, propertySymbol As PropertySymbol, diagnostics As BindingDiagnosticBag) As BoundExpression Return BindFieldOrPropertyInitializerExpression(initValueOrAsNewNode, propertySymbol.Type, Nothing, diagnostics) End Function Private Function BindFieldOrPropertyInitializerExpression( equalsValueOrAsNewSyntax As SyntaxNode, targetType As TypeSymbol, asNewVariablePlaceholderOpt As BoundWithLValueExpressionPlaceholder, diagnostics As BindingDiagnosticBag ) As BoundExpression Dim boundInitExpression As BoundExpression = Nothing Dim fieldInitializerSyntax As VisualBasicSyntaxNode If equalsValueOrAsNewSyntax.Kind = SyntaxKind.AsNewClause Then Dim asNew = DirectCast(equalsValueOrAsNewSyntax, AsNewClauseSyntax) Select Case asNew.NewExpression.Kind Case SyntaxKind.ObjectCreationExpression DisallowNewOnTupleType(asNew.Type, diagnostics) Dim objectCreationExpressionSyntax = DirectCast(asNew.NewExpression, ObjectCreationExpressionSyntax) boundInitExpression = BindObjectCreationExpression(asNew.NewExpression.Type, objectCreationExpressionSyntax.ArgumentList, targetType, objectCreationExpressionSyntax, diagnostics, asNewVariablePlaceholderOpt) Case SyntaxKind.AnonymousObjectCreationExpression boundInitExpression = BindAnonymousObjectCreationExpression( DirectCast(asNew.NewExpression, AnonymousObjectCreationExpressionSyntax), diagnostics) Case Else Throw ExceptionUtilities.UnexpectedValue(asNew.NewExpression.Kind) End Select fieldInitializerSyntax = asNew Else Dim valueSyntax = DirectCast(equalsValueOrAsNewSyntax, EqualsValueSyntax) fieldInitializerSyntax = valueSyntax.Value boundInitExpression = BindValue(DirectCast(fieldInitializerSyntax, ExpressionSyntax), diagnostics) End If If targetType IsNot Nothing Then boundInitExpression = ApplyImplicitConversion(boundInitExpression.Syntax, targetType, boundInitExpression, diagnostics) Else ' Try to reclassify boundInitValue if we still can. boundInitExpression = MakeRValueAndIgnoreDiagnostics(boundInitExpression) End If Return boundInitExpression End Function ''' <summary> ''' Checks for errors in the constant initialization of a field, and only returns a BoundFieldOrPropertyInitializer for ''' decimals and dates because they aren't compile time constant in CLR. Other data type end up directly in metadata and ''' do not cause a BoundFieldOrPropertyInitializer node. ''' </summary> ''' <param name="fieldSymbol">The field symbol.</param> ''' <param name="equalsValueOrAsNewSyntax">The syntax node for the optional initialization.</param> ''' <param name="boundInitializers">The array of bound initializers to add the newly bound ones to.</param> Private Shared Sub BindConstFieldInitializer( fieldSymbol As SourceFieldSymbol, equalsValueOrAsNewSyntax As VisualBasicSyntaxNode, boundInitializers As ArrayBuilder(Of BoundInitializer)) Debug.Assert(fieldSymbol.IsConst) If Not fieldSymbol.IsConstButNotMetadataConstant Then Return End If ' Const fields of type Date or Decimal will get initialized in the synthesized shared constructor ' because their value is not regarded as compile time constant by the CLR. ' This will produce sequence points in the shared constructor which is exactly what Dev10 does. Dim constantValue = fieldSymbol.GetConstantValue(VisualBasic.ConstantFieldsInProgress.Empty) If constantValue IsNot Nothing Then Dim meSymbol As ParameterSymbol = Nothing Dim boundFieldAccessExpr = New BoundFieldAccess(equalsValueOrAsNewSyntax, Nothing, fieldSymbol, True, fieldSymbol.Type) boundFieldAccessExpr.SetWasCompilerGenerated() Dim boundInitValue = New BoundLiteral(equalsValueOrAsNewSyntax, constantValue, fieldSymbol.Type) boundInitializers.Add(New BoundFieldInitializer(equalsValueOrAsNewSyntax, ImmutableArray.Create(Of FieldSymbol)(fieldSymbol), boundFieldAccessExpr, boundInitValue, binderOpt:=Nothing)) End If End Sub ''' <summary> ''' Binds constant initialization value of the field. ''' </summary> ''' <param name="fieldSymbol">The symbol.</param> ''' <param name="equalsValueOrAsNewSyntax">The initialization syntax.</param> ''' <param name="diagnostics">The diagnostics.</param><returns></returns> Friend Function BindFieldAndEnumConstantInitializer( fieldSymbol As FieldSymbol, equalsValueOrAsNewSyntax As VisualBasicSyntaxNode, isEnum As Boolean, diagnostics As BindingDiagnosticBag, <Out> ByRef constValue As ConstantValue ) As BoundExpression constValue = Nothing Dim boundInitValue As BoundExpression = Nothing Dim initValueDiagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, withDependencies:=diagnostics.AccumulatesDependencies) If equalsValueOrAsNewSyntax.Kind = SyntaxKind.EqualsValue Then Dim equalsValueSyntax As EqualsValueSyntax = DirectCast(equalsValueOrAsNewSyntax, EqualsValueSyntax) boundInitValue = BindValue(equalsValueSyntax.Value, initValueDiagnostics) Else ' illegal case, const fields cannot be initialized with AsNew ' all diagnostics here will be ignored because we are just binding for the purpose of storing ' the bound node in a BoundBadNode. The required diagnostics have already been reported in ' SourceFieldSymbol.Type Dim asNewSyntax = DirectCast(equalsValueOrAsNewSyntax, AsNewClauseSyntax) Dim fieldType = If(fieldSymbol.HasDeclaredType, fieldSymbol.Type, GetSpecialType(SpecialType.System_Object, asNewSyntax, BindingDiagnosticBag.Discarded)) ' prevent recursion if field type is inferred. Select Case asNewSyntax.NewExpression.Kind Case SyntaxKind.ObjectCreationExpression Dim objectCreationExpressionSyntax = DirectCast(asNewSyntax.NewExpression, ObjectCreationExpressionSyntax) boundInitValue = BindObjectCreationExpression(asNewSyntax.Type, objectCreationExpressionSyntax.ArgumentList, fieldType, objectCreationExpressionSyntax, BindingDiagnosticBag.Discarded, Nothing) Case SyntaxKind.AnonymousObjectCreationExpression boundInitValue = BindAnonymousObjectCreationExpression( DirectCast(asNewSyntax.NewExpression, AnonymousObjectCreationExpressionSyntax), BindingDiagnosticBag.Discarded) Case Else Throw ExceptionUtilities.UnexpectedValue(asNewSyntax.NewExpression.Kind) End Select boundInitValue = New BoundBadExpression(boundInitValue.Syntax, LookupResultKind.Empty, ImmutableArray(Of Symbol).Empty, ImmutableArray.Create(boundInitValue), fieldType, hasErrors:=True) End If If Not boundInitValue.HasErrors Then Dim targetType As TypeSymbol If fieldSymbol.HasDeclaredType Then targetType = fieldSymbol.Type If isEnum Then targetType = targetType.GetEnumUnderlyingTypeOrSelf End If boundInitValue = ApplyImplicitConversion(boundInitValue.Syntax, targetType, boundInitValue, initValueDiagnostics) Else targetType = If(boundInitValue.Type, ErrorTypeSymbol.UnknownResultType) End If Dim boundInitValueHasErrorsOrConstTypeIsWrong As Boolean = initValueDiagnostics.HasAnyResolvedErrors OrElse fieldSymbol.HasDeclaredType AndAlso Not targetType.IsValidTypeForConstField() ' NOTE: we'll only report ERR_RequiredConstConversion2 ("Conversion from '...' to '.' cannot occur in ' NOTE: a constant expression") and ERR_RequiredConstExpr ("Constant expression is required") in case ' NOTE: the type (if declared) is a valid type for const fields. This is different from Dev10 that sometimes ' NOTE: reported issues and sometimes not ' NOTE: e.g. reports in "const goo as DelegateType = AddressOf methodName" (ERR_ConstAsNonConstant + ERR_RequiredConstExpr) ' NOTE: only type diagnostics for "const s as StructureType = nothing" If boundInitValueHasErrorsOrConstTypeIsWrong Then constValue = Me.GetExpressionConstantValueIfAny(boundInitValue, BindingDiagnosticBag.Discarded, ConstantContext.Default) Else constValue = Me.GetExpressionConstantValueIfAny(boundInitValue, initValueDiagnostics, ConstantContext.Default) End If ' e.g. the init value of "Public goo as Byte = 2.2" is still considered as constant and therefore a CByte(2) ' is being assigned as the constant value of this field/enum. However in case of Option Strict On there has ' been a diagnostics in the call to ApplyImplicitConversion. If constValue Is Nothing Then ' set hasErrors to indicate later check not to add more diagnostics. boundInitValue = BadExpression(boundInitValue.Syntax, boundInitValue, targetType) End If End If diagnostics.AddRange(initValueDiagnostics) initValueDiagnostics.Free() Return boundInitValue End Function ''' <summary> ''' Binds a constant local's value. ''' </summary> ''' <param name="symbol">The local symbol.</param> ''' <param name="type">The local symbol's type. It is passed in because this method is called while the type is being resolved and before it is set.</param> Friend Function BindLocalConstantInitializer(symbol As LocalSymbol, type As TypeSymbol, name As ModifiedIdentifierSyntax, equalsValueOpt As EqualsValueSyntax, diagnostics As BindingDiagnosticBag, <Out> ByRef constValue As ConstantValue) As BoundExpression constValue = Nothing Dim valueExpression As BoundExpression = Nothing If equalsValueOpt IsNot Nothing Then Dim valueSyntax = equalsValueOpt.Value If IsBindingImplicitlyTypedLocal(symbol) Then ReportDiagnostic(diagnostics, name, ERRID.ERR_CircularEvaluation1, symbol) Return BadExpression(valueSyntax, ErrorTypeSymbol.UnknownResultType) End If Dim binder = New LocalInProgressBinder(Me, symbol) valueExpression = binder.BindValue(valueSyntax, diagnostics) ' When inferring the type, the type is nothing. Only apply conversion if there is a type. If there isn't a type then the ' constant gets the expression type and there is no need to apply a conversion. If type IsNot Nothing Then valueExpression = binder.ApplyImplicitConversion(valueSyntax, type, valueExpression, diagnostics) End If If Not valueExpression.HasErrors Then ' ExpressionIsConstant is called to report diagnostics at the correct location in the expression. ' Only call ExpressionIsConstant if the expression is good to avoid reporting a bad expression is not ' a constant. If (valueExpression.Type Is Nothing OrElse Not valueExpression.Type.IsErrorType) Then constValue = binder.GetExpressionConstantValueIfAny(valueExpression, diagnostics, ConstantContext.Default) If constValue IsNot Nothing Then Return valueExpression End If End If ' The result is not a constant and is not marked with hasErrors so return a BadExpression. Return BadExpression(valueSyntax, valueExpression, ErrorTypeSymbol.UnknownResultType).MakeCompilerGenerated() End If Else valueExpression = BadExpression(name, ErrorTypeSymbol.UnknownResultType).MakeCompilerGenerated() ReportDiagnostic(diagnostics, name, ERRID.ERR_ConstantWithNoValue) End If Return valueExpression End Function ''' <summary> ''' Binds a parameter's default value syntax ''' </summary> Friend Function BindParameterDefaultValue( targetType As TypeSymbol, equalsValueSyntax As EqualsValueSyntax, diagnostics As BindingDiagnosticBag, <Out> ByRef constValue As ConstantValue ) As BoundExpression constValue = Nothing Dim boundInitValue As BoundExpression = BindValue(equalsValueSyntax.Value, diagnostics) If Not boundInitValue.HasErrors Then ' Check if the constant can be converted to the parameter type. If Not targetType.IsErrorType Then boundInitValue = ApplyImplicitConversion(boundInitValue.Syntax, targetType, boundInitValue, diagnostics) End If ' Report errors if value is not a constant. constValue = GetExpressionConstantValueIfAny(boundInitValue, diagnostics, ConstantContext.ParameterDefaultValue) If constValue Is Nothing Then boundInitValue = BadExpression(boundInitValue.Syntax, boundInitValue, targetType) End If End If Return boundInitValue End Function End Class End Namespace