From 8c28e241c105a55daa1a7505e07050483ba009a6 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 10 Apr 2020 20:52:53 -0400 Subject: [PATCH 01/23] Decode ModuleInitializerAttribute to SourceMethodSymbolWithAttributes.IsModuleInitializer --- .../Symbols/Attributes/AttributeData.cs | 6 +++ .../MethodWellKnownAttributeData.cs | 16 ++++++++ .../SourceMethodSymbolWithAttributes.cs | 6 +++ .../Symbol/Symbols/ModuleInitializersTests.cs | 39 +++++++++++++++++++ .../Attributes/AttributeDescription.cs | 3 ++ .../Portable/Traits/CompilerFeature.cs | 1 + 6 files changed, 71 insertions(+) create mode 100644 src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs index 3b7206d7ed084..301239ce1cfdd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs @@ -660,6 +660,12 @@ private protected sealed override bool IsStringProperty(string memberName) return false; } + internal static void DecodeModuleInitializerAttribute(ref DecodeWellKnownAttributeArguments arguments) + { + // TODO: diagnostics + arguments.GetOrCreateData().HasModuleInitializerAttribute = true; + } + #endregion /// diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/MethodWellKnownAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/MethodWellKnownAttributeData.cs index 386d004801376..4d174fe04a842 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/MethodWellKnownAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/MethodWellKnownAttributeData.cs @@ -44,6 +44,22 @@ public bool HasSkipLocalsInitAttribute } } + private bool _hasModuleInitializerAttribute; + public bool HasModuleInitializerAttribute + { + get + { + VerifySealed(expected: true); + return _hasModuleInitializerAttribute; + } + set + { + VerifySealed(expected: false); + _hasModuleInitializerAttribute = value; + SetDataStored(); + } + } + private ImmutableArray _memberNotNullAttributeData = ImmutableArray.Empty; public void AddNotNullMember(string memberName) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 3ce3227735ae3..3ee67c7722566 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -482,6 +482,10 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut MessageID.IDS_FeatureMemberNotNull.CheckFeatureAvailability(arguments.Diagnostics, arguments.AttributeSyntaxOpt); CSharpAttributeData.DecodeMemberNotNullWhenAttribute(ContainingType, ref arguments); } + else if (attribute.IsTargetAttribute(this, AttributeDescription.ModuleInitializerAttribute)) + { + CSharpAttributeData.DecodeModuleInitializerAttribute(ref arguments); + } else { var compilation = this.DeclaringCompilation; @@ -1012,5 +1016,7 @@ internal override System.Reflection.MethodImplAttributes ImplementationAttribute return result; } } + + internal bool IsModuleInitializer => GetDecodedWellKnownAttributeData()?.HasModuleInitializerAttribute ?? false; } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs new file mode 100644 index 0000000000000..d474c5951770b --- /dev/null +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs @@ -0,0 +1,39 @@ +// 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. + +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols +{ + [CompilerTrait(CompilerFeature.ModuleInitializers)] + public sealed class ModuleInitializersTests : CSharpTestBase + { + private static readonly CSharpParseOptions s_parseOptions = TestOptions.RegularPreview; + + [Fact] + public static void ModuleInitializerAttributeIsDecoded() + { + var source = +@"using System.Runtime.CompilerServices; + +class C +{ + [ModuleInitializer] + internal static void M1() { } + + internal static void M2() { } +} + +namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : System.Attribute { } } +"; + var compilation = CreateCompilation(source, parseOptions: s_parseOptions); + + Assert.True(compilation.GetMember("C.M1").IsModuleInitializer); + Assert.False(compilation.GetMember("C.M2").IsModuleInitializer); + } + } +} diff --git a/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs b/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs index 7ac415b963564..f9cbe8c2d133f 100644 --- a/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs +++ b/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs @@ -428,6 +428,8 @@ static AttributeDescription() private static readonly byte[][] s_signaturesOfEnumeratorCancellationAttribute = { s_signature_HasThis_Void }; private static readonly byte[][] s_signaturesOfNativeIntegerAttribute = { s_signature_HasThis_Void, s_signature_HasThis_Void_SzArray_Boolean }; + private static readonly byte[][] s_signaturesOfModuleInitializerAttribute = { s_signature_HasThis_Void }; + // early decoded attributes: internal static readonly AttributeDescription OptionalAttribute = new AttributeDescription("System.Runtime.InteropServices", "OptionalAttribute", s_signaturesOfOptionalAttribute); internal static readonly AttributeDescription ComImportAttribute = new AttributeDescription("System.Runtime.InteropServices", "ComImportAttribute", s_signaturesOfComImportAttribute); @@ -559,5 +561,6 @@ static AttributeDescription() internal static readonly AttributeDescription EnumeratorCancellationAttribute = new AttributeDescription("System.Runtime.CompilerServices", "EnumeratorCancellationAttribute", s_signaturesOfEnumeratorCancellationAttribute); internal static readonly AttributeDescription SkipLocalsInitAttribute = new AttributeDescription("System.Runtime.CompilerServices", "SkipLocalsInitAttribute", s_signaturesOfSkipLocalsInitAttribute); internal static readonly AttributeDescription NativeIntegerAttribute = new AttributeDescription("System.Runtime.CompilerServices", "NativeIntegerAttribute", s_signaturesOfNativeIntegerAttribute); + internal static readonly AttributeDescription ModuleInitializerAttribute = new AttributeDescription("System.Runtime.CompilerServices", "ModuleInitializerAttribute", s_signaturesOfModuleInitializerAttribute); } } diff --git a/src/Test/Utilities/Portable/Traits/CompilerFeature.cs b/src/Test/Utilities/Portable/Traits/CompilerFeature.cs index 618e811949382..efcd371c5fd75 100644 --- a/src/Test/Utilities/Portable/Traits/CompilerFeature.cs +++ b/src/Test/Utilities/Portable/Traits/CompilerFeature.cs @@ -35,5 +35,6 @@ public enum CompilerFeature DefaultInterfaceImplementation, LambdaDiscardParameters, StatementAttributes, + ModuleInitializers, } } From 223ef89403cdf4fdeb0d859f8ea658ca5995c23a Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 10 Apr 2020 20:55:58 -0400 Subject: [PATCH 02/23] Check feature availability --- .../CSharp/Portable/CSharpResources.resx | 3 +++ .../CSharp/Portable/Errors/MessageID.cs | 2 ++ .../SourceMethodSymbolWithAttributes.cs | 1 + .../Portable/xlf/CSharpResources.cs.xlf | 5 ++++ .../Portable/xlf/CSharpResources.de.xlf | 5 ++++ .../Portable/xlf/CSharpResources.es.xlf | 5 ++++ .../Portable/xlf/CSharpResources.fr.xlf | 5 ++++ .../Portable/xlf/CSharpResources.it.xlf | 5 ++++ .../Portable/xlf/CSharpResources.ja.xlf | 5 ++++ .../Portable/xlf/CSharpResources.ko.xlf | 5 ++++ .../Portable/xlf/CSharpResources.pl.xlf | 5 ++++ .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 ++++ .../Portable/xlf/CSharpResources.ru.xlf | 5 ++++ .../Portable/xlf/CSharpResources.tr.xlf | 5 ++++ .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 ++++ .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 ++++ .../Symbol/Symbols/ModuleInitializersTests.cs | 23 +++++++++++++++++++ 17 files changed, 94 insertions(+) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 4981411e47760..e387c734d322d 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6070,4 +6070,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Generator failed to initialize. + + module initializers + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index ee1d0255674a3..d2329b8d3dcc6 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -192,6 +192,7 @@ internal enum MessageID IDS_FeatureMemberNotNull = MessageBase + 12768, IDS_FeatureNativeInt = MessageBase + 12769, IDS_FeatureTargetTypedObjectCreation = MessageBase + 12770, + IDS_FeatureModuleInitializers = MessageBase + 12771, } // Message IDs may refer to strings that need to be localized. @@ -305,6 +306,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureTargetTypedObjectCreation: // syntax check case MessageID.IDS_FeatureMemberNotNull: case MessageID.IDS_FeatureNativeInt: + case MessageID.IDS_FeatureModuleInitializers: return LanguageVersion.Preview; // C# 8.0 features. diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 3ee67c7722566..064088f223c28 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -484,6 +484,7 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut } else if (attribute.IsTargetAttribute(this, AttributeDescription.ModuleInitializerAttribute)) { + MessageID.IDS_FeatureModuleInitializers.CheckFeatureAvailability(arguments.Diagnostics, arguments.AttributeSyntaxOpt); CSharpAttributeData.DecodeModuleInitializerAttribute(ref arguments); } else diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 02b6b217a6448..b39fcbe52c435 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -944,6 +944,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions skrývání názvů ve vnořených funkcích diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 95c16ceb7d483..04b174f9cbf0f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -944,6 +944,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions Namensshadowing in geschachtelten Funktionen diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index f032e1a84a4d3..f8015cef27a13 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -944,6 +944,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions sombreado de nombres en funciones anidadas diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 433368bae8306..7c4b760486aef 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -944,6 +944,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions ombrage des noms dans les fonctions imbriquées diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index d5108b13b04d6..a4cd4a2d67dd5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -944,6 +944,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions shadowing dei nomi nelle funzioni annidate diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index b6db6db127f48..99fbe3822140e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -944,6 +944,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions 入れ子になった関数での名前シャドウイング diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 3f872fc92b216..154579a6a7a80 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -944,6 +944,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions 중첩된 함수의 이름 섀도잉 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 3b6a62eb48926..2c439b0e07cc1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -944,6 +944,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions zasłanianie nazw w funkcjach zagnieżdżonych diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 6831addc21819..2e5969e6d693e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -942,6 +942,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions sombreamento de nome em funções aninhadas diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 4f91d6c1c484d..e28f4d86368e1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -944,6 +944,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions скрытие имен во вложенных функциях diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index d31f31ac9e803..8ccd36ec4df97 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -944,6 +944,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions iç içe işlevlerde ad gölgeleme diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 16152ea3cb142..c95cdc3fd9cf0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -944,6 +944,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions 在嵌套函数中的名称映射 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 2da8f95ee52f8..b27990eac0b14 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -944,6 +944,11 @@ MemberNotNull attribute + + module initializers + module initializers + + name shadowing in nested functions 巢狀函式中的名稱鏡像處理 diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs index d474c5951770b..15b0d0081b529 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs @@ -35,5 +35,28 @@ namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : S Assert.True(compilation.GetMember("C.M1").IsModuleInitializer); Assert.False(compilation.GetMember("C.M2").IsModuleInitializer); } + + [Fact] + public static void ModuleInitializersNotUsableInCSharp8() + { + var source = +@"using System.Runtime.CompilerServices; + +class C +{ + [ModuleInitializer] + internal static void M() { } +} + +namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : System.Attribute { } } +"; + var compilation = CreateCompilation(source, parseOptions: TestOptions.Regular8); + + compilation.VerifyDiagnostics( + // (5,6): error CS8652: The feature 'module initializers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [ModuleInitializer] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "ModuleInitializer").WithArguments("module initializers").WithLocation(5, 6) + ); + } } } From a51bac27632edb912c9756e63eb707f0dafbc58c Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 10 Apr 2020 21:09:49 -0400 Subject: [PATCH 03/23] Test for simple success case --- .../Symbol/Symbols/ModuleInitializersTests.cs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs index 15b0d0081b529..9f14c1424899a 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs @@ -58,5 +58,48 @@ namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : S Diagnostic(ErrorCode.ERR_FeatureInPreview, "ModuleInitializer").WithArguments("module initializers").WithLocation(5, 6) ); } + + [Fact] + public void ModuleTypeStaticConstructorIsNotEmittedWhenNoMethodIsMarkedWithModuleInitializerAttribute() + { + string source = @" +using System.Runtime.CompilerServices; + +class C +{ + internal static void M() { } +} + +namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : System.Attribute { } } +"; + var verifier = CompileAndVerify(source, parseOptions: s_parseOptions); + + verifier.VerifyMemberInIL("..cctor", expected: false); + } + + [Fact] + public void ModuleTypeStaticConstructorCallsMethodMarkedWithModuleInitializerAttribute() + { + string source = @" +using System.Runtime.CompilerServices; + +class C +{ + [ModuleInitializer] + internal static void M() { } +} + +namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : System.Attribute { } } +"; + var verifier = CompileAndVerify(source, parseOptions: s_parseOptions); + + verifier.VerifyIL("..cctor", @" +{ + // Code size 6 (0x6) + .maxstack 0 + IL_0000: call ""void C.M()"" + IL_0005: ret +}"); + } } } From 44d207d5c538a0a4da6aeb3f343ecb2e9f2be39d Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 10 Apr 2020 21:13:27 -0400 Subject: [PATCH 04/23] Method is not specific to PrivateImplementationDetails --- src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs | 4 ++-- .../VisualBasic/Portable/Compilation/MethodCompiler.vb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index d52e5c874da8e..d2d780bd205e5 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -641,12 +641,12 @@ private void CompileNamedType(NamedTypeSymbol containingType) compilationState.Free(); } - private void CompileSynthesizedMethods(PrivateImplementationDetails privateImplClass, DiagnosticBag diagnostics) + private void CompileSynthesizedMethods(Cci.INamespaceTypeDefinition synthesizedTopLevelType, DiagnosticBag diagnostics) { Debug.Assert(_moduleBeingBuiltOpt != null); var compilationState = new TypeCompilationState(null, _compilation, _moduleBeingBuiltOpt); - foreach (MethodSymbol method in privateImplClass.GetMethods(new EmitContext(_moduleBeingBuiltOpt, null, diagnostics, metadataOnly: false, includePrivateMembers: true))) + foreach (MethodSymbol method in synthesizedTopLevelType.GetMethods(new EmitContext(_moduleBeingBuiltOpt, null, diagnostics, metadataOnly: false, includePrivateMembers: true))) { Debug.Assert(method.SynthesizesLoweredBoundBody); method.GenerateMethodBody(compilationState, diagnostics); diff --git a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb index b47b9b13a04a9..842215532bb30 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb @@ -838,7 +838,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return Nothing End Function - Private Sub CompileSynthesizedMethods(privateImplClass As PrivateImplementationDetails) + Private Sub CompileSynthesizedMethods(privateImplClass As Cci.INamespaceTypeDefinition) Debug.Assert(_moduleBeingBuiltOpt IsNot Nothing) Dim compilationState As New TypeCompilationState(_compilation, _moduleBeingBuiltOpt, initializeComponentOpt:=Nothing) From ee873abcc14d95c816890ef469425cae83fc3467 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 10 Apr 2020 21:21:52 -0400 Subject: [PATCH 05/23] Simplify RootModuleType.cs --- .../Core/Portable/PEWriter/RootModuleType.cs | 391 +++++------------- 1 file changed, 105 insertions(+), 286 deletions(-) diff --git a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs index 64ce7bc27441f..18af5ac31ef6c 100644 --- a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs @@ -4,12 +4,11 @@ #nullable enable -using System; using System.Collections.Generic; -using System.Runtime.InteropServices; using System.Reflection.Metadata; +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.Emit; using Roslyn.Utilities; -using EmitContext = Microsoft.CodeAnalysis.Emit.EmitContext; namespace Microsoft.Cci { @@ -18,288 +17,108 @@ namespace Microsoft.Cci /// internal class RootModuleType : INamespaceTypeDefinition { - public TypeDefinitionHandle TypeDef - { - get { return default(TypeDefinitionHandle); } - } - - public ITypeDefinition ResolvedType - { - get { return this; } - } - - public IEnumerable GetAttributes(EmitContext context) - { - return SpecializedCollections.EmptyEnumerable(); - } - - public bool MangleName - { - get { return false; } - } - - public string Name - { - get { return ""; } - } - - public ushort Alignment - { - get { return 0; } - } - - public ITypeReference? GetBaseClass(EmitContext context) - { - return null; - } - - public IEnumerable GetEvents(EmitContext context) - { - return SpecializedCollections.EmptyEnumerable(); - } - - public IEnumerable GetExplicitImplementationOverrides(EmitContext context) - { - return SpecializedCollections.EmptyEnumerable(); - } - - public IEnumerable GetFields(EmitContext context) - { - return SpecializedCollections.EmptyEnumerable(); - } - - public bool HasDeclarativeSecurity - { - get { return false; } - } - - public IEnumerable Interfaces(EmitContext context) - { - return SpecializedCollections.EmptyEnumerable(); - } - - public bool IsAbstract - { - get { return false; } - } - - public bool IsBeforeFieldInit - { - get { return false; } - } - - public bool IsComObject - { - get { return false; } - } - - public bool IsGeneric - { - get { return false; } - } - - public bool IsInterface - { - get { return false; } - } - - public bool IsDelegate - { - get { return false; } - } - - public bool IsRuntimeSpecial - { - get { return false; } - } - - public bool IsSerializable - { - get { return false; } - } - - public bool IsSpecialName - { - get { return false; } - } - - public bool IsWindowsRuntimeImport - { - get { return false; } - } - - public bool IsSealed - { - get { return false; } - } - - public LayoutKind Layout - { - get { return LayoutKind.Auto; } - } - - public IEnumerable GetMethods(EmitContext context) - { - return SpecializedCollections.EmptyEnumerable(); - } - - public IEnumerable GetNestedTypes(EmitContext context) - { - return SpecializedCollections.EmptyEnumerable(); - } - - public IEnumerable GetProperties(EmitContext context) - { - return SpecializedCollections.EmptyEnumerable(); - } - - public uint SizeOf - { - get { return 0; } - } - - public CharSet StringFormat - { - get { return CharSet.Ansi; } - } - - public bool IsPublic - { - get { return false; } - } - - public bool IsNested - { - get { return false; } - } - - IEnumerable ITypeDefinition.GenericParameters - { - get { throw ExceptionUtilities.Unreachable; } - } - - ushort ITypeDefinition.GenericParameterCount - { - get - { - return 0; - } - } - - IEnumerable ITypeDefinition.SecurityAttributes - { - get { throw ExceptionUtilities.Unreachable; } - } - - void IReference.Dispatch(MetadataVisitor visitor) - { - throw ExceptionUtilities.Unreachable; - } - - bool ITypeReference.IsEnum - { - get { throw ExceptionUtilities.Unreachable; } - } - - bool ITypeReference.IsValueType - { - get { throw ExceptionUtilities.Unreachable; } - } - - ITypeDefinition ITypeReference.GetResolvedType(EmitContext context) - { - return this; - } - - PrimitiveTypeCode ITypeReference.TypeCode - { - get { throw ExceptionUtilities.Unreachable; } - } - - ushort INamedTypeReference.GenericParameterCount - { - get { throw ExceptionUtilities.Unreachable; } - } - - IUnitReference INamespaceTypeReference.GetUnit(EmitContext context) - { - throw ExceptionUtilities.Unreachable; - } - - string INamespaceTypeReference.NamespaceName - { - get - { - return string.Empty; - } - } - - IGenericMethodParameterReference? ITypeReference.AsGenericMethodParameterReference - { - get - { - return null; - } - } - - IGenericTypeInstanceReference? ITypeReference.AsGenericTypeInstanceReference - { - get - { - return null; - } - } - - IGenericTypeParameterReference? ITypeReference.AsGenericTypeParameterReference - { - get - { - return null; - } - } - - INamespaceTypeDefinition ITypeReference.AsNamespaceTypeDefinition(EmitContext context) - { - return this; - } - - INamespaceTypeReference ITypeReference.AsNamespaceTypeReference - { - get - { - return this; - } - } - - INestedTypeDefinition? ITypeReference.AsNestedTypeDefinition(EmitContext context) - { - return null; - } - - INestedTypeReference? ITypeReference.AsNestedTypeReference - { - get - { - return null; - } - } - - ISpecializedNestedTypeReference? ITypeReference.AsSpecializedNestedTypeReference - { - get - { - return null; - } - } - - ITypeDefinition ITypeReference.AsTypeDefinition(EmitContext context) - { - return this; - } - - IDefinition IReference.AsDefinition(EmitContext context) - { - return this; - } + public TypeDefinitionHandle TypeDef => default; + + public ITypeDefinition ResolvedType => this; + + public IEnumerable GetAttributes(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + + public bool MangleName => false; + + public string Name => ""; + + public ushort Alignment => 0; + + public ITypeReference? GetBaseClass(EmitContext context) => null; + + public IEnumerable GetEvents(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + + public IEnumerable GetExplicitImplementationOverrides(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + + public IEnumerable GetFields(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + + public bool HasDeclarativeSecurity => false; + + public IEnumerable Interfaces(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + + public bool IsAbstract => false; + + public bool IsBeforeFieldInit => false; + + public bool IsComObject => false; + + public bool IsGeneric => false; + + public bool IsInterface => false; + + public bool IsDelegate => false; + + public bool IsRuntimeSpecial => false; + + public bool IsSerializable => false; + + public bool IsSpecialName => false; + + public bool IsWindowsRuntimeImport => false; + + public bool IsSealed => false; + + public LayoutKind Layout => LayoutKind.Auto; + + public IEnumerable GetMethods(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + + public IEnumerable GetNestedTypes(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + + public IEnumerable GetProperties(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + + public uint SizeOf => 0; + + public CharSet StringFormat => CharSet.Ansi; + + public bool IsPublic => false; + + public bool IsNested => false; + + IEnumerable ITypeDefinition.GenericParameters => throw ExceptionUtilities.Unreachable; + + ushort ITypeDefinition.GenericParameterCount => 0; + + IEnumerable ITypeDefinition.SecurityAttributes => throw ExceptionUtilities.Unreachable; + + void IReference.Dispatch(MetadataVisitor visitor) => throw ExceptionUtilities.Unreachable; + + bool ITypeReference.IsEnum => throw ExceptionUtilities.Unreachable; + + bool ITypeReference.IsValueType => throw ExceptionUtilities.Unreachable; + + ITypeDefinition ITypeReference.GetResolvedType(EmitContext context) => this; + + PrimitiveTypeCode ITypeReference.TypeCode => throw ExceptionUtilities.Unreachable; + + ushort INamedTypeReference.GenericParameterCount => throw ExceptionUtilities.Unreachable; + + IUnitReference INamespaceTypeReference.GetUnit(EmitContext context) => throw ExceptionUtilities.Unreachable; + + string INamespaceTypeReference.NamespaceName => string.Empty; + + IGenericMethodParameterReference? ITypeReference.AsGenericMethodParameterReference => null; + + IGenericTypeInstanceReference? ITypeReference.AsGenericTypeInstanceReference => null; + + IGenericTypeParameterReference? ITypeReference.AsGenericTypeParameterReference => null; + + INamespaceTypeDefinition ITypeReference.AsNamespaceTypeDefinition(EmitContext context) => this; + + INamespaceTypeReference ITypeReference.AsNamespaceTypeReference => this; + + INestedTypeDefinition? ITypeReference.AsNestedTypeDefinition(EmitContext context) => null; + + INestedTypeReference? ITypeReference.AsNestedTypeReference => null; + + ISpecializedNestedTypeReference? ITypeReference.AsSpecializedNestedTypeReference => null; + + ITypeDefinition ITypeReference.AsTypeDefinition(EmitContext context) => this; + + IDefinition IReference.AsDefinition(EmitContext context) => this; } } From f5fe948da2e94b9bc7ccf37dc15e088f6c19f71b Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 10 Apr 2020 21:25:10 -0400 Subject: [PATCH 06/23] Compile synthesized methods that the root module type may have --- .../CSharp/Portable/Compiler/MethodCompiler.cs | 9 +++++++++ .../Core/Portable/Emit/CommonPEModuleBuilder.cs | 2 ++ .../Core/Portable/PEWriter/RootModuleType.cs | 16 ++++++++++++++++ .../Portable/Compilation/MethodCompiler.vb | 8 ++++++++ 4 files changed, 35 insertions(+) diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index d2d780bd205e5..fdf830a62151e 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -175,6 +175,15 @@ public static void CompileMethodBodies( methodCompiler.CompileSynthesizedMethods(privateImplClass, diagnostics); } + + var rootModuleType = moduleBeingBuiltOpt.RootModuleType; + if (rootModuleType != null) + { + // all threads that were adding methods must be finished now, we can freeze the class: + rootModuleType.Freeze(); + + methodCompiler.CompileSynthesizedMethods(rootModuleType, diagnostics); + } } // If we are trying to emit and there's an error without a corresponding diagnostic (e.g. because diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index b21826e1bb012..481258173a10f 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -946,6 +946,8 @@ internal override bool SupportsPrivateImplClass get { return true; } } + internal Cci.RootModuleType RootModuleType => _rootModuleType; + #endregion public sealed override Cci.ITypeReference GetPlatformType(Cci.PlatformType platformType, EmitContext context) diff --git a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs index 18af5ac31ef6c..ae4fc252b8e6a 100644 --- a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs @@ -4,9 +4,11 @@ #nullable enable +using System; using System.Collections.Generic; using System.Reflection.Metadata; using System.Runtime.InteropServices; +using System.Threading; using Microsoft.CodeAnalysis.Emit; using Roslyn.Utilities; @@ -17,6 +19,20 @@ namespace Microsoft.Cci /// internal class RootModuleType : INamespaceTypeDefinition { + // Once frozen, the collections of fields, methods and types are immutable. + private int _frozen; + + private bool IsFrozen => _frozen != 0; + + internal void Freeze() + { + var wasFrozen = Interlocked.Exchange(ref _frozen, 1); + if (wasFrozen != 0) + { + throw new InvalidOperationException(); + } + } + public TypeDefinitionHandle TypeDef => default; public ITypeDefinition ResolvedType => this; diff --git a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb index 842215532bb30..c3ad1e4146139 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb @@ -248,6 +248,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic compiler.CompileSynthesizedMethods(privateImplClass) End If + + Dim rootModuleType = moduleBeingBuiltOpt.RootModuleType + If rootModuleType IsNot Nothing Then + ' all threads that were adding methods must be finished now, we can freeze the class: + rootModuleType.Freeze() + + compiler.CompileSynthesizedMethods(rootModuleType) + End If End If Dim entryPoint = GetEntryPoint(compilation, moduleBeingBuiltOpt, diagnostics, cancellationToken) From 4e4889adef072f44f0ed97ce096ddc55a629f931 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 10 Apr 2020 22:42:57 -0400 Subject: [PATCH 07/23] Emit root module type constructor calling the module initializer methods --- .../Portable/Compiler/MethodCompiler.cs | 12 ++ ...thesizedRootModuleTypeStaticConstructor.cs | 144 ++++++++++++++++++ .../Core/Portable/PEWriter/RootModuleType.cs | 49 +++++- 3 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleTypeStaticConstructor.cs diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index fdf830a62151e..c3bfd475d554c 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -524,6 +524,18 @@ private void CompileNamedType(NamedTypeSymbol containingType) { hasStaticConstructor = true; } + + if (_moduleBeingBuiltOpt is object && method is SourceMethodSymbolWithAttributes { MethodKind: MethodKind.Ordinary, IsModuleInitializer: true }) + { + var rootModuleType = _moduleBeingBuiltOpt.RootModuleType; + rootModuleType.AddModuleInitializerMethod(method); + + if (rootModuleType.GetSynthesizedMethod(WellKnownMemberNames.StaticConstructorName) is null) + { + rootModuleType.TryAddSynthesizedMethod( + new SynthesizedRootModuleTypeStaticConstructor(rootModuleType, _moduleBeingBuiltOpt.SourceModule)); + } + } break; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleTypeStaticConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleTypeStaticConstructor.cs new file mode 100644 index 0000000000000..125440e8de2d0 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleTypeStaticConstructor.cs @@ -0,0 +1,144 @@ +// 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. + +#nullable enable + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Reflection; +using Microsoft.Cci; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + internal sealed class SynthesizedRootModuleTypeStaticConstructor : MethodSymbol + { + private readonly RootModuleType _rootModuleType; + + internal SynthesizedRootModuleTypeStaticConstructor(RootModuleType rootModuleType, SourceModuleSymbol containingModule) + { + _rootModuleType = rootModuleType; + ContainingModule = containingModule; + } + + public override AssemblySymbol ContainingAssembly => ContainingModule.ContainingAssembly; + + internal override ModuleSymbol ContainingModule { get; } + + public override NamedTypeSymbol? ContainingType => null; + + public override Symbol? ContainingSymbol => null; + + public override string Name => WellKnownMemberNames.StaticConstructorName; + + internal override bool HasSpecialName => true; + + public override bool HidesBaseMethodsByName => true; + + internal override bool SynthesizesLoweredBoundBody => true; + + internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) + { + var F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); + F.CurrentFunction = this; + + var body = ArrayBuilder.GetInstance(); + + foreach (var moduleInitializerMethod in _rootModuleType.GetModuleInitializerMethods()) + { + body.Add(F.ExpressionStatement( + F.StaticCall((MethodSymbol)moduleInitializerMethod, ImmutableArray.Empty))); + } + + body.Add(F.Return()); + + F.CloseMethod(F.Block(body.ToImmutableAndFree())); + } + + internal override bool GenerateDebugInfo => false; + + public override bool IsImplicitlyDeclared => true; + + public override TypeWithAnnotations ReturnTypeWithAnnotations => TypeWithAnnotations.Create(ContainingAssembly.GetSpecialType(SpecialType.System_Void)); + + public override bool AreLocalsZeroed => ContainingModule.AreLocalsZeroed; + + public override MethodKind MethodKind => MethodKind.StaticConstructor; + + public override int Arity => 0; + + public override bool IsExtensionMethod => false; + + public override bool IsVararg => false; + + public override bool ReturnsVoid => true; + + public override bool IsAsync => false; + + public override RefKind RefKind => RefKind.None; + + public override FlowAnalysisAnnotations ReturnTypeFlowAnalysisAnnotations => FlowAnalysisAnnotations.None; + + public override ImmutableHashSet ReturnNotNullIfParameterNotNull => ImmutableHashSet.Empty; + + public override FlowAnalysisAnnotations FlowAnalysisAnnotations => FlowAnalysisAnnotations.None; + + public override ImmutableArray TypeArgumentsWithAnnotations => ImmutableArray.Empty; + + public override ImmutableArray TypeParameters => ImmutableArray.Empty; + + public override ImmutableArray Parameters => ImmutableArray.Empty; + + public override ImmutableArray ExplicitInterfaceImplementations => ImmutableArray.Empty; + + public override ImmutableArray RefCustomModifiers => ImmutableArray.Empty; + + public override Symbol? AssociatedSymbol => null; + + public override ImmutableArray Locations => ImmutableArray.Empty; + + public override ImmutableArray DeclaringSyntaxReferences => ImmutableArray.Empty; + + public override Accessibility DeclaredAccessibility => Accessibility.Private; + + public override bool IsStatic => true; + + public override bool IsVirtual => false; + + public override bool IsOverride => false; + + public override bool IsAbstract => false; + + public override bool IsSealed => false; + + public override bool IsExtern => false; + + internal override MethodImplAttributes ImplementationAttributes => default; + + internal override bool HasDeclarativeSecurity => false; + + internal override MarshalPseudoCustomAttributeData? ReturnValueMarshallingInformation => null; + + internal override bool RequiresSecurityObject => false; + + internal override bool IsDeclaredReadOnly => false; + + internal override CallingConvention CallingConvention => CallingConvention.Default; + + internal override ObsoleteAttributeData? ObsoleteAttributeData => null; + + public override DllImportData? GetDllImportData() => null; + + internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) => throw ExceptionUtilities.Unreachable; + + internal override ImmutableArray GetAppliedConditionalSymbols() => ImmutableArray.Empty; + + internal override IEnumerable GetSecurityInformation() => throw ExceptionUtilities.Unreachable; + + internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) => false; + + internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) => false; + } +} diff --git a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs index ae4fc252b8e6a..bb5a94337c234 100644 --- a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs @@ -5,7 +5,11 @@ #nullable enable using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; using System.Reflection.Metadata; using System.Runtime.InteropServices; using System.Threading; @@ -31,6 +35,49 @@ internal void Freeze() { throw new InvalidOperationException(); } + + _orderedSynthesizedMethods = _synthesizedMethods.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).ToImmutableArray(); + + // TODO: require deterministic order + _orderedModuleInitializerMethods = _moduleInitializerMethods.ToImmutableArray(); + } + + private ImmutableArray _orderedSynthesizedMethods; + private readonly ConcurrentDictionary _synthesizedMethods = new ConcurrentDictionary(); + + // Add a new synthesized method indexed by its name if the method isn't already present. + internal bool TryAddSynthesizedMethod(IMethodDefinition method) + { + Debug.Assert(!IsFrozen); +#nullable disable // Can 'method.Name' be null? https://github.com/dotnet/roslyn/issues/39166 + return _synthesizedMethods.TryAdd(method.Name, method); +#nullable enable + } + + internal IMethodDefinition? GetSynthesizedMethod(string name) + { + return _synthesizedMethods.TryGetValue(name, out var method) ? method : null; + } + + public IEnumerable GetMethods(EmitContext context) + { + Debug.Assert(IsFrozen); + return _orderedSynthesizedMethods; + } + + private ImmutableArray _orderedModuleInitializerMethods; + private readonly ConcurrentBag _moduleInitializerMethods = new ConcurrentBag(); + + internal void AddModuleInitializerMethod(IMethodDefinition method) + { + Debug.Assert(!IsFrozen); + _moduleInitializerMethods.Add(method); + } + + internal ImmutableArray GetModuleInitializerMethods() + { + Debug.Assert(IsFrozen); + return _orderedModuleInitializerMethods; } public TypeDefinitionHandle TypeDef => default; @@ -81,8 +128,6 @@ internal void Freeze() public LayoutKind Layout => LayoutKind.Auto; - public IEnumerable GetMethods(EmitContext context) => SpecializedCollections.EmptyEnumerable(); - public IEnumerable GetNestedTypes(EmitContext context) => SpecializedCollections.EmptyEnumerable(); public IEnumerable GetProperties(EmitContext context) => SpecializedCollections.EmptyEnumerable(); From 46e61efdcf161157493fdbfd1dacbae0dcef9046 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 10 Apr 2020 23:11:14 -0400 Subject: [PATCH 08/23] Fix the method full names in the CompilationTestData that the compiler produces --- .../Portable/Compiler/MethodCompiler.cs | 4 +- .../Synthesized/SynthesizedRootModuleType.cs | 128 ++++++++++++++++++ ...thesizedRootModuleTypeStaticConstructor.cs | 12 +- 3 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleType.cs diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index c3bfd475d554c..72f8b7aaff72c 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -533,7 +533,9 @@ private void CompileNamedType(NamedTypeSymbol containingType) if (rootModuleType.GetSynthesizedMethod(WellKnownMemberNames.StaticConstructorName) is null) { rootModuleType.TryAddSynthesizedMethod( - new SynthesizedRootModuleTypeStaticConstructor(rootModuleType, _moduleBeingBuiltOpt.SourceModule)); + new SynthesizedRootModuleTypeStaticConstructor( + rootModuleType, + new SynthesizedRootModuleType(_moduleBeingBuiltOpt.SourceModule.GlobalNamespace, rootModuleType))); } } break; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleType.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleType.cs new file mode 100644 index 0000000000000..f78f5f684f145 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleType.cs @@ -0,0 +1,128 @@ +// 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. + +#nullable enable + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Runtime.InteropServices; +using Microsoft.CodeAnalysis.CodeGen; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols +{ + /// + /// Represents the that will be emitted. Used for so that tests can use proper metadata names. + /// See . + /// + internal sealed class SynthesizedRootModuleType : NamedTypeSymbol + { + private readonly Cci.RootModuleType _rootModuleType; + + public SynthesizedRootModuleType(NamespaceSymbol globalNamespace, Cci.RootModuleType rootModuleType) + { + ContainingSymbol = globalNamespace; + _rootModuleType = rootModuleType; + } + + public override Symbol ContainingSymbol { get; } + + public override string Name => _rootModuleType.Name; + + internal override bool MangleName => _rootModuleType.MangleName; + + internal override bool HasSpecialName => _rootModuleType.IsSpecialName; + + public override int Arity => 0; + + public override ImmutableArray TypeParameters => ImmutableArray.Empty; + + public override NamedTypeSymbol ConstructedFrom => this; + + public override bool MightContainExtensionMethods => throw ExceptionUtilities.Unreachable; + + public override IEnumerable MemberNames => throw ExceptionUtilities.Unreachable; + + public override Accessibility DeclaredAccessibility => throw ExceptionUtilities.Unreachable; + + public override bool IsSerializable => false; + + public override bool AreLocalsZeroed => ContainingModule.AreLocalsZeroed; + + public override TypeKind TypeKind => TypeKind.Module; + + public override bool IsRefLikeType => false; + + public override bool IsReadOnly => false; + + public override ImmutableArray Locations => ImmutableArray.Empty; + + public override ImmutableArray DeclaringSyntaxReferences => ImmutableArray.Empty; + + public override bool IsStatic => throw ExceptionUtilities.Unreachable; + + public override bool IsAbstract => throw ExceptionUtilities.Unreachable; + + public override bool IsSealed => throw ExceptionUtilities.Unreachable; + + internal override ImmutableArray TypeArgumentsWithAnnotationsNoUseSiteDiagnostics => throw ExceptionUtilities.Unreachable; + + internal override bool HasCodeAnalysisEmbeddedAttribute => throw ExceptionUtilities.Unreachable; + + internal override bool IsComImport => false; + + internal override bool IsWindowsRuntimeImport => throw ExceptionUtilities.Unreachable; + + internal override bool ShouldAddWinRTMembers => throw ExceptionUtilities.Unreachable; + + internal override TypeLayout Layout => throw ExceptionUtilities.Unreachable; + + internal override CharSet MarshallingCharSet => throw ExceptionUtilities.Unreachable; + + internal override bool HasDeclarativeSecurity => throw ExceptionUtilities.Unreachable; + + internal override bool IsInterface => throw ExceptionUtilities.Unreachable; + + internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics => throw ExceptionUtilities.Unreachable; + + internal override ObsoleteAttributeData ObsoleteAttributeData => throw ExceptionUtilities.Unreachable; + + internal override NamedTypeSymbol NativeIntegerUnderlyingType => throw ExceptionUtilities.Unreachable; + + public override ImmutableArray GetMembers() => throw ExceptionUtilities.Unreachable; + + public override ImmutableArray GetMembers(string name) => throw ExceptionUtilities.Unreachable; + + public override ImmutableArray GetTypeMembers() => throw ExceptionUtilities.Unreachable; + + public override ImmutableArray GetTypeMembers(string name) => throw ExceptionUtilities.Unreachable; + + public override ImmutableArray GetTypeMembers(string name, int arity) => throw ExceptionUtilities.Unreachable; + + protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) => throw ExceptionUtilities.Unreachable; + + internal override ImmutableArray GetAppliedConditionalSymbols() => throw ExceptionUtilities.Unreachable; + + internal override AttributeUsageInfo GetAttributeUsageInfo() => throw ExceptionUtilities.Unreachable; + + internal override NamedTypeSymbol GetDeclaredBaseType(ConsList basesBeingResolved) => throw ExceptionUtilities.Unreachable; + + internal override ImmutableArray GetDeclaredInterfaces(ConsList basesBeingResolved) => throw ExceptionUtilities.Unreachable; + + internal override ImmutableArray GetEarlyAttributeDecodingMembers() => throw ExceptionUtilities.Unreachable; + + internal override ImmutableArray GetEarlyAttributeDecodingMembers(string name) => throw ExceptionUtilities.Unreachable; + + internal override IEnumerable GetFieldsToEmit() => throw ExceptionUtilities.Unreachable; + + internal override ImmutableArray GetInterfacesToEmit() => throw ExceptionUtilities.Unreachable; + + internal override IEnumerable GetSecurityInformation() => throw ExceptionUtilities.Unreachable; + + internal override ImmutableArray InterfacesNoUseSiteDiagnostics(ConsList? basesBeingResolved = null) => throw ExceptionUtilities.Unreachable; + + internal override NamedTypeSymbol AsNativeInteger() => throw ExceptionUtilities.Unreachable; + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleTypeStaticConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleTypeStaticConstructor.cs index 125440e8de2d0..3d2e8c3930858 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleTypeStaticConstructor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleTypeStaticConstructor.cs @@ -17,19 +17,15 @@ internal sealed class SynthesizedRootModuleTypeStaticConstructor : MethodSymbol { private readonly RootModuleType _rootModuleType; - internal SynthesizedRootModuleTypeStaticConstructor(RootModuleType rootModuleType, SourceModuleSymbol containingModule) + internal SynthesizedRootModuleTypeStaticConstructor(RootModuleType rootModuleType, NamedTypeSymbol containingType) { _rootModuleType = rootModuleType; - ContainingModule = containingModule; + ContainingType = containingType; } - public override AssemblySymbol ContainingAssembly => ContainingModule.ContainingAssembly; + public override NamedTypeSymbol ContainingType { get; } - internal override ModuleSymbol ContainingModule { get; } - - public override NamedTypeSymbol? ContainingType => null; - - public override Symbol? ContainingSymbol => null; + public override Symbol ContainingSymbol => ContainingType; public override string Name => WellKnownMemberNames.StaticConstructorName; From e509e89a949de99a53f60e8624063270da675d6d Mon Sep 17 00:00:00 2001 From: jnm2 Date: Sun, 12 Apr 2020 12:48:42 -0400 Subject: [PATCH 09/23] Freeze the root module type since it is processed when emitting metadata only --- .../CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs | 2 ++ .../Portable/Compilation/SynthesizedMetadataCompiler.vb | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/Compilers/CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs index bdbb19e68ee1f..533a683d93cf6 100644 --- a/src/Compilers/CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs @@ -43,6 +43,8 @@ public static void ProcessSynthesizedMembers( { Debug.Assert(moduleBeingBuilt != null); + moduleBeingBuilt.RootModuleType.Freeze(); + var compiler = new SynthesizedMetadataCompiler(moduleBeingBuilt, cancellationToken); compiler.Visit(compilation.SourceModule.GlobalNamespace); } diff --git a/src/Compilers/VisualBasic/Portable/Compilation/SynthesizedMetadataCompiler.vb b/src/Compilers/VisualBasic/Portable/Compilation/SynthesizedMetadataCompiler.vb index f1f3f4459baac..27974924870c0 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/SynthesizedMetadataCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/SynthesizedMetadataCompiler.vb @@ -33,6 +33,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Optional cancellationToken As CancellationToken = Nothing) Debug.Assert(moduleBeingBuilt IsNot Nothing) + + moduleBeingBuilt.RootModuleType.Freeze() + Dim compiler = New SynthesizedMetadataCompiler(moduleBeingBuilt:=moduleBeingBuilt, cancellationToken:=cancellationToken) compilation.SourceModule.GlobalNamespace.Accept(compiler) End Sub From b4d607b92ce4464496c1b9a90543130fd8928ca8 Mon Sep 17 00:00:00 2001 From: Joseph Musser Date: Mon, 13 Apr 2020 15:59:22 -0400 Subject: [PATCH 10/23] Apply suggestions from code review Review suggestions using PROTOTYPE in comments Co-Authored-By: Rikki Gibson --- .../CSharp/Portable/Symbols/Attributes/AttributeData.cs | 2 +- src/Compilers/Core/Portable/PEWriter/RootModuleType.cs | 2 +- .../VisualBasic/Portable/Compilation/MethodCompiler.vb | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs index 301239ce1cfdd..cb9faae38b463 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs @@ -662,7 +662,7 @@ private protected sealed override bool IsStringProperty(string memberName) internal static void DecodeModuleInitializerAttribute(ref DecodeWellKnownAttributeArguments arguments) { - // TODO: diagnostics + // PROTOTYPE(module-initializers): diagnostics arguments.GetOrCreateData().HasModuleInitializerAttribute = true; } diff --git a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs index bb5a94337c234..2f8ae2b5e2da8 100644 --- a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs @@ -38,7 +38,7 @@ internal void Freeze() _orderedSynthesizedMethods = _synthesizedMethods.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).ToImmutableArray(); - // TODO: require deterministic order + // PROTOTYPE(module-initializers): require deterministic order _orderedModuleInitializerMethods = _moduleInitializerMethods.ToImmutableArray(); } diff --git a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb index c3ad1e4146139..04b33e04e22e7 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb @@ -252,6 +252,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim rootModuleType = moduleBeingBuiltOpt.RootModuleType If rootModuleType IsNot Nothing Then ' all threads that were adding methods must be finished now, we can freeze the class: + ' PROTOTYPE(module-initializers): what should happen when a VB method is marked with ``? rootModuleType.Freeze() compiler.CompileSynthesizedMethods(rootModuleType) From 7308772c593bcaaee47ea5fb8ebef0e60cb23f74 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 17 Apr 2020 19:28:35 -0400 Subject: [PATCH 11/23] Inline now and extract as private method later --- .../CSharp/Portable/Symbols/Attributes/AttributeData.cs | 6 ------ .../Symbols/Source/SourceMethodSymbolWithAttributes.cs | 3 ++- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs index cb9faae38b463..3b7206d7ed084 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/AttributeData.cs @@ -660,12 +660,6 @@ private protected sealed override bool IsStringProperty(string memberName) return false; } - internal static void DecodeModuleInitializerAttribute(ref DecodeWellKnownAttributeArguments arguments) - { - // PROTOTYPE(module-initializers): diagnostics - arguments.GetOrCreateData().HasModuleInitializerAttribute = true; - } - #endregion /// diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 064088f223c28..7f103093e65c5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -485,7 +485,8 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut else if (attribute.IsTargetAttribute(this, AttributeDescription.ModuleInitializerAttribute)) { MessageID.IDS_FeatureModuleInitializers.CheckFeatureAvailability(arguments.Diagnostics, arguments.AttributeSyntaxOpt); - CSharpAttributeData.DecodeModuleInitializerAttribute(ref arguments); + // PROTOTYPE(module-initializers): diagnostics + arguments.GetOrCreateData().HasModuleInitializerAttribute = true; } else { From f50aa4c7ed3e804c55a77f9c18cbde5cbf464786 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 17 Apr 2020 19:32:11 -0400 Subject: [PATCH 12/23] Add suggested comment where features are mapped to versions --- src/Compilers/CSharp/Portable/Errors/MessageID.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index d2329b8d3dcc6..825184ddf6673 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -306,7 +306,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureTargetTypedObjectCreation: // syntax check case MessageID.IDS_FeatureMemberNotNull: case MessageID.IDS_FeatureNativeInt: - case MessageID.IDS_FeatureModuleInitializers: + case MessageID.IDS_FeatureModuleInitializers: // semantic check on method attribute return LanguageVersion.Preview; // C# 8.0 features. From 5908d80b7ec6d100b7b269d80bfb683a0f86efd3 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 17 Apr 2020 19:44:26 -0400 Subject: [PATCH 13/23] Revert in preparation for taking an approach that is not based on synthesized symbols --- .../Portable/Compiler/MethodCompiler.cs | 27 +- .../Compiler/SynthesizedMetadataCompiler.cs | 2 - .../MethodWellKnownAttributeData.cs | 16 - .../SourceMethodSymbolWithAttributes.cs | 1 - .../Synthesized/SynthesizedRootModuleType.cs | 128 ------- ...thesizedRootModuleTypeStaticConstructor.cs | 140 -------- .../Portable/Emit/CommonPEModuleBuilder.cs | 2 - .../Core/Portable/PEWriter/RootModuleType.cs | 324 ++++++++++++------ .../Portable/Compilation/MethodCompiler.vb | 11 +- .../SynthesizedMetadataCompiler.vb | 3 - 10 files changed, 225 insertions(+), 429 deletions(-) delete mode 100644 src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleType.cs delete mode 100644 src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleTypeStaticConstructor.cs diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 72f8b7aaff72c..d52e5c874da8e 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -175,15 +175,6 @@ public static void CompileMethodBodies( methodCompiler.CompileSynthesizedMethods(privateImplClass, diagnostics); } - - var rootModuleType = moduleBeingBuiltOpt.RootModuleType; - if (rootModuleType != null) - { - // all threads that were adding methods must be finished now, we can freeze the class: - rootModuleType.Freeze(); - - methodCompiler.CompileSynthesizedMethods(rootModuleType, diagnostics); - } } // If we are trying to emit and there's an error without a corresponding diagnostic (e.g. because @@ -524,20 +515,6 @@ private void CompileNamedType(NamedTypeSymbol containingType) { hasStaticConstructor = true; } - - if (_moduleBeingBuiltOpt is object && method is SourceMethodSymbolWithAttributes { MethodKind: MethodKind.Ordinary, IsModuleInitializer: true }) - { - var rootModuleType = _moduleBeingBuiltOpt.RootModuleType; - rootModuleType.AddModuleInitializerMethod(method); - - if (rootModuleType.GetSynthesizedMethod(WellKnownMemberNames.StaticConstructorName) is null) - { - rootModuleType.TryAddSynthesizedMethod( - new SynthesizedRootModuleTypeStaticConstructor( - rootModuleType, - new SynthesizedRootModuleType(_moduleBeingBuiltOpt.SourceModule.GlobalNamespace, rootModuleType))); - } - } break; } @@ -664,12 +641,12 @@ private void CompileNamedType(NamedTypeSymbol containingType) compilationState.Free(); } - private void CompileSynthesizedMethods(Cci.INamespaceTypeDefinition synthesizedTopLevelType, DiagnosticBag diagnostics) + private void CompileSynthesizedMethods(PrivateImplementationDetails privateImplClass, DiagnosticBag diagnostics) { Debug.Assert(_moduleBeingBuiltOpt != null); var compilationState = new TypeCompilationState(null, _compilation, _moduleBeingBuiltOpt); - foreach (MethodSymbol method in synthesizedTopLevelType.GetMethods(new EmitContext(_moduleBeingBuiltOpt, null, diagnostics, metadataOnly: false, includePrivateMembers: true))) + foreach (MethodSymbol method in privateImplClass.GetMethods(new EmitContext(_moduleBeingBuiltOpt, null, diagnostics, metadataOnly: false, includePrivateMembers: true))) { Debug.Assert(method.SynthesizesLoweredBoundBody); method.GenerateMethodBody(compilationState, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs index 533a683d93cf6..bdbb19e68ee1f 100644 --- a/src/Compilers/CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/SynthesizedMetadataCompiler.cs @@ -43,8 +43,6 @@ public static void ProcessSynthesizedMembers( { Debug.Assert(moduleBeingBuilt != null); - moduleBeingBuilt.RootModuleType.Freeze(); - var compiler = new SynthesizedMetadataCompiler(moduleBeingBuilt, cancellationToken); compiler.Visit(compilation.SourceModule.GlobalNamespace); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/MethodWellKnownAttributeData.cs b/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/MethodWellKnownAttributeData.cs index 4d174fe04a842..386d004801376 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/MethodWellKnownAttributeData.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Attributes/WellKnownAttributeData/MethodWellKnownAttributeData.cs @@ -44,22 +44,6 @@ public bool HasSkipLocalsInitAttribute } } - private bool _hasModuleInitializerAttribute; - public bool HasModuleInitializerAttribute - { - get - { - VerifySealed(expected: true); - return _hasModuleInitializerAttribute; - } - set - { - VerifySealed(expected: false); - _hasModuleInitializerAttribute = value; - SetDataStored(); - } - } - private ImmutableArray _memberNotNullAttributeData = ImmutableArray.Empty; public void AddNotNullMember(string memberName) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 7f103093e65c5..551464e7dc927 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -486,7 +486,6 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut { MessageID.IDS_FeatureModuleInitializers.CheckFeatureAvailability(arguments.Diagnostics, arguments.AttributeSyntaxOpt); // PROTOTYPE(module-initializers): diagnostics - arguments.GetOrCreateData().HasModuleInitializerAttribute = true; } else { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleType.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleType.cs deleted file mode 100644 index f78f5f684f145..0000000000000 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleType.cs +++ /dev/null @@ -1,128 +0,0 @@ -// 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. - -#nullable enable - -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Runtime.InteropServices; -using Microsoft.CodeAnalysis.CodeGen; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.CSharp.Symbols -{ - /// - /// Represents the that will be emitted. Used for so that tests can use proper metadata names. - /// See . - /// - internal sealed class SynthesizedRootModuleType : NamedTypeSymbol - { - private readonly Cci.RootModuleType _rootModuleType; - - public SynthesizedRootModuleType(NamespaceSymbol globalNamespace, Cci.RootModuleType rootModuleType) - { - ContainingSymbol = globalNamespace; - _rootModuleType = rootModuleType; - } - - public override Symbol ContainingSymbol { get; } - - public override string Name => _rootModuleType.Name; - - internal override bool MangleName => _rootModuleType.MangleName; - - internal override bool HasSpecialName => _rootModuleType.IsSpecialName; - - public override int Arity => 0; - - public override ImmutableArray TypeParameters => ImmutableArray.Empty; - - public override NamedTypeSymbol ConstructedFrom => this; - - public override bool MightContainExtensionMethods => throw ExceptionUtilities.Unreachable; - - public override IEnumerable MemberNames => throw ExceptionUtilities.Unreachable; - - public override Accessibility DeclaredAccessibility => throw ExceptionUtilities.Unreachable; - - public override bool IsSerializable => false; - - public override bool AreLocalsZeroed => ContainingModule.AreLocalsZeroed; - - public override TypeKind TypeKind => TypeKind.Module; - - public override bool IsRefLikeType => false; - - public override bool IsReadOnly => false; - - public override ImmutableArray Locations => ImmutableArray.Empty; - - public override ImmutableArray DeclaringSyntaxReferences => ImmutableArray.Empty; - - public override bool IsStatic => throw ExceptionUtilities.Unreachable; - - public override bool IsAbstract => throw ExceptionUtilities.Unreachable; - - public override bool IsSealed => throw ExceptionUtilities.Unreachable; - - internal override ImmutableArray TypeArgumentsWithAnnotationsNoUseSiteDiagnostics => throw ExceptionUtilities.Unreachable; - - internal override bool HasCodeAnalysisEmbeddedAttribute => throw ExceptionUtilities.Unreachable; - - internal override bool IsComImport => false; - - internal override bool IsWindowsRuntimeImport => throw ExceptionUtilities.Unreachable; - - internal override bool ShouldAddWinRTMembers => throw ExceptionUtilities.Unreachable; - - internal override TypeLayout Layout => throw ExceptionUtilities.Unreachable; - - internal override CharSet MarshallingCharSet => throw ExceptionUtilities.Unreachable; - - internal override bool HasDeclarativeSecurity => throw ExceptionUtilities.Unreachable; - - internal override bool IsInterface => throw ExceptionUtilities.Unreachable; - - internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics => throw ExceptionUtilities.Unreachable; - - internal override ObsoleteAttributeData ObsoleteAttributeData => throw ExceptionUtilities.Unreachable; - - internal override NamedTypeSymbol NativeIntegerUnderlyingType => throw ExceptionUtilities.Unreachable; - - public override ImmutableArray GetMembers() => throw ExceptionUtilities.Unreachable; - - public override ImmutableArray GetMembers(string name) => throw ExceptionUtilities.Unreachable; - - public override ImmutableArray GetTypeMembers() => throw ExceptionUtilities.Unreachable; - - public override ImmutableArray GetTypeMembers(string name) => throw ExceptionUtilities.Unreachable; - - public override ImmutableArray GetTypeMembers(string name, int arity) => throw ExceptionUtilities.Unreachable; - - protected override NamedTypeSymbol WithTupleDataCore(TupleExtraData newData) => throw ExceptionUtilities.Unreachable; - - internal override ImmutableArray GetAppliedConditionalSymbols() => throw ExceptionUtilities.Unreachable; - - internal override AttributeUsageInfo GetAttributeUsageInfo() => throw ExceptionUtilities.Unreachable; - - internal override NamedTypeSymbol GetDeclaredBaseType(ConsList basesBeingResolved) => throw ExceptionUtilities.Unreachable; - - internal override ImmutableArray GetDeclaredInterfaces(ConsList basesBeingResolved) => throw ExceptionUtilities.Unreachable; - - internal override ImmutableArray GetEarlyAttributeDecodingMembers() => throw ExceptionUtilities.Unreachable; - - internal override ImmutableArray GetEarlyAttributeDecodingMembers(string name) => throw ExceptionUtilities.Unreachable; - - internal override IEnumerable GetFieldsToEmit() => throw ExceptionUtilities.Unreachable; - - internal override ImmutableArray GetInterfacesToEmit() => throw ExceptionUtilities.Unreachable; - - internal override IEnumerable GetSecurityInformation() => throw ExceptionUtilities.Unreachable; - - internal override ImmutableArray InterfacesNoUseSiteDiagnostics(ConsList? basesBeingResolved = null) => throw ExceptionUtilities.Unreachable; - - internal override NamedTypeSymbol AsNativeInteger() => throw ExceptionUtilities.Unreachable; - } -} diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleTypeStaticConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleTypeStaticConstructor.cs deleted file mode 100644 index 3d2e8c3930858..0000000000000 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedRootModuleTypeStaticConstructor.cs +++ /dev/null @@ -1,140 +0,0 @@ -// 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. - -#nullable enable - -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Reflection; -using Microsoft.Cci; -using Microsoft.CodeAnalysis.PooledObjects; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.CSharp.Symbols -{ - internal sealed class SynthesizedRootModuleTypeStaticConstructor : MethodSymbol - { - private readonly RootModuleType _rootModuleType; - - internal SynthesizedRootModuleTypeStaticConstructor(RootModuleType rootModuleType, NamedTypeSymbol containingType) - { - _rootModuleType = rootModuleType; - ContainingType = containingType; - } - - public override NamedTypeSymbol ContainingType { get; } - - public override Symbol ContainingSymbol => ContainingType; - - public override string Name => WellKnownMemberNames.StaticConstructorName; - - internal override bool HasSpecialName => true; - - public override bool HidesBaseMethodsByName => true; - - internal override bool SynthesizesLoweredBoundBody => true; - - internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics) - { - var F = new SyntheticBoundNodeFactory(this, this.GetNonNullSyntaxNode(), compilationState, diagnostics); - F.CurrentFunction = this; - - var body = ArrayBuilder.GetInstance(); - - foreach (var moduleInitializerMethod in _rootModuleType.GetModuleInitializerMethods()) - { - body.Add(F.ExpressionStatement( - F.StaticCall((MethodSymbol)moduleInitializerMethod, ImmutableArray.Empty))); - } - - body.Add(F.Return()); - - F.CloseMethod(F.Block(body.ToImmutableAndFree())); - } - - internal override bool GenerateDebugInfo => false; - - public override bool IsImplicitlyDeclared => true; - - public override TypeWithAnnotations ReturnTypeWithAnnotations => TypeWithAnnotations.Create(ContainingAssembly.GetSpecialType(SpecialType.System_Void)); - - public override bool AreLocalsZeroed => ContainingModule.AreLocalsZeroed; - - public override MethodKind MethodKind => MethodKind.StaticConstructor; - - public override int Arity => 0; - - public override bool IsExtensionMethod => false; - - public override bool IsVararg => false; - - public override bool ReturnsVoid => true; - - public override bool IsAsync => false; - - public override RefKind RefKind => RefKind.None; - - public override FlowAnalysisAnnotations ReturnTypeFlowAnalysisAnnotations => FlowAnalysisAnnotations.None; - - public override ImmutableHashSet ReturnNotNullIfParameterNotNull => ImmutableHashSet.Empty; - - public override FlowAnalysisAnnotations FlowAnalysisAnnotations => FlowAnalysisAnnotations.None; - - public override ImmutableArray TypeArgumentsWithAnnotations => ImmutableArray.Empty; - - public override ImmutableArray TypeParameters => ImmutableArray.Empty; - - public override ImmutableArray Parameters => ImmutableArray.Empty; - - public override ImmutableArray ExplicitInterfaceImplementations => ImmutableArray.Empty; - - public override ImmutableArray RefCustomModifiers => ImmutableArray.Empty; - - public override Symbol? AssociatedSymbol => null; - - public override ImmutableArray Locations => ImmutableArray.Empty; - - public override ImmutableArray DeclaringSyntaxReferences => ImmutableArray.Empty; - - public override Accessibility DeclaredAccessibility => Accessibility.Private; - - public override bool IsStatic => true; - - public override bool IsVirtual => false; - - public override bool IsOverride => false; - - public override bool IsAbstract => false; - - public override bool IsSealed => false; - - public override bool IsExtern => false; - - internal override MethodImplAttributes ImplementationAttributes => default; - - internal override bool HasDeclarativeSecurity => false; - - internal override MarshalPseudoCustomAttributeData? ReturnValueMarshallingInformation => null; - - internal override bool RequiresSecurityObject => false; - - internal override bool IsDeclaredReadOnly => false; - - internal override CallingConvention CallingConvention => CallingConvention.Default; - - internal override ObsoleteAttributeData? ObsoleteAttributeData => null; - - public override DllImportData? GetDllImportData() => null; - - internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) => throw ExceptionUtilities.Unreachable; - - internal override ImmutableArray GetAppliedConditionalSymbols() => ImmutableArray.Empty; - - internal override IEnumerable GetSecurityInformation() => throw ExceptionUtilities.Unreachable; - - internal override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) => false; - - internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChanges = false) => false; - } -} diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index 481258173a10f..b21826e1bb012 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -946,8 +946,6 @@ internal override bool SupportsPrivateImplClass get { return true; } } - internal Cci.RootModuleType RootModuleType => _rootModuleType; - #endregion public sealed override Cci.ITypeReference GetPlatformType(Cci.PlatformType platformType, EmitContext context) diff --git a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs index 2f8ae2b5e2da8..64ce7bc27441f 100644 --- a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs @@ -5,16 +5,11 @@ #nullable enable using System; -using System.Collections.Concurrent; using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics; -using System.Linq; -using System.Reflection.Metadata; using System.Runtime.InteropServices; -using System.Threading; -using Microsoft.CodeAnalysis.Emit; +using System.Reflection.Metadata; using Roslyn.Utilities; +using EmitContext = Microsoft.CodeAnalysis.Emit.EmitContext; namespace Microsoft.Cci { @@ -23,163 +18,288 @@ namespace Microsoft.Cci /// internal class RootModuleType : INamespaceTypeDefinition { - // Once frozen, the collections of fields, methods and types are immutable. - private int _frozen; - - private bool IsFrozen => _frozen != 0; - - internal void Freeze() + public TypeDefinitionHandle TypeDef { - var wasFrozen = Interlocked.Exchange(ref _frozen, 1); - if (wasFrozen != 0) - { - throw new InvalidOperationException(); - } - - _orderedSynthesizedMethods = _synthesizedMethods.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).ToImmutableArray(); - - // PROTOTYPE(module-initializers): require deterministic order - _orderedModuleInitializerMethods = _moduleInitializerMethods.ToImmutableArray(); + get { return default(TypeDefinitionHandle); } } - private ImmutableArray _orderedSynthesizedMethods; - private readonly ConcurrentDictionary _synthesizedMethods = new ConcurrentDictionary(); - - // Add a new synthesized method indexed by its name if the method isn't already present. - internal bool TryAddSynthesizedMethod(IMethodDefinition method) + public ITypeDefinition ResolvedType { - Debug.Assert(!IsFrozen); -#nullable disable // Can 'method.Name' be null? https://github.com/dotnet/roslyn/issues/39166 - return _synthesizedMethods.TryAdd(method.Name, method); -#nullable enable + get { return this; } } - internal IMethodDefinition? GetSynthesizedMethod(string name) + public IEnumerable GetAttributes(EmitContext context) { - return _synthesizedMethods.TryGetValue(name, out var method) ? method : null; + return SpecializedCollections.EmptyEnumerable(); } - public IEnumerable GetMethods(EmitContext context) + public bool MangleName { - Debug.Assert(IsFrozen); - return _orderedSynthesizedMethods; + get { return false; } } - private ImmutableArray _orderedModuleInitializerMethods; - private readonly ConcurrentBag _moduleInitializerMethods = new ConcurrentBag(); - - internal void AddModuleInitializerMethod(IMethodDefinition method) + public string Name { - Debug.Assert(!IsFrozen); - _moduleInitializerMethods.Add(method); + get { return ""; } } - internal ImmutableArray GetModuleInitializerMethods() + public ushort Alignment { - Debug.Assert(IsFrozen); - return _orderedModuleInitializerMethods; + get { return 0; } } - public TypeDefinitionHandle TypeDef => default; - - public ITypeDefinition ResolvedType => this; - - public IEnumerable GetAttributes(EmitContext context) => SpecializedCollections.EmptyEnumerable(); - - public bool MangleName => false; - - public string Name => ""; - - public ushort Alignment => 0; + public ITypeReference? GetBaseClass(EmitContext context) + { + return null; + } - public ITypeReference? GetBaseClass(EmitContext context) => null; + public IEnumerable GetEvents(EmitContext context) + { + return SpecializedCollections.EmptyEnumerable(); + } - public IEnumerable GetEvents(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + public IEnumerable GetExplicitImplementationOverrides(EmitContext context) + { + return SpecializedCollections.EmptyEnumerable(); + } - public IEnumerable GetExplicitImplementationOverrides(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + public IEnumerable GetFields(EmitContext context) + { + return SpecializedCollections.EmptyEnumerable(); + } - public IEnumerable GetFields(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + public bool HasDeclarativeSecurity + { + get { return false; } + } - public bool HasDeclarativeSecurity => false; + public IEnumerable Interfaces(EmitContext context) + { + return SpecializedCollections.EmptyEnumerable(); + } - public IEnumerable Interfaces(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + public bool IsAbstract + { + get { return false; } + } - public bool IsAbstract => false; + public bool IsBeforeFieldInit + { + get { return false; } + } - public bool IsBeforeFieldInit => false; + public bool IsComObject + { + get { return false; } + } - public bool IsComObject => false; + public bool IsGeneric + { + get { return false; } + } - public bool IsGeneric => false; + public bool IsInterface + { + get { return false; } + } - public bool IsInterface => false; + public bool IsDelegate + { + get { return false; } + } - public bool IsDelegate => false; + public bool IsRuntimeSpecial + { + get { return false; } + } - public bool IsRuntimeSpecial => false; + public bool IsSerializable + { + get { return false; } + } - public bool IsSerializable => false; + public bool IsSpecialName + { + get { return false; } + } - public bool IsSpecialName => false; + public bool IsWindowsRuntimeImport + { + get { return false; } + } - public bool IsWindowsRuntimeImport => false; + public bool IsSealed + { + get { return false; } + } - public bool IsSealed => false; + public LayoutKind Layout + { + get { return LayoutKind.Auto; } + } - public LayoutKind Layout => LayoutKind.Auto; + public IEnumerable GetMethods(EmitContext context) + { + return SpecializedCollections.EmptyEnumerable(); + } - public IEnumerable GetNestedTypes(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + public IEnumerable GetNestedTypes(EmitContext context) + { + return SpecializedCollections.EmptyEnumerable(); + } - public IEnumerable GetProperties(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + public IEnumerable GetProperties(EmitContext context) + { + return SpecializedCollections.EmptyEnumerable(); + } - public uint SizeOf => 0; + public uint SizeOf + { + get { return 0; } + } - public CharSet StringFormat => CharSet.Ansi; + public CharSet StringFormat + { + get { return CharSet.Ansi; } + } - public bool IsPublic => false; + public bool IsPublic + { + get { return false; } + } - public bool IsNested => false; + public bool IsNested + { + get { return false; } + } - IEnumerable ITypeDefinition.GenericParameters => throw ExceptionUtilities.Unreachable; + IEnumerable ITypeDefinition.GenericParameters + { + get { throw ExceptionUtilities.Unreachable; } + } - ushort ITypeDefinition.GenericParameterCount => 0; + ushort ITypeDefinition.GenericParameterCount + { + get + { + return 0; + } + } - IEnumerable ITypeDefinition.SecurityAttributes => throw ExceptionUtilities.Unreachable; + IEnumerable ITypeDefinition.SecurityAttributes + { + get { throw ExceptionUtilities.Unreachable; } + } - void IReference.Dispatch(MetadataVisitor visitor) => throw ExceptionUtilities.Unreachable; + void IReference.Dispatch(MetadataVisitor visitor) + { + throw ExceptionUtilities.Unreachable; + } - bool ITypeReference.IsEnum => throw ExceptionUtilities.Unreachable; + bool ITypeReference.IsEnum + { + get { throw ExceptionUtilities.Unreachable; } + } - bool ITypeReference.IsValueType => throw ExceptionUtilities.Unreachable; + bool ITypeReference.IsValueType + { + get { throw ExceptionUtilities.Unreachable; } + } - ITypeDefinition ITypeReference.GetResolvedType(EmitContext context) => this; + ITypeDefinition ITypeReference.GetResolvedType(EmitContext context) + { + return this; + } - PrimitiveTypeCode ITypeReference.TypeCode => throw ExceptionUtilities.Unreachable; + PrimitiveTypeCode ITypeReference.TypeCode + { + get { throw ExceptionUtilities.Unreachable; } + } - ushort INamedTypeReference.GenericParameterCount => throw ExceptionUtilities.Unreachable; + ushort INamedTypeReference.GenericParameterCount + { + get { throw ExceptionUtilities.Unreachable; } + } - IUnitReference INamespaceTypeReference.GetUnit(EmitContext context) => throw ExceptionUtilities.Unreachable; + IUnitReference INamespaceTypeReference.GetUnit(EmitContext context) + { + throw ExceptionUtilities.Unreachable; + } - string INamespaceTypeReference.NamespaceName => string.Empty; + string INamespaceTypeReference.NamespaceName + { + get + { + return string.Empty; + } + } - IGenericMethodParameterReference? ITypeReference.AsGenericMethodParameterReference => null; + IGenericMethodParameterReference? ITypeReference.AsGenericMethodParameterReference + { + get + { + return null; + } + } - IGenericTypeInstanceReference? ITypeReference.AsGenericTypeInstanceReference => null; + IGenericTypeInstanceReference? ITypeReference.AsGenericTypeInstanceReference + { + get + { + return null; + } + } - IGenericTypeParameterReference? ITypeReference.AsGenericTypeParameterReference => null; + IGenericTypeParameterReference? ITypeReference.AsGenericTypeParameterReference + { + get + { + return null; + } + } - INamespaceTypeDefinition ITypeReference.AsNamespaceTypeDefinition(EmitContext context) => this; + INamespaceTypeDefinition ITypeReference.AsNamespaceTypeDefinition(EmitContext context) + { + return this; + } - INamespaceTypeReference ITypeReference.AsNamespaceTypeReference => this; + INamespaceTypeReference ITypeReference.AsNamespaceTypeReference + { + get + { + return this; + } + } - INestedTypeDefinition? ITypeReference.AsNestedTypeDefinition(EmitContext context) => null; + INestedTypeDefinition? ITypeReference.AsNestedTypeDefinition(EmitContext context) + { + return null; + } - INestedTypeReference? ITypeReference.AsNestedTypeReference => null; + INestedTypeReference? ITypeReference.AsNestedTypeReference + { + get + { + return null; + } + } - ISpecializedNestedTypeReference? ITypeReference.AsSpecializedNestedTypeReference => null; + ISpecializedNestedTypeReference? ITypeReference.AsSpecializedNestedTypeReference + { + get + { + return null; + } + } - ITypeDefinition ITypeReference.AsTypeDefinition(EmitContext context) => this; + ITypeDefinition ITypeReference.AsTypeDefinition(EmitContext context) + { + return this; + } - IDefinition IReference.AsDefinition(EmitContext context) => this; + IDefinition IReference.AsDefinition(EmitContext context) + { + return this; + } } } diff --git a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb index 04b33e04e22e7..b47b9b13a04a9 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb @@ -248,15 +248,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic compiler.CompileSynthesizedMethods(privateImplClass) End If - - Dim rootModuleType = moduleBeingBuiltOpt.RootModuleType - If rootModuleType IsNot Nothing Then - ' all threads that were adding methods must be finished now, we can freeze the class: - ' PROTOTYPE(module-initializers): what should happen when a VB method is marked with ``? - rootModuleType.Freeze() - - compiler.CompileSynthesizedMethods(rootModuleType) - End If End If Dim entryPoint = GetEntryPoint(compilation, moduleBeingBuiltOpt, diagnostics, cancellationToken) @@ -847,7 +838,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return Nothing End Function - Private Sub CompileSynthesizedMethods(privateImplClass As Cci.INamespaceTypeDefinition) + Private Sub CompileSynthesizedMethods(privateImplClass As PrivateImplementationDetails) Debug.Assert(_moduleBeingBuiltOpt IsNot Nothing) Dim compilationState As New TypeCompilationState(_compilation, _moduleBeingBuiltOpt, initializeComponentOpt:=Nothing) diff --git a/src/Compilers/VisualBasic/Portable/Compilation/SynthesizedMetadataCompiler.vb b/src/Compilers/VisualBasic/Portable/Compilation/SynthesizedMetadataCompiler.vb index 27974924870c0..f1f3f4459baac 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/SynthesizedMetadataCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/SynthesizedMetadataCompiler.vb @@ -33,9 +33,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Optional cancellationToken As CancellationToken = Nothing) Debug.Assert(moduleBeingBuilt IsNot Nothing) - - moduleBeingBuilt.RootModuleType.Freeze() - Dim compiler = New SynthesizedMetadataCompiler(moduleBeingBuilt:=moduleBeingBuilt, cancellationToken:=cancellationToken) compilation.SourceModule.GlobalNamespace.Accept(compiler) End Sub From 0290b4c4a677e539702d276e4398af1173b43d55 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 17 Apr 2020 21:39:29 -0400 Subject: [PATCH 14/23] Store decoded ModuleInitializerAttribute state directly on the compilation --- .../Portable/Compilation/CSharpCompilation.cs | 14 ++++++++++++ .../SourceMethodSymbolWithAttributes.cs | 3 +-- .../Symbol/Symbols/ModuleInitializersTests.cs | 22 ------------------- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 00e2e696737be..2f30c2cbdaecc 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -2007,6 +2007,20 @@ private protected override bool IsSymbolAccessibleWithinCore( throw new NotImplementedException(); } + private ImmutableQueue _moduleInitializerMethods = ImmutableQueue.Empty; + + internal void AddModuleInitializerMethod(SourceMethodSymbolWithAttributes method) + { + Debug.Assert(!_declarationDiagnosticsFrozen); + ImmutableInterlocked.Enqueue(ref _moduleInitializerMethods, method); + } + + internal ImmutableQueue GetModuleInitializerMethods() + { + Debug.Assert(_declarationDiagnosticsFrozen); + return _moduleInitializerMethods; + } + #endregion #region Binding diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 551464e7dc927..46e9949d69ba5 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -486,6 +486,7 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut { MessageID.IDS_FeatureModuleInitializers.CheckFeatureAvailability(arguments.Diagnostics, arguments.AttributeSyntaxOpt); // PROTOTYPE(module-initializers): diagnostics + DeclaringCompilation.AddModuleInitializerMethod(this); } else { @@ -1017,7 +1018,5 @@ internal override System.Reflection.MethodImplAttributes ImplementationAttribute return result; } } - - internal bool IsModuleInitializer => GetDecodedWellKnownAttributeData()?.HasModuleInitializerAttribute ?? false; } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs index 9f14c1424899a..7376f2da4f582 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs @@ -14,28 +14,6 @@ public sealed class ModuleInitializersTests : CSharpTestBase { private static readonly CSharpParseOptions s_parseOptions = TestOptions.RegularPreview; - [Fact] - public static void ModuleInitializerAttributeIsDecoded() - { - var source = -@"using System.Runtime.CompilerServices; - -class C -{ - [ModuleInitializer] - internal static void M1() { } - - internal static void M2() { } -} - -namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : System.Attribute { } } -"; - var compilation = CreateCompilation(source, parseOptions: s_parseOptions); - - Assert.True(compilation.GetMember("C.M1").IsModuleInitializer); - Assert.False(compilation.GetMember("C.M2").IsModuleInitializer); - } - [Fact] public static void ModuleInitializersNotUsableInCSharp8() { From a64bb21b09cd25349f44daf0d14f173c469d57b2 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Sun, 19 Apr 2020 17:27:10 -0400 Subject: [PATCH 15/23] Emit without synthesizing symbols --- .../Portable/Compilation/CSharpCompilation.cs | 26 +++ .../Symbol/Symbols/ModuleInitializersTests.cs | 49 ++++-- .../Portable/Emit/CommonPEModuleBuilder.cs | 9 +- .../PEWriter/RootModuleStaticConstructor.cs | 162 ++++++++++++++++++ .../Core/Portable/PEWriter/RootModuleType.cs | 23 ++- 5 files changed, 245 insertions(+), 24 deletions(-) create mode 100644 src/Compilers/Core/Portable/PEWriter/RootModuleStaticConstructor.cs diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 2f30c2cbdaecc..35ae42fd2b193 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -16,6 +16,7 @@ using System.Reflection.Metadata; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Symbols; @@ -2808,6 +2809,8 @@ internal override bool CompileMethods( filterOpt: filterOpt, cancellationToken: cancellationToken); + GenerateModuleInitializer(moduleBeingBuilt, methodBodyDiagnosticBag); + bool hasMethodBodyError = !FilterAndAppendAndFreeDiagnostics(diagnostics, ref methodBodyDiagnosticBag); if (hasDeclarationErrors || hasMethodBodyError) @@ -2819,6 +2822,29 @@ internal override bool CompileMethods( return true; } + private void GenerateModuleInitializer(PEModuleBuilder moduleBeingBuilt, DiagnosticBag methodBodyDiagnosticBag) + { + if (GetModuleInitializerMethods() is { IsEmpty: false } moduleInitializerMethods) + { + var ilBuilder = new ILBuilder(moduleBeingBuilt, new LocalSlotManager(slotAllocator: null), OptimizationLevel.Release, areLocalsZeroed: true); + + // PROTOTYPE(module-initializers): require deterministic order + foreach (var method in moduleInitializerMethods) + { + ilBuilder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0); + + ilBuilder.EmitToken( + moduleBeingBuilt.Translate(method, methodBodyDiagnosticBag, needDeclaration: true), + method.SyntaxNode, + methodBodyDiagnosticBag); + } + + ilBuilder.EmitRet(isVoid: true); + ilBuilder.Realize(); + moduleBeingBuilt.RootModuleType.SetStaticConstructorBody(ilBuilder.RealizedIL); + } + } + internal override bool GenerateResourcesAndDocumentationComments( CommonPEModuleBuilder moduleBuilder, Stream? xmlDocStream, diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs index 7376f2da4f582..1c4113f884769 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs @@ -41,43 +41,68 @@ namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : S public void ModuleTypeStaticConstructorIsNotEmittedWhenNoMethodIsMarkedWithModuleInitializerAttribute() { string source = @" +using System; using System.Runtime.CompilerServices; class C { - internal static void M() { } + internal static void M() => Console.WriteLine(""C.M""); +} + +class Program +{ + static void Main() => Console.WriteLine(""Program.Main""); } namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : System.Attribute { } } "; - var verifier = CompileAndVerify(source, parseOptions: s_parseOptions); - verifier.VerifyMemberInIL("..cctor", expected: false); + CompileAndVerify( + source, + parseOptions: s_parseOptions, + options: new CSharpCompilationOptions(OutputKind.ConsoleApplication, metadataImportOptions: MetadataImportOptions.All), + symbolValidator: module => + { + var rootModuleType = (TypeSymbol)module.GlobalNamespace.GetMember(""); + Assert.Null(rootModuleType.GetMember(".cctor")); + }, + expectedOutput: @" +Program.Main"); } [Fact] public void ModuleTypeStaticConstructorCallsMethodMarkedWithModuleInitializerAttribute() { string source = @" +using System; using System.Runtime.CompilerServices; class C { [ModuleInitializer] - internal static void M() { } + internal static void M() => Console.WriteLine(""C.M""); +} + +class Program +{ + static void Main() => Console.WriteLine(""Program.Main""); } namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : System.Attribute { } } "; - var verifier = CompileAndVerify(source, parseOptions: s_parseOptions); - verifier.VerifyIL("..cctor", @" -{ - // Code size 6 (0x6) - .maxstack 0 - IL_0000: call ""void C.M()"" - IL_0005: ret -}"); + var x = CompileAndVerify( + source, + parseOptions: s_parseOptions, + options: new CSharpCompilationOptions(OutputKind.ConsoleApplication, metadataImportOptions: MetadataImportOptions.All), + symbolValidator: module => + { + var rootModuleType = (TypeSymbol)module.GlobalNamespace.GetMember(""); + Assert.NotNull(rootModuleType.GetMember(".cctor")); + }, + expectedOutput: @" +C.M +Program.Main"); } } } diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index b21826e1bb012..e845b4632380d 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -459,8 +459,6 @@ internal abstract class PEModuleBuilder { - private readonly Cci.RootModuleType _rootModuleType = new Cci.RootModuleType(); - internal readonly TSourceModuleSymbol SourceModule; internal readonly TCompilation Compilation; @@ -469,6 +467,7 @@ internal abstract class PEModuleBuilder _namesOfTopLevelTypes; internal readonly TModuleCompilationState CompilationState; + public Cci.RootModuleType RootModuleType { get; } = new Cci.RootModuleType(); public abstract TEmbeddedTypesManager EmbeddedTypesManagerOpt { get; } @@ -552,9 +551,9 @@ protected bool ContainsTopLevelType(string fullEmittedName) Dispatch(typeReferenceIndexer); } - AddTopLevelType(names, _rootModuleType); - VisitTopLevelType(typeReferenceIndexer, _rootModuleType); - yield return _rootModuleType; + AddTopLevelType(names, RootModuleType); + VisitTopLevelType(typeReferenceIndexer, RootModuleType); + yield return RootModuleType; foreach (var typeDef in GetAnonymousTypeDefinitions(context)) { diff --git a/src/Compilers/Core/Portable/PEWriter/RootModuleStaticConstructor.cs b/src/Compilers/Core/Portable/PEWriter/RootModuleStaticConstructor.cs new file mode 100644 index 0000000000000..2c20dc559a616 --- /dev/null +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleStaticConstructor.cs @@ -0,0 +1,162 @@ +// 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. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Reflection; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeGen; +using Microsoft.CodeAnalysis.Debugging; +using Microsoft.CodeAnalysis.Emit; +using Roslyn.Utilities; + +namespace Microsoft.Cci +{ + internal sealed partial class RootModuleStaticConstructor : IMethodDefinition, IMethodBody + { + public RootModuleStaticConstructor(ITypeDefinition containingTypeDefinition, ImmutableArray il) + { + ContainingTypeDefinition = containingTypeDefinition; + IL = il; + } + + // IMethodDefinition implementation + + public ITypeDefinition ContainingTypeDefinition { get; } + + public string Name => WellKnownMemberNames.StaticConstructorName; + + public IMethodBody GetBody(EmitContext context) => this; + + public IEnumerable GenericParameters => SpecializedCollections.EmptyEnumerable(); + + public bool IsImplicitlyDeclared => true; + + public bool HasDeclarativeSecurity => false; + + public bool IsAbstract => false; + + public bool IsAccessCheckedOnOverride => false; + + public bool IsConstructor => false; + + public bool IsExternal => false; + + public bool IsHiddenBySignature => true; + + public bool IsNewSlot => false; + + public bool IsPlatformInvoke => false; + + public bool IsRuntimeSpecial => true; + + public bool IsSealed => false; + + public bool IsSpecialName => true; + + public bool IsStatic => true; + + public bool IsVirtual => false; + + public ImmutableArray Parameters => ImmutableArray.Empty; + + public IPlatformInvokeInformation PlatformInvokeData => null; + + public bool RequiresSecurityObject => false; + + public bool ReturnValueIsMarshalledExplicitly => false; + + public IMarshallingInformation ReturnValueMarshallingInformation => null; + + public ImmutableArray ReturnValueMarshallingDescriptor => default; + + public IEnumerable SecurityAttributes => null; + + public INamespace ContainingNamespace => null; + + public TypeMemberVisibility Visibility => TypeMemberVisibility.Private; + + public bool AcceptsExtraArguments => false; + + public ushort GenericParameterCount => 0; + + public bool IsGeneric => false; + + public ImmutableArray ExtraParameters => ImmutableArray.Empty; + + public IGenericMethodInstanceReference AsGenericMethodInstanceReference => null; + + public ISpecializedMethodReference AsSpecializedMethodReference => null; + + public CallingConvention CallingConvention => CallingConvention.Default; + + public ushort ParameterCount => 0; + + public ImmutableArray ReturnValueCustomModifiers => ImmutableArray.Empty; + + public ImmutableArray RefCustomModifiers => ImmutableArray.Empty; + + public bool ReturnValueIsByRef => false; + + public IDefinition AsDefinition(EmitContext context) => this; + + public void Dispatch(MetadataVisitor visitor) => visitor.Visit((IMethodDefinition)this); + + public IEnumerable GetAttributes(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + + public ITypeReference GetContainingType(EmitContext context) => ContainingTypeDefinition; + + public MethodImplAttributes GetImplementationAttributes(EmitContext context) => default; + + public ImmutableArray GetParameters(EmitContext context) => ImmutableArray.Empty; + + public IMethodDefinition GetResolvedMethod(EmitContext context) => this; + + public IEnumerable GetReturnValueAttributes(EmitContext context) => SpecializedCollections.EmptyEnumerable(); + + public ITypeReference GetType(EmitContext context) => context.Module.GetPlatformType(PlatformType.SystemVoid, context); + + // IMethodBody implementation + + public ushort MaxStack => 0; + + public ImmutableArray IL { get; } + + public IMethodDefinition MethodDefinition => this; + + public ImmutableArray ExceptionRegions => ImmutableArray.Empty; + + public bool AreLocalsZeroed => false; + + public bool HasStackalloc => false; + + public ImmutableArray LocalVariables => ImmutableArray.Empty; + + public StateMachineMoveNextBodyDebugInfo MoveNextBodyInfo => null; + + public ImmutableArray SequencePoints => ImmutableArray.Empty; + + public bool HasDynamicLocalVariables => false; + + public ImmutableArray LocalScopes => ImmutableArray.Empty; + + public IImportScope ImportScope => null; + + public DebugId MethodId => default; + + public ImmutableArray StateMachineHoistedLocalScopes => ImmutableArray.Empty; + + public string StateMachineTypeName => null; + + public ImmutableArray StateMachineHoistedLocalSlots => ImmutableArray.Empty; + + public ImmutableArray StateMachineAwaiterSlots => ImmutableArray.Empty; + + public ImmutableArray ClosureDebugInfo => ImmutableArray.Empty; + + public ImmutableArray LambdaDebugInfo => ImmutableArray.Empty; + + public DynamicAnalysisMethodBodyData DynamicAnalysisData => null; + } +} diff --git a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs index 64ce7bc27441f..ae0df807a1708 100644 --- a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs @@ -4,10 +4,12 @@ #nullable enable -using System; using System.Collections.Generic; -using System.Runtime.InteropServices; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; using System.Reflection.Metadata; +using System.Runtime.InteropServices; using Roslyn.Utilities; using EmitContext = Microsoft.CodeAnalysis.Emit.EmitContext; @@ -18,6 +20,18 @@ namespace Microsoft.Cci /// internal class RootModuleType : INamespaceTypeDefinition { + private IReadOnlyList _methods = SpecializedCollections.EmptyReadOnlyList(); + + public void SetStaticConstructorBody(ImmutableArray il) + { + Debug.Assert(!_methods.Any()); + + _methods = SpecializedCollections.SingletonReadOnlyList( + new RootModuleStaticConstructor(containingTypeDefinition: this, il)); + } + + public IEnumerable GetMethods(EmitContext context) => _methods; + public TypeDefinitionHandle TypeDef { get { return default(TypeDefinitionHandle); } @@ -138,11 +152,6 @@ public LayoutKind Layout get { return LayoutKind.Auto; } } - public IEnumerable GetMethods(EmitContext context) - { - return SpecializedCollections.EmptyEnumerable(); - } - public IEnumerable GetNestedTypes(EmitContext context) { return SpecializedCollections.EmptyEnumerable(); From f144ce2a5942f99f4505ce71a1a7ccf8c748f1e9 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 24 Apr 2020 17:30:42 -0400 Subject: [PATCH 16/23] Assert that SetStaticConstructorBody is not called after GetMethods --- src/Compilers/Core/Portable/PEWriter/RootModuleType.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs index ae0df807a1708..220de7aa6f0d5 100644 --- a/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs +++ b/src/Compilers/Core/Portable/PEWriter/RootModuleType.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Linq; using System.Reflection.Metadata; using System.Runtime.InteropServices; using Roslyn.Utilities; @@ -20,17 +19,20 @@ namespace Microsoft.Cci /// internal class RootModuleType : INamespaceTypeDefinition { - private IReadOnlyList _methods = SpecializedCollections.EmptyReadOnlyList(); + private IReadOnlyList? _methods; public void SetStaticConstructorBody(ImmutableArray il) { - Debug.Assert(!_methods.Any()); + Debug.Assert(_methods is null); _methods = SpecializedCollections.SingletonReadOnlyList( new RootModuleStaticConstructor(containingTypeDefinition: this, il)); } - public IEnumerable GetMethods(EmitContext context) => _methods; + public IEnumerable GetMethods(EmitContext context) + { + return _methods ??= SpecializedCollections.EmptyReadOnlyList(); + } public TypeDefinitionHandle TypeDef { From 11c64a8c4c7ee5f9271720806e7ed8c6750cb219 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 24 Apr 2020 17:42:23 -0400 Subject: [PATCH 17/23] Remove unnecessary GetModuleInitializerMethods method --- .../CSharp/Portable/Compilation/CSharpCompilation.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 35ae42fd2b193..c638063671860 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -2016,12 +2016,6 @@ internal void AddModuleInitializerMethod(SourceMethodSymbolWithAttributes method ImmutableInterlocked.Enqueue(ref _moduleInitializerMethods, method); } - internal ImmutableQueue GetModuleInitializerMethods() - { - Debug.Assert(_declarationDiagnosticsFrozen); - return _moduleInitializerMethods; - } - #endregion #region Binding @@ -2824,12 +2818,14 @@ internal override bool CompileMethods( private void GenerateModuleInitializer(PEModuleBuilder moduleBeingBuilt, DiagnosticBag methodBodyDiagnosticBag) { - if (GetModuleInitializerMethods() is { IsEmpty: false } moduleInitializerMethods) + Debug.Assert(_declarationDiagnosticsFrozen); + + if (!_moduleInitializerMethods.IsEmpty) { var ilBuilder = new ILBuilder(moduleBeingBuilt, new LocalSlotManager(slotAllocator: null), OptimizationLevel.Release, areLocalsZeroed: true); // PROTOTYPE(module-initializers): require deterministic order - foreach (var method in moduleInitializerMethods) + foreach (var method in _moduleInitializerMethods) { ilBuilder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0); From 2960b8be3f17b2a584a0a736773dc0e2dc5b09ae Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 24 Apr 2020 17:43:41 -0400 Subject: [PATCH 18/23] fixup! Emit without synthesizing symbols --- .../CSharp/Portable/Compilation/CSharpCompilation.cs | 2 +- .../CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index c638063671860..653e48e7ea306 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -2822,7 +2822,7 @@ private void GenerateModuleInitializer(PEModuleBuilder moduleBeingBuilt, Diagnos if (!_moduleInitializerMethods.IsEmpty) { - var ilBuilder = new ILBuilder(moduleBeingBuilt, new LocalSlotManager(slotAllocator: null), OptimizationLevel.Release, areLocalsZeroed: true); + var ilBuilder = new ILBuilder(moduleBeingBuilt, new LocalSlotManager(slotAllocator: null), OptimizationLevel.Release, areLocalsZeroed: false); // PROTOTYPE(module-initializers): require deterministic order foreach (var method in _moduleInitializerMethods) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs index 1c4113f884769..4f53bc7942c27 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs @@ -91,10 +91,10 @@ class Program namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : System.Attribute { } } "; - var x = CompileAndVerify( + CompileAndVerify( source, parseOptions: s_parseOptions, - options: new CSharpCompilationOptions(OutputKind.ConsoleApplication, metadataImportOptions: MetadataImportOptions.All), + options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: module => { var rootModuleType = (TypeSymbol)module.GlobalNamespace.GetMember(""); From 0d0936dc354e8311f73e8f5aec82b6e28b7ffff0 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 24 Apr 2020 17:47:13 -0400 Subject: [PATCH 19/23] Remove unnecessary dependency on SourceMethodSymbolWithAttributes.SyntaxNode --- src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 653e48e7ea306..68a1478912a9d 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -2831,7 +2831,7 @@ private void GenerateModuleInitializer(PEModuleBuilder moduleBeingBuilt, Diagnos ilBuilder.EmitToken( moduleBeingBuilt.Translate(method, methodBodyDiagnosticBag, needDeclaration: true), - method.SyntaxNode, + CSharpSyntaxTree.Dummy.GetRoot(), methodBodyDiagnosticBag); } From a83e6df05a43a9c5f0d7e61a1be3790c43a7b957 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 24 Apr 2020 18:19:36 -0400 Subject: [PATCH 20/23] Use ConcurrentSet to prevent duplicates --- .../CSharp/Portable/Compilation/CSharpCompilation.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 68a1478912a9d..938e150d106cf 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -2008,12 +2008,12 @@ private protected override bool IsSymbolAccessibleWithinCore( throw new NotImplementedException(); } - private ImmutableQueue _moduleInitializerMethods = ImmutableQueue.Empty; + private ConcurrentSet? _moduleInitializerMethods; internal void AddModuleInitializerMethod(SourceMethodSymbolWithAttributes method) { Debug.Assert(!_declarationDiagnosticsFrozen); - ImmutableInterlocked.Enqueue(ref _moduleInitializerMethods, method); + LazyInitializer.EnsureInitialized(ref _moduleInitializerMethods).Add(method); } #endregion @@ -2820,7 +2820,7 @@ private void GenerateModuleInitializer(PEModuleBuilder moduleBeingBuilt, Diagnos { Debug.Assert(_declarationDiagnosticsFrozen); - if (!_moduleInitializerMethods.IsEmpty) + if (_moduleInitializerMethods is object) { var ilBuilder = new ILBuilder(moduleBeingBuilt, new LocalSlotManager(slotAllocator: null), OptimizationLevel.Release, areLocalsZeroed: false); From 8fb31eda1e5b08ba52c7e0651a96f5bbfbbe644b Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 24 Apr 2020 18:23:46 -0400 Subject: [PATCH 21/23] Allow any MethodSymbol to be added as a module initializer for the compilation --- .../CSharp/Portable/Compilation/CSharpCompilation.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 938e150d106cf..c6fa6ca8950c9 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -2008,9 +2008,9 @@ private protected override bool IsSymbolAccessibleWithinCore( throw new NotImplementedException(); } - private ConcurrentSet? _moduleInitializerMethods; + private ConcurrentSet? _moduleInitializerMethods; - internal void AddModuleInitializerMethod(SourceMethodSymbolWithAttributes method) + internal void AddModuleInitializerMethod(MethodSymbol method) { Debug.Assert(!_declarationDiagnosticsFrozen); LazyInitializer.EnsureInitialized(ref _moduleInitializerMethods).Add(method); From 34dd24af7984c369933c16fc08cacef23fe130f1 Mon Sep 17 00:00:00 2001 From: jnm2 Date: Fri, 24 Apr 2020 18:37:37 -0400 Subject: [PATCH 22/23] Assert expected metadata flags --- .../Symbol/Symbols/ModuleInitializersTests.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs index 4f53bc7942c27..bb4b247e42a87 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Reflection; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; @@ -98,7 +100,19 @@ namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : S symbolValidator: module => { var rootModuleType = (TypeSymbol)module.GlobalNamespace.GetMember(""); - Assert.NotNull(rootModuleType.GetMember(".cctor")); + var staticConstructor = (PEMethodSymbol)rootModuleType.GetMember(".cctor"); + + Assert.NotNull(staticConstructor); + Assert.Equal(MethodKind.StaticConstructor, staticConstructor.MethodKind); + + var expectedFlags = + MethodAttributes.Private + | MethodAttributes.Static + | MethodAttributes.SpecialName + | MethodAttributes.RTSpecialName + | MethodAttributes.HideBySig; + + Assert.Equal(expectedFlags, staticConstructor.Flags); }, expectedOutput: @" C.M From 771e905b120ad468362ce2dde9763126eb5515bb Mon Sep 17 00:00:00 2001 From: jnm2 Date: Sat, 25 Apr 2020 14:52:52 -0400 Subject: [PATCH 23/23] Add specific test that C# 9 is the first version supporting module initializers --- .../Symbol/Symbols/ModuleInitializersTests.cs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs index bb4b247e42a87..558aab4d66028 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/ModuleInitializersTests.cs @@ -17,7 +17,7 @@ public sealed class ModuleInitializersTests : CSharpTestBase private static readonly CSharpParseOptions s_parseOptions = TestOptions.RegularPreview; [Fact] - public static void ModuleInitializersNotUsableInCSharp8() + public static void LastLanguageVersionNotSupportingModuleInitializersIs8() { var source = @"using System.Runtime.CompilerServices; @@ -39,6 +39,25 @@ namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : S ); } + [Fact] + public static void FirstLanguageVersionSupportingModuleInitializersIs9() + { + var source = +@"using System.Runtime.CompilerServices; + +class C +{ + [ModuleInitializer] + internal static void M() { } +} + +namespace System.Runtime.CompilerServices { class ModuleInitializerAttribute : System.Attribute { } } +"; + var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + + compilation.VerifyDiagnostics(); + } + [Fact] public void ModuleTypeStaticConstructorIsNotEmittedWhenNoMethodIsMarkedWithModuleInitializerAttribute() {