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

Main attributes for simple programs #59471

Closed
7 changes: 5 additions & 2 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -3302,7 +3302,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep
<value>'{0}' does not contain a constructor that takes {1} arguments</value>
</data>
<data name="ERR_GlobalAttributesNotFirst" xml:space="preserve">
<value>Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations</value>
<value>Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations</value>
</data>
<data name="ERR_ExpressionExpected" xml:space="preserve">
<value>Expected expression</value>
Expand Down Expand Up @@ -3975,7 +3975,7 @@ You should consider suppressing the warning only if you're sure that you don't w
<value>Cannot declare namespace in script code</value>
</data>
<data name="ERR_GlobalAttributesNotAllowed" xml:space="preserve">
<value>Assembly and module attributes are not allowed in this context</value>
<value>Assembly, module, and main attributes are not allowed in this context</value>
</data>
<data name="ERR_InvalidDelegateType" xml:space="preserve">
<value>Delegate '{0}' has no invoke method or an invoke method with a return type or parameter types that are not supported.</value>
Expand Down Expand Up @@ -6986,4 +6986,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_LineContainsDifferentWhitespace" xml:space="preserve">
<value>Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}'</value>
</data>
<data name="IDS_FeatureMainAttributeLocation" xml:space="preserve">
<value>'main' as an attribute target specifier</value>
</data>
</root>
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 @@ -244,6 +244,7 @@ internal enum MessageID

IDS_FeatureCacheStaticMethodGroupConversion = MessageBase + 12816,
IDS_FeatureRawStringLiterals = MessageBase + 12817,
IDS_FeatureMainAttributeLocation = MessageBase + 12818,
}

// Message IDs may refer to strings that need to be localized.
Expand Down Expand Up @@ -360,6 +361,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
case MessageID.IDS_FeatureListPattern: // semantic check
case MessageID.IDS_FeatureCacheStaticMethodGroupConversion: // lowering check
case MessageID.IDS_ParameterNullChecking: // syntax check
case MessageID.IDS_FeatureMainAttributeLocation: // syntax check
return LanguageVersion.Preview;

