diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs index f238992e37eb2ffab4e884802b8b79afd1298571..f766745065930ed374eb476ee984661be6319311 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs @@ -97,7 +97,7 @@ internal struct ProcessedFieldInitializers foreach (FieldOrPropertyInitializer initializer in siblingInitializers) { - FieldSymbol fieldSymbol = initializer.Field; + FieldSymbol fieldSymbol = initializer.FieldOpt; Debug.Assert((object)fieldSymbol != null); // A constant field of type decimal needs a field initializer, so @@ -156,7 +156,7 @@ internal struct ProcessedFieldInitializers for (int j = 0; j < siblingInitializers.Length; j++) { var initializer = siblingInitializers[j]; - var fieldSymbol = initializer.Field; + var fieldSymbol = initializer.FieldOpt; if ((object)fieldSymbol != null && fieldSymbol.IsConst) { diff --git a/src/Compilers/CSharp/Portable/Symbols/FieldOrPropertyInitializer.cs b/src/Compilers/CSharp/Portable/Symbols/FieldOrPropertyInitializer.cs index 92d80709f0c6e35adee95253ffe54894130b1cb2..efc56a5c93633652d67daf13689dd19201ae75ea 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FieldOrPropertyInitializer.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FieldOrPropertyInitializer.cs @@ -11,20 +11,21 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols internal struct FieldOrPropertyInitializer { /// - /// The field being initialized (possibly a backing field of a property), or null if this is a global statement. + /// The field being initialized (possibly a backing field of a property), or null if this is a top-level statement in script code. /// - internal readonly FieldSymbol Field; + internal readonly FieldSymbol FieldOpt; /// - /// A reference to or . + /// A reference to or top-level in script code. /// internal readonly SyntaxReference Syntax; - public FieldOrPropertyInitializer(FieldSymbol field, SyntaxReference syntax) + public FieldOrPropertyInitializer(FieldSymbol fieldOpt, SyntaxNode syntax) { - Debug.Assert(((object)field != null) || (syntax != null)); - Field = field; - Syntax = syntax; + Debug.Assert(syntax.IsKind(SyntaxKind.EqualsValueClause) && fieldOpt != null || syntax is StatementSyntax); + + FieldOpt = fieldOpt; + Syntax = syntax.GetReference(); } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index 19a084d62fbf937930cf97a47a893d8c47a7fffc..93ec94f3074d31a4bf3916cca242cf647b5fc584 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -2110,10 +2110,10 @@ private static void AddNestedTypesToDictionary(Dictionary NonTypeNonIndexerMembers = ArrayBuilder.GetInstance(); - public ArrayBuilder> StaticInitializers = ArrayBuilder>.GetInstance(); - public ArrayBuilder> InstanceInitializers = ArrayBuilder>.GetInstance(); - public ArrayBuilder IndexerDeclarations = ArrayBuilder.GetInstance(); + public readonly ArrayBuilder NonTypeNonIndexerMembers = ArrayBuilder.GetInstance(); + public readonly ArrayBuilder> StaticInitializers = ArrayBuilder>.GetInstance(); + public readonly ArrayBuilder> InstanceInitializers = ArrayBuilder>.GetInstance(); + public readonly ArrayBuilder IndexerDeclarations = ArrayBuilder.GetInstance(); public MembersAndInitializers ToReadOnlyAndFree() { @@ -2477,8 +2477,6 @@ private static bool ParametersMatchEventAccessor(EventSymbol eventSymbol, Immuta private void AddEnumMembers(MembersAndInitializersBuilder result, EnumDeclarationSyntax syntax, DiagnosticBag diagnostics) { - ArrayBuilder initializers = null; - // The previous enum constant used to calculate subsequent // implicit enum constants. (This is the most recent explicit // enum constant or the first implicit constant if no explicit values.) @@ -2487,71 +2485,55 @@ private void AddEnumMembers(MembersAndInitializersBuilder result, EnumDeclaratio // Offset from "otherSymbol". int otherSymbolOffset = 0; - foreach (var m in syntax.Members) + foreach (var member in syntax.Members) { - switch (m.Kind()) - { - case SyntaxKind.EnumMemberDeclaration: - { - SourceEnumConstantSymbol symbol; - var valueOpt = m.EqualsValue; - - if (valueOpt != null) - { - symbol = SourceEnumConstantSymbol.CreateExplicitValuedConstant(this, m, diagnostics); - } - else - { - symbol = SourceEnumConstantSymbol.CreateImplicitValuedConstant(this, m, otherSymbol, otherSymbolOffset, diagnostics); - } + SourceEnumConstantSymbol symbol; + var valueOpt = member.EqualsValue; - result.NonTypeNonIndexerMembers.Add(symbol); - - if ((valueOpt != null) || ((object)otherSymbol == null)) - { - otherSymbol = symbol; - otherSymbolOffset = 1; - } - else - { - otherSymbolOffset++; - } + if (valueOpt != null) + { + symbol = SourceEnumConstantSymbol.CreateExplicitValuedConstant(this, member, diagnostics); + } + else + { + symbol = SourceEnumConstantSymbol.CreateImplicitValuedConstant(this, member, otherSymbol, otherSymbolOffset, diagnostics); + } - // The symbol is added to the set of initializers, even for - // implicit values since it's necessary to generate constants - // for each member to catch errors such as overflow. - AddInitializer(ref initializers, symbol, valueOpt); - } - break; + result.NonTypeNonIndexerMembers.Add(symbol); - default: - throw ExceptionUtilities.UnexpectedValue(m.Kind()); + if (valueOpt != null || (object)otherSymbol == null) + { + otherSymbol = symbol; + otherSymbolOffset = 1; + } + else + { + otherSymbolOffset++; } } - - AddInitializers(ref result.StaticInitializers, initializers); } - private static void AddInitializer(ref ArrayBuilder initializers, FieldSymbol field, CSharpSyntaxNode node) + private static void AddInitializer(ref ArrayBuilder initializers, FieldSymbol fieldOpt, CSharpSyntaxNode node) { if (initializers == null) { initializers = new ArrayBuilder(); } + else + { + // initializers should be added in syntax order: + Debug.Assert(node.SyntaxTree == initializers.Last().Syntax.SyntaxTree); + Debug.Assert(node.SpanStart > initializers.Last().Syntax.GetSyntax().SpanStart); + } - initializers.Add(new FieldOrPropertyInitializer(field, node.GetReferenceOrNull())); + initializers.Add(new FieldOrPropertyInitializer(fieldOpt, node)); } - private static void AddInitializers(ref ArrayBuilder> allInitializers, ArrayBuilder siblings) + private static void AddInitializers(ArrayBuilder> allInitializers, ArrayBuilder siblingsOpt) { - if (siblings != null) + if (siblingsOpt != null) { - if (allInitializers == null) - { - allInitializers = new ArrayBuilder>(); - } - - allInitializers.Add(siblings.ToImmutableAndFree()); + allInitializers.Add(siblingsOpt.ToImmutableAndFree()); } } @@ -2647,11 +2629,11 @@ private void CheckForStructBadInitializers(MembersAndInitializersBuilder builder Debug.Assert(TypeKind == TypeKind.Struct); foreach (var initializers in builder.InstanceInitializers) - { + { foreach (FieldOrPropertyInitializer initializer in initializers) - { - // '{0}': cannot have instance field initializers in structs - diagnostics.Add(ErrorCode.ERR_FieldInitializerInStruct, (initializer.Field.AssociatedSymbol ?? initializer.Field).Locations[0], this); + { + // '{0}': cannot have instance field initializers in structs + diagnostics.Add(ErrorCode.ERR_FieldInitializerInStruct, (initializer.FieldOpt.AssociatedSymbol ?? initializer.FieldOpt).Locations[0], this); } } } @@ -2677,6 +2659,7 @@ private void AddSynthesizedConstructorsIfNecessary(ArrayBuilder members, hasInstanceConstructor = true; hasParameterlessInstanceConstructor = hasParameterlessInstanceConstructor || method.ParameterCount == 0; break; + case MethodKind.StaticConstructor: hasStaticConstructor = true; break; @@ -2690,27 +2673,11 @@ private void AddSynthesizedConstructorsIfNecessary(ArrayBuilder members, } } - var hasStaticInitializer = false; - if (staticInitializers != null) - { - foreach (var siblings in staticInitializers) - { - foreach (var initializer in siblings) - { - // constants don't count, since they do not exist as fields at runtime - // NOTE: even for decimal constants (which require field initializers), - // we do not create .cctor here since a static constructor implicitly created for a decimal - // should not appear in the list returned by public API like GetMembers(). - if (!initializer.Field.IsConst) - { - hasStaticInitializer = true; - goto OUTER; - } - } - } - } - - OUTER: + // constants don't count, since they do not exist as fields at runtime + // NOTE: even for decimal constants (which require field initializers), + // we do not create .cctor here since a static constructor implicitly created for a decimal + // should not appear in the list returned by public API like GetMembers(). + var hasStaticInitializer = HasNonConstantInitializer(staticInitializers); // NOTE: Per section 11.3.8 of the spec, "every struct implicitly has a parameterless instance constructor". // We won't insert a parameterless constructor for a struct if there already is one. @@ -2735,6 +2702,25 @@ private void AddSynthesizedConstructorsIfNecessary(ArrayBuilder members, } } + private static bool HasNonConstantInitializer(ArrayBuilder> initializers) + { + if (initializers != null) + { + foreach (var siblings in initializers) + { + foreach (var initializer in siblings) + { + if (!initializer.FieldOpt.IsConst) + { + return true; + } + } + } + } + + return false; + } + private void AddNonTypeMembers( MembersAndInitializersBuilder result, SyntaxList members, @@ -3014,8 +3000,8 @@ private void AddSynthesizedConstructorsIfNecessary(ArrayBuilder members, } } - AddInitializers(ref result.InstanceInitializers, instanceInitializers); - AddInitializers(ref result.StaticInitializers, staticInitializers); + AddInitializers(result.InstanceInitializers, instanceInitializers); + AddInitializers(result.StaticInitializers, staticInitializers); } private static bool IsGlobalCodeAllowed(CSharpSyntaxNode parent) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index 7ec50dea5afc824a150939f52869fe7340d94c0c..d08feb917c159f32fc3c552fccbeddba32b92808 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -990,7 +990,7 @@ internal override void PostDecodeWellKnownAttributes(ImmutableArray, ''' , ''' , - ''' (top-level statement), or - ''' Nothing (enums field with an implicit value). + ''' (top-level statement). ''' Public ReadOnly Syntax As SyntaxReference @@ -29,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' ''' The initializer syntax for the statement. Public Sub New(syntax As SyntaxReference) - Debug.Assert(syntax IsNot Nothing) + Debug.Assert(TypeOf syntax.GetSyntax() Is StatementSyntax) Me.Syntax = syntax End Sub @@ -40,10 +39,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' The initializer syntax for the field. Public Sub New(field As FieldSymbol, syntax As SyntaxReference) Debug.Assert(field IsNot Nothing) - Debug.Assert(syntax Is Nothing OrElse - syntax.GetVisualBasicSyntax.Kind = SyntaxKind.AsNewClause OrElse - syntax.GetVisualBasicSyntax.Kind = SyntaxKind.EqualsValue OrElse - syntax.GetVisualBasicSyntax.Kind = SyntaxKind.ModifiedIdentifier) + Debug.Assert(syntax.GetSyntax().IsKind(SyntaxKind.AsNewClause) OrElse + syntax.GetSyntax().IsKind(SyntaxKind.EqualsValue) OrElse + syntax.GetSyntax().IsKind(SyntaxKind.ModifiedIdentifier)) Me.FieldsOrProperty = ImmutableArray.Create(Of Symbol)(field) Me.Syntax = syntax @@ -54,7 +52,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' Public Sub New(fieldsOrProperties As ImmutableArray(Of Symbol), syntax As SyntaxReference) Debug.Assert(Not fieldsOrProperties.IsEmpty) - Debug.Assert(syntax.GetSyntax.Kind = SyntaxKind.AsNewClause OrElse syntax.GetSyntax.Kind = SyntaxKind.EqualsValue) + Debug.Assert(syntax.GetSyntax().IsKind(SyntaxKind.AsNewClause) OrElse syntax.GetSyntax().IsKind(SyntaxKind.EqualsValue)) Me.FieldsOrProperty = fieldsOrProperties Me.Syntax = syntax @@ -68,7 +66,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Public Sub New([property] As PropertySymbol, syntax As SyntaxReference) Debug.Assert([property] IsNot Nothing) Debug.Assert(syntax IsNot Nothing) - Debug.Assert(syntax.GetSyntax.Kind = SyntaxKind.AsNewClause OrElse syntax.GetSyntax.Kind = SyntaxKind.EqualsValue) + Debug.Assert(syntax.GetSyntax().IsKind(SyntaxKind.AsNewClause) OrElse syntax.GetSyntax().IsKind(SyntaxKind.EqualsValue)) Me.FieldsOrProperty = ImmutableArray.Create(Of Symbol)([property]) Me.Syntax = syntax diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb index d194a588625461ca214d7e73446b22118656840a..9dc7752bb44d10e4c16e547bf8d8df4534000e16 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMemberContainerTypeSymbol.vb @@ -1555,13 +1555,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' Adds a field initializer for the field to list of field initializers ''' ''' All initializers. - ''' The field initializer to add to the list of initializers. - Friend Shared Sub AddInitializer(ByRef initializers As ArrayBuilder(Of FieldOrPropertyInitializer), fieldInitializer As FieldOrPropertyInitializer) + ''' The field initializer to add to the list of initializers. + Friend Shared Sub AddInitializer(ByRef initializers As ArrayBuilder(Of FieldOrPropertyInitializer), initializer As FieldOrPropertyInitializer) If initializers Is Nothing Then initializers = ArrayBuilder(Of FieldOrPropertyInitializer).GetInstance() + Else + ' initializers should be added in syntax order + Debug.Assert(initializer.Syntax.SyntaxTree Is initializers.Last().Syntax.SyntaxTree) + Debug.Assert(initializer.Syntax.Span.Start > initializers.Last().Syntax.Span.Start) End If - initializers.Add(fieldInitializer) + initializers.Add(initializer) End Sub ''' diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol.vb index 72b07c7325c97ab3a564683cb5fa6f2c36797510..8e8c6ca95e9951e957593963ad25e2cb30275c52 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceNamedTypeSymbol.vb @@ -256,7 +256,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ElseIf TypeKind = TypeKind.Enum Then Dim enumBlock = DirectCast(node, EnumBlockSyntax) - AddEnumMembers(enumBlock, binder, diagBag, members, staticInitializers) + AddEnumMembers(enumBlock, binder, diagBag, members) Else Dim typeBlock = DirectCast(node, TypeBlockSyntax) For Each memberSyntax In typeBlock.Members @@ -682,10 +682,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Sub Private Sub AddEnumMembers(syntax As EnumBlockSyntax, - bodyBinder As Binder, - diagnostics As DiagnosticBag, - members As MembersAndInitializersBuilder, - ByRef staticInitializers As ArrayBuilder(Of FieldOrPropertyInitializer)) + bodyBinder As Binder, + diagnostics As DiagnosticBag, + members As MembersAndInitializersBuilder) Dim valField = New SynthesizedFieldSymbol( Me, @@ -705,43 +704,35 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ' Offset from "otherSymbol". Dim otherSymbolOffset As Integer = 0 - Dim memberList = syntax.Members - - If memberList.Count = 0 Then + If syntax.Members.Count = 0 Then Binder.ReportDiagnostic(diagnostics, syntax.EnumStatement.Identifier, ERRID.ERR_BadEmptyEnum1, syntax.EnumStatement.Identifier.ValueText) - Else - For Each member In syntax.Members - If member.Kind <> SyntaxKind.EnumMemberDeclaration Then - ' skip invalid syntax - Continue For - End If - - Dim declaration = DirectCast(member, EnumMemberDeclarationSyntax) - Dim symbol As SourceEnumConstantSymbol - Dim valueOpt = declaration.Initializer - If valueOpt IsNot Nothing Then - symbol = SourceEnumConstantSymbol.CreateExplicitValuedConstant(Me, bodyBinder, declaration, diagnostics) - Else - symbol = SourceEnumConstantSymbol.CreateImplicitValuedConstant(Me, bodyBinder, declaration, otherSymbol, otherSymbolOffset, diagnostics) - End If + Return + End If - If (valueOpt IsNot Nothing) OrElse (otherSymbol Is Nothing) Then - otherSymbol = symbol - otherSymbolOffset = 1 - Else - otherSymbolOffset = otherSymbolOffset + 1 - End If + For Each member In syntax.Members + If member.Kind <> SyntaxKind.EnumMemberDeclaration Then + ' skip invalid syntax + Continue For + End If - AddMember(symbol, bodyBinder, members, omitDiagnostics:=False) + Dim declaration = DirectCast(member, EnumMemberDeclarationSyntax) + Dim symbol As SourceEnumConstantSymbol + Dim valueOpt = declaration.Initializer + If valueOpt IsNot Nothing Then + symbol = SourceEnumConstantSymbol.CreateExplicitValuedConstant(Me, bodyBinder, declaration, diagnostics) + Else + symbol = SourceEnumConstantSymbol.CreateImplicitValuedConstant(Me, bodyBinder, declaration, otherSymbol, otherSymbolOffset, diagnostics) + End If - Dim initializer = New FieldOrPropertyInitializer(symbol, If(valueOpt IsNot Nothing, bodyBinder.GetSyntaxReference(valueOpt), Nothing)) + If (valueOpt IsNot Nothing) OrElse (otherSymbol Is Nothing) Then + otherSymbol = symbol + otherSymbolOffset = 1 + Else + otherSymbolOffset = otherSymbolOffset + 1 + End If - ' The symbol is added to the set of initializers, even for - ' implicit values since it's necessary to generate constants - ' for each member to catch errors such as overflow. - SourceNamedTypeSymbol.AddInitializer(staticInitializers, initializer) - Next - End If + AddMember(symbol, bodyBinder, members, omitDiagnostics:=False) + Next End Sub #End Region