Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Features/module initializers #46071

Merged
merged 38 commits into from
Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
176ad60
Merge pull request #43714 from dotnet/master
JoeRobich Apr 27, 2020
6fe4010
Codegen for module initializers feature (#43281)
jnm2 Apr 28, 2020
e61e71c
Merge remote-tracking branch 'upstream/master' into merges/master-to-…
RikkiGibson May 4, 2020
8aa9686
Fix merge conflicts
RikkiGibson May 4, 2020
eee9c61
Merge pull request #43968 from RikkiGibson/merges/master-to-features/…
May 5, 2020
00f92ac
Module initializers deterministic ordering (#43964)
RikkiGibson May 7, 2020
8145427
Diagnostics for module initializers feature (#43301)
jnm2 May 12, 2020
3790b6b
Disallow module initializers in VB (#44227)
RikkiGibson May 15, 2020
6e6ab9a
Merge remote-tracking branch 'upstream/master' into merges/master-to-…
RikkiGibson May 16, 2020
95abfb4
Merge pull request #44314 from dotnet/merges/master-to-features/modul…
May 16, 2020
d5faa63
Test netmodules containing module initializers (#44228)
RikkiGibson May 16, 2020
f7522d1
Merge remote-tracking branch 'upstream/master' into merges/master-to-…
RikkiGibson Jun 11, 2020
0bcbd4f
Merge pull request #44963 from dotnet/merges/master-to-features/modul…
Jun 11, 2020
d09d7ab
Merge branch 'features/module-initializers' into merges/master-to-fea…
RikkiGibson Jun 18, 2020
ae703fe
Merge pull request #45271 from dotnet/merges/master-to-features/modul…
Jun 18, 2020
635b016
Merge remote-tracking branch 'upstream/master' into merges/master-to-…
RikkiGibson Jun 19, 2020
8975f88
Merge pull request #45307 from dotnet/merges/master-to-features/modul…
Jun 19, 2020
6127260
Merge pull request #45333 from dotnet/merges/master-to-features/modul…
Jun 20, 2020
61ac775
Merge pull request #45344 from dotnet/merges/master-to-features/modul…
Jun 22, 2020
d7ba863
Merge pull request #45370 from dotnet/merges/master-to-features/modul…
Jun 23, 2020
d908825
Merge pull request #45410 from dotnet/merges/master-to-features/modul…
Jun 24, 2020
f96e8aa
Merge pull request #45439 from dotnet/merges/master-to-features/modul…
Jun 28, 2020
8505050
Merge branch 'features/module-initializers' into merges/master-to-fea…
RikkiGibson Jun 30, 2020
265dde5
Merge branch 'master' of github.com:dotnet/roslyn into merges/master-…
RikkiGibson Jul 1, 2020
388f75e
Merge pull request #45549 from dotnet/merges/master-to-features/modul…
Jul 1, 2020
c0192fe
Merge branch 'features/module-initializers' into merges/master-to-fea…
RikkiGibson Jul 2, 2020
e35d0dc
Merge pull request #45604 from dotnet/merges/master-to-features/modul…
Jul 2, 2020
47e448e
Merge branch 'features/module-initializers' into merges/master-to-fea…
RikkiGibson Jul 3, 2020
8cd4e03
Merge pull request #45634 from dotnet/merges/master-to-features/modul…
Jul 3, 2020
4d7a526
Merge branch 'features/module-initializers' into merges/master-to-fea…
RikkiGibson Jul 4, 2020
a2acd33
Merge pull request #45646 from dotnet/merges/master-to-features/modul…
Jul 4, 2020
e220ae0
Merge pull request #45720 from dotnet/merges/master-to-features/modul…
Jul 7, 2020
7e57320
Merge pull request #45773 from dotnet/merges/master-to-features/modul…
Jul 8, 2020
f4a6672
Merge remote-tracking branch 'upstream/master' into merges/master-to-…
RikkiGibson Jul 14, 2020
7a6822a
Merge pull request #45818 from dotnet/merges/master-to-features/modul…
Jul 15, 2020
9564bd7
Add tests (#45969)
RikkiGibson Jul 15, 2020
91eb6ee
Merge pull request #46025 from dotnet/merges/master-to-features/modul…
Jul 16, 2020
ab38a9d
Add additional module initializers tests from review (#46020)
RikkiGibson Jul 17, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -6319,4 +6319,19 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_DoesNotOverrideBaseEqualityContract" xml:space="preserve">
<value>'{0}' does not override expected property from '{1}'.</value>
</data>
<data name="IDS_FeatureModuleInitializers" xml:space="preserve">
<value>module initializers</value>
</data>
<data name="ERR_ModuleInitializerMethodMustBeAccessibleOutsideTopLevelType" xml:space="preserve">
<value>Module initializer method '{0}' must be accessible at the module level</value>
</data>
<data name="ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid" xml:space="preserve">
<value>Module initializer method '{0}' must be static, must have no parameters, and must return 'void'</value>
</data>
<data name="ERR_ModuleInitializerMethodAndContainingTypesMustNotBeGeneric" xml:space="preserve">
<value>Module initializer method '{0}' must not be generic and must not be contained in a generic type</value>
</data>
<data name="ERR_ModuleInitializerMethodMustBeOrdinary" xml:space="preserve">
<value>A module initializer must be an ordinary member method</value>
</data>
</root>
38 changes: 38 additions & 0 deletions src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Cci;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols;
Expand Down Expand Up @@ -2057,6 +2058,14 @@ private protected override bool IsSymbolAccessibleWithinCore(
throw new NotImplementedException();
}

private ConcurrentSet<MethodSymbol>? _moduleInitializerMethods;

internal void AddModuleInitializerMethod(MethodSymbol method)
{
Debug.Assert(!_declarationDiagnosticsFrozen);
LazyInitializer.EnsureInitialized(ref _moduleInitializerMethods).Add(method);
}

#endregion

#region Binding
Expand Down Expand Up @@ -2857,6 +2866,11 @@ internal override bool CompileMethods(
filterOpt: filterOpt,
cancellationToken: cancellationToken);

if (!hasDeclarationErrors && !CommonCompiler.HasUnsuppressableErrors(methodBodyDiagnosticBag))
{
GenerateModuleInitializer(moduleBeingBuilt, methodBodyDiagnosticBag);
}

bool hasMethodBodyError = !FilterAndAppendAndFreeDiagnostics(diagnostics, ref methodBodyDiagnosticBag);

if (hasDeclarationErrors || hasMethodBodyError)
Expand All @@ -2868,6 +2882,30 @@ internal override bool CompileMethods(
return true;
}

private void GenerateModuleInitializer(PEModuleBuilder moduleBeingBuilt, DiagnosticBag methodBodyDiagnosticBag)
{
Debug.Assert(_declarationDiagnosticsFrozen);

if (_moduleInitializerMethods is object)
{
var ilBuilder = new ILBuilder(moduleBeingBuilt, new LocalSlotManager(slotAllocator: null), OptimizationLevel.Release, areLocalsZeroed: false);

foreach (MethodSymbol method in _moduleInitializerMethods.OrderBy<MethodSymbol>(LexicalOrderSymbolComparer.Instance))
{
ilBuilder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0);

ilBuilder.EmitToken(
moduleBeingBuilt.Translate(method, methodBodyDiagnosticBag, needDeclaration: true),
CSharpSyntaxTree.Dummy.GetRoot(),
methodBodyDiagnosticBag);
}

ilBuilder.EmitRet(isVoid: true);
ilBuilder.Realize();
moduleBeingBuilt.RootModuleType.SetStaticConstructorBody(ilBuilder.RealizedIL);
}
}

internal override bool GenerateResourcesAndDocumentationComments(
CommonPEModuleBuilder moduleBuilder,
Stream? xmlDocStream,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@

namespace Microsoft.CodeAnalysis.CSharp
{
/// <summary> This is an implementation of a special symbol comparer, which is supposed to be used for
/// sorting original definition symbols (explicitly or explicitly declared in source within the same
/// container) in lexical order of their declarations. It will not work on anything that uses non-source locations.
/// </summary>
/// <summary>
/// This is an implementation of a special symbol comparer, which is supposed to be used for sorting
/// original definition symbols (explicitly or implicitly declared in source within the same compilation)
/// in lexical order of their declarations. It will not work on anything that uses non-source locations.
/// </summary>
internal class LexicalOrderSymbolComparer : IComparer<Symbol>
{
public static readonly LexicalOrderSymbolComparer Instance = new LexicalOrderSymbolComparer();
Expand All @@ -30,6 +31,7 @@ public int Compare(Symbol x, Symbol y)

var xSortKey = x.GetLexicalSortKey();
var ySortKey = y.GetLexicalSortKey();
Debug.Assert((object)x.DeclaringCompilation == y.DeclaringCompilation);

comparison = LexicalSortKey.Compare(xSortKey, ySortKey);
if (comparison != 0)
Expand Down
11 changes: 4 additions & 7 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1820,13 +1820,10 @@ internal enum ErrorCode
ERR_CannotConvertAddressOfToDelegate = 8811,
ERR_AddressOfToNonFunctionPointer = 8812,

ERR_8813 = 8813, // used by features/module-initializers

ERR_8814 = 8814, // used by features/module-initializers

ERR_8815 = 8815, // used by features/module-initializers

ERR_8816 = 8816, // used by features/module-initializers
ERR_ModuleInitializerMethodMustBeOrdinary = 8813,
ERR_ModuleInitializerMethodMustBeAccessibleOutsideTopLevelType = 8814,
ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid = 8815,
ERR_ModuleInitializerMethodAndContainingTypesMustNotBeGeneric = 8816,

ERR_PartialMethodReturnTypeDifference = 8817,
ERR_PartialMethodRefReturnDifference = 8818,
Expand Down
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/MessageID.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ internal enum MessageID
IDS_FeatureInitOnlySetters = MessageBase + 12781,
IDS_FeatureRecords = MessageBase + 12782,
IDS_FeatureNullPointerConstantPattern = MessageBase + 12783,
IDS_FeatureModuleInitializers = MessageBase + 12784,
}

// Message IDs may refer to strings that need to be localized.
Expand Down Expand Up @@ -332,6 +333,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
case MessageID.IDS_FeatureInitOnlySetters: // semantic check
case MessageID.IDS_FeatureRecords:
case MessageID.IDS_FeatureStaticAnonymousFunction: // syntax check
case MessageID.IDS_FeatureModuleInitializers: // semantic check on method attribute
return LanguageVersion.Preview;

// C# 8.0 features.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;

Expand Down Expand Up @@ -486,6 +487,11 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut
MessageID.IDS_FeatureMemberNotNull.CheckFeatureAvailability(arguments.Diagnostics, arguments.AttributeSyntaxOpt);
CSharpAttributeData.DecodeMemberNotNullWhenAttribute<MethodWellKnownAttributeData>(ContainingType, ref arguments);
}
else if (attribute.IsTargetAttribute(this, AttributeDescription.ModuleInitializerAttribute))
{
MessageID.IDS_FeatureModuleInitializers.CheckFeatureAvailability(arguments.Diagnostics, arguments.AttributeSyntaxOpt);
DecodeModuleInitializerAttribute(arguments);
}
else
{
var compilation = this.DeclaringCompilation;
Expand Down Expand Up @@ -762,6 +768,46 @@ private void DecodeDllImportAttribute(ref DecodeWellKnownAttributeArguments<Attr
preserveSig);
}
}

private void DecodeModuleInitializerAttribute(DecodeWellKnownAttributeArguments<AttributeSyntax, CSharpAttributeData, AttributeLocation> arguments)
{
Debug.Assert(arguments.AttributeSyntaxOpt is object);

if (MethodKind != MethodKind.Ordinary)
{
arguments.Diagnostics.Add(ErrorCode.ERR_ModuleInitializerMethodMustBeOrdinary, arguments.AttributeSyntaxOpt.Location);
return;
}

Debug.Assert(ContainingType is object);
var hasError = false;

HashSet<DiagnosticInfo>? useSiteDiagnostics = null;
if (!AccessCheck.IsSymbolAccessible(this, ContainingAssembly, ref useSiteDiagnostics))
{
arguments.Diagnostics.Add(ErrorCode.ERR_ModuleInitializerMethodMustBeAccessibleOutsideTopLevelType, arguments.AttributeSyntaxOpt.Location, Name);
hasError = true;
}

arguments.Diagnostics.Add(arguments.AttributeSyntaxOpt, useSiteDiagnostics);

if (!IsStatic || ParameterCount > 0 || !ReturnsVoid)
{
arguments.Diagnostics.Add(ErrorCode.ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid, arguments.AttributeSyntaxOpt.Location, Name);
hasError = true;
}

if (IsGenericMethod || ContainingType.IsGenericType)
{
arguments.Diagnostics.Add(ErrorCode.ERR_ModuleInitializerMethodAndContainingTypesMustNotBeGeneric, arguments.AttributeSyntaxOpt.Location, Name);
hasError = true;
}

if (!hasError && !CallsAreOmitted(arguments.AttributeSyntaxOpt.SyntaxTree))
{
DeclaringCompilation.AddModuleInitializerMethod(this);
}
}
#nullable restore

internal sealed override void PostDecodeWellKnownAttributes(ImmutableArray<CSharpAttributeData> boundAttributes, ImmutableArray<AttributeSyntax> allAttributeSyntaxNodes, DiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
Expand Down
25 changes: 25 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,26 @@
<target state="translated">Chybějící vzor</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodAndContainingTypesMustNotBeGeneric">
<source>Module initializer method '{0}' must not be generic and must not be contained in a generic type</source>
<target state="new">Module initializer method '{0}' must not be generic and must not be contained in a generic type</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodMustBeAccessibleOutsideTopLevelType">
<source>Module initializer method '{0}' must be accessible at the module level</source>
<target state="new">Module initializer method '{0}' must be accessible at the module level</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodMustBeOrdinary">
<source>A module initializer must be an ordinary member method</source>
<target state="new">A module initializer must be an ordinary member method</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid">
<source>Module initializer method '{0}' must be static, must have no parameters, and must return 'void'</source>
<target state="new">Module initializer method '{0}' must be static, must have no parameters, and must return 'void'</target>
<note />
</trans-unit>
<trans-unit id="ERR_MultipleAnalyzerConfigsInSameDir">
<source>Multiple analyzer config files cannot be in the same directory ('{0}').</source>
<target state="translated">Ve stejném adresáři nemůže být více konfiguračních souborů analyzátoru ({0}).</target>
Expand Down Expand Up @@ -1284,6 +1304,11 @@
<target state="new">MemberNotNull attribute</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureModuleInitializers">
<source>module initializers</source>
<target state="new">module initializers</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureNameShadowingInNestedFunctions">
<source>name shadowing in nested functions</source>
<target state="translated">skrývání názvů ve vnořených funkcích</target>
Expand Down
25 changes: 25 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,26 @@
<target state="translated">Muster fehlt.</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodAndContainingTypesMustNotBeGeneric">
<source>Module initializer method '{0}' must not be generic and must not be contained in a generic type</source>
<target state="new">Module initializer method '{0}' must not be generic and must not be contained in a generic type</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodMustBeAccessibleOutsideTopLevelType">
<source>Module initializer method '{0}' must be accessible at the module level</source>
<target state="new">Module initializer method '{0}' must be accessible at the module level</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodMustBeOrdinary">
<source>A module initializer must be an ordinary member method</source>
<target state="new">A module initializer must be an ordinary member method</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid">
<source>Module initializer method '{0}' must be static, must have no parameters, and must return 'void'</source>
<target state="new">Module initializer method '{0}' must be static, must have no parameters, and must return 'void'</target>
<note />
</trans-unit>
<trans-unit id="ERR_MultipleAnalyzerConfigsInSameDir">
<source>Multiple analyzer config files cannot be in the same directory ('{0}').</source>
<target state="translated">Dasselbe Verzeichnis ({0}) darf nicht mehrere Konfigurationsdateien des Analysetools enthalten.</target>
Expand Down Expand Up @@ -1284,6 +1304,11 @@
<target state="new">MemberNotNull attribute</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureModuleInitializers">
<source>module initializers</source>
<target state="new">module initializers</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureNameShadowingInNestedFunctions">
<source>name shadowing in nested functions</source>
<target state="translated">Namensshadowing in geschachtelten Funktionen</target>
Expand Down
25 changes: 25 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,26 @@
<target state="translated">Falta un patrón.</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodAndContainingTypesMustNotBeGeneric">
<source>Module initializer method '{0}' must not be generic and must not be contained in a generic type</source>
<target state="new">Module initializer method '{0}' must not be generic and must not be contained in a generic type</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodMustBeAccessibleOutsideTopLevelType">
<source>Module initializer method '{0}' must be accessible at the module level</source>
<target state="new">Module initializer method '{0}' must be accessible at the module level</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodMustBeOrdinary">
<source>A module initializer must be an ordinary member method</source>
<target state="new">A module initializer must be an ordinary member method</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid">
<source>Module initializer method '{0}' must be static, must have no parameters, and must return 'void'</source>
<target state="new">Module initializer method '{0}' must be static, must have no parameters, and must return 'void'</target>
<note />
</trans-unit>
<trans-unit id="ERR_MultipleAnalyzerConfigsInSameDir">
<source>Multiple analyzer config files cannot be in the same directory ('{0}').</source>
<target state="translated">No es posible que un mismo directorio ("{0}") contenga varios archivos de configuración del analizador.</target>
Expand Down Expand Up @@ -1284,6 +1304,11 @@
<target state="new">MemberNotNull attribute</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureModuleInitializers">
<source>module initializers</source>
<target state="new">module initializers</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureNameShadowingInNestedFunctions">
<source>name shadowing in nested functions</source>
<target state="translated">sombreado de nombres en funciones anidadas</target>
Expand Down
25 changes: 25 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,26 @@
<target state="translated">Modèle manquant</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodAndContainingTypesMustNotBeGeneric">
<source>Module initializer method '{0}' must not be generic and must not be contained in a generic type</source>
<target state="new">Module initializer method '{0}' must not be generic and must not be contained in a generic type</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodMustBeAccessibleOutsideTopLevelType">
<source>Module initializer method '{0}' must be accessible at the module level</source>
<target state="new">Module initializer method '{0}' must be accessible at the module level</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodMustBeOrdinary">
<source>A module initializer must be an ordinary member method</source>
<target state="new">A module initializer must be an ordinary member method</target>
<note />
</trans-unit>
<trans-unit id="ERR_ModuleInitializerMethodMustBeStaticParameterlessVoid">
<source>Module initializer method '{0}' must be static, must have no parameters, and must return 'void'</source>
<target state="new">Module initializer method '{0}' must be static, must have no parameters, and must return 'void'</target>
<note />
</trans-unit>
<trans-unit id="ERR_MultipleAnalyzerConfigsInSameDir">
<source>Multiple analyzer config files cannot be in the same directory ('{0}').</source>
<target state="translated">Plusieurs fichiers config d'analyseur ne peuvent pas figurer dans le même répertoire ('{0}').</target>
Expand Down Expand Up @@ -1284,6 +1304,11 @@
<target state="new">MemberNotNull attribute</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureModuleInitializers">
<source>module initializers</source>
<target state="new">module initializers</target>
<note />
</trans-unit>
<trans-unit id="IDS_FeatureNameShadowingInNestedFunctions">
<source>name shadowing in nested functions</source>
<target state="translated">ombrage des noms dans les fonctions imbriquées</target>
Expand Down
Loading