// C# 10.0 features.
Expand Down
9 changes: 6 additions & 3 deletions src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,7 @@ private static bool IsGlobalAttributeTarget(SyntaxToken token)
{
case AttributeLocation.Assembly:
case AttributeLocation.Module:
case AttributeLocation.Main:
return true;
default:
return false;
Expand Down Expand Up @@ -928,10 +929,12 @@ private AttributeListSyntax ParseAttributeDeclaration()
var attributes = _pool.AllocateSeparated<AttributeSyntax>();
try
{
if (attrLocation != null && attrLocation.Identifier.ToAttributeLocation() == AttributeLocation.Module)
attrLocation = attrLocation?.Identifier.ToAttributeLocation() switch
{
attrLocation = CheckFeatureAvailability(attrLocation, MessageID.IDS_FeatureModuleAttrLoc);
}
AttributeLocation.Module => CheckFeatureAvailability(attrLocation, MessageID.IDS_FeatureModuleAttrLoc),
AttributeLocation.Main => CheckFeatureAvailability(attrLocation, MessageID.IDS_FeatureMainAttributeLocation),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We generally want to prefer doing semantic checks for these types of things if reasonable to do.

_ => attrLocation
};

this.ParseAttributes(attributes);
var closeBracket = this.EatToken(SyntaxKind.CloseBracketToken);
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TryStatement(Microsoft.CodeAn
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TryStatement(Microsoft.CodeAnalysis.SyntaxToken tryKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! block, Microsoft.CodeAnalysis.SyntaxList<Microsoft.CodeAnalysis.CSharp.Syntax.CatchClauseSyntax!> catches, Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax? finally) -> Microsoft.CodeAnalysis.CSharp.Syntax.TryStatementSyntax!
*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TryStatement(Microsoft.CodeAnalysis.SyntaxToken tryKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! block, Microsoft.CodeAnalysis.SyntaxList<Microsoft.CodeAnalysis.CSharp.Syntax.CatchClauseSyntax!> catches, Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! finally) -> Microsoft.CodeAnalysis.CSharp.Syntax.TryStatementSyntax!
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.InterpolatedStringExpression(Microsoft.CodeAnalysis.SyntaxToken stringStartToken, Microsoft.CodeAnalysis.SyntaxToken stringEndToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.InterpolatedStringExpressionSyntax!
Microsoft.CodeAnalysis.CSharp.SyntaxKind.MainKeyword = 8447 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ internal enum AttributeLocation : short
Parameter = 1 << 7,
Return = 1 << 8,
TypeParameter = 1 << 9,
Main = 1 << 10,

// must be the last:
Unknown = 1 << 10,
Unknown = 1 << 11,
}

internal static class AttributeLocationExtensions
Expand Down Expand Up @@ -90,6 +91,10 @@ internal static string ToDisplayString(this AttributeLocation locations)
result.Append("typevar");
break;

case AttributeLocation.Main:
result.Append("main");
break;

default:
throw ExceptionUtilities.UnexpectedValue(i);
}
Expand Down Expand Up @@ -139,6 +144,8 @@ private static AttributeLocation ToAttributeLocation(string text)
return AttributeLocation.Property;
case "typevar":
return AttributeLocation.TypeParameter;
case "main":
return AttributeLocation.Main;
default:
return AttributeLocation.None;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2322,7 +2322,7 @@ AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations
{
get
{
return IsInteractive ? AttributeLocation.None : AttributeLocation.Assembly | AttributeLocation.Module;
return IsInteractive ? AttributeLocation.None : AttributeLocation.Assembly | AttributeLocation.Module | AttributeLocation.Main;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ private static bool MatchAttributeTarget(IAttributeTargetSymbol attributeTarget,
{
case AttributeLocation.Assembly:
case AttributeLocation.Module:
case AttributeLocation.Main:
// global attributes are disallowed in interactive code:
diagnostics.Add(ErrorCode.ERR_GlobalAttributesNotAllowed, targetOpt.Identifier.GetLocation());
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal sealed class SynthesizedSimpleProgramEntryPointSymbol : SourceMemberMethodSymbol
internal sealed class SynthesizedSimpleProgramEntryPointSymbol : SourceMemberMethodSymbol, IAttributeTargetSymbol
{
/// <summary>
/// The corresponding <see cref="SingleTypeDeclaration"/>.
Expand Down Expand Up @@ -281,6 +281,22 @@ internal override bool IsDefinedInSourceTree(SyntaxTree tree, TextSpan? definedW

public SyntaxNode ReturnTypeSyntax => CompilationUnit.Members.First(m => m.Kind() == SyntaxKind.GlobalStatement);

internal override OneOrMany<SyntaxList<AttributeListSyntax>> GetAttributeDeclarations()
{
// there could me multiple simple program entry points. Only consider [main:] attributes
// if we're the entry point that will ultimately be selected.
if (this == GetSimpleProgramEntryPoint(DeclaringCompilation))
{
return OneOrMany.Create(((SourceAssemblySymbol)ContainingAssembly).GetAttributeDeclarations());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the later filtering on these for only main declarations?

}

return OneOrMany<SyntaxList<AttributeListSyntax>>.Empty;
}

protected override IAttributeTargetSymbol AttributeOwner => (IAttributeTargetSymbol)this.ContainingAssembly;

AttributeLocation IAttributeTargetSymbol.DefaultAttributeLocation => AttributeLocation.Main;

private static bool IsNullableAnalysisEnabled(CSharpCompilation compilation, CompilationUnitSyntax syntax)
{
foreach (var member in syntax.Members)
Expand Down
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,8 @@ public enum SyntaxKind : ushort
ManagedKeyword = 8445,
/// <summary>Represents <see langword="unmanaged"/>.</summary>
UnmanagedKeyword = 8446,
/// <summary>Represents <see langword="main"/>.</summary>
MainKeyword = 8447,

// when adding a contextual keyword following functions must be adapted:
// <see cref="SyntaxFacts.GetContextualKeywordKinds"/>
Expand Down
7 changes: 6 additions & 1 deletion src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1075,7 +1075,7 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text)

public static IEnumerable<SyntaxKind> GetContextualKeywordKinds()
{
for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.UnmanagedKeyword; i++)
for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.MainKeyword; i++)
{
yield return (SyntaxKind)i;
}
Expand Down Expand Up @@ -1128,6 +1128,7 @@ public static bool IsContextualKeyword(SyntaxKind kind)
case SyntaxKind.RecordKeyword:
case SyntaxKind.ManagedKeyword:
case SyntaxKind.UnmanagedKeyword:
case SyntaxKind.MainKeyword:
return true;
default:
return false;
Expand Down Expand Up @@ -1247,6 +1248,8 @@ public static SyntaxKind GetContextualKeywordKind(string text)
return SyntaxKind.ManagedKeyword;
case "unmanaged":
return SyntaxKind.UnmanagedKeyword;
case "main":
return SyntaxKind.MainKeyword;
default:
return SyntaxKind.None;
}
Expand Down Expand Up @@ -1684,6 +1687,8 @@ public static string GetText(SyntaxKind kind)
return "managed";
case SyntaxKind.UnmanagedKeyword:
return "unmanaged";
case SyntaxKind.MainKeyword:
return "main";
default:
return string.Empty;
}
Expand Down
13 changes: 9 additions & 4 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading