-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Add main attributes proposal #5817
Closed
Closed
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
# Attribute target for Simple programs | ||
|
||
## Summary | ||
|
||
C# should allow an attribute to target the main method / program entrypoint | ||
without the need for it to be syntactically placed next to it. | ||
|
||
## Motivation | ||
|
||
Today, top level (simple) programs have no way to place attributes on the main | ||
method, as there is no syntactic place for them to attach to. This means that | ||
application models, such as Windows Forms, cannot take advantage of the | ||
simplified entry point as they require additional attributes to be placed on | ||
main (see | ||
<https://github.com/dotnet/designs/blob/main/accepted/2021/winforms/streamline-application-bootstrap.md>). | ||
|
||
Further if a source generator wishes to add an attribute to the main method, the | ||
user of the generator must not use top level statements and explicitly make | ||
their main method `partial`. | ||
|
||
## Detailed design | ||
|
||
A new global attribute target `main` will be recognized alongside `assembly` and | ||
`module`, that allows an attribute to specify it should be attached to the | ||
entrypoint of a simple / top level program. | ||
|
||
For example: | ||
|
||
```csharp | ||
[main: STAThread] | ||
``` | ||
|
||
Can be placed in any syntax tree of the compilation, and the `[STAThread]` | ||
attribute will be attached the entrypoint of the program. | ||
|
||
Only simple program entrypoints are supported. In the case of multiple | ||
entrypoints the attribute will only apply to the first chosen location. | ||
|
||
### Assemblies with no top level statements | ||
|
||
It is an error to use the `[main:` target in a program that has no top level | ||
statements. This includes assemblies with no entry point (e.g. a class library) | ||
or a program with a regular entrypoint (e.g. `static void Main()`). | ||
|
||
### Attribute locations | ||
|
||
There is no new | ||
[`AttributeTargets`](https://docs.microsoft.com/en-us/dotnet/api/system.attributetargets?view=net-6.0) | ||
enum value defined as part of this proposal, and it is an error to prefix an | ||
attribute with `[main:` that has a target where the `AttributeTargets.Method` | ||
flag is not set (e.g. | ||
`(target & AttributeTargets.Method) != AttributeTargets.Method`) | ||
|
||
The | ||
[`AllowMultiple`](https://docs.microsoft.com/en-us/dotnet/api/system.attributeusageattribute.allowmultiple?view=net-6.0) | ||
field of `AttributeUsage` is respected, and it is an error to prefix an | ||
attribute with `[main:` multiple times unless `AllowMultiple` is set to true. | ||
This applies across all syntax trees, only one prefixed attribute is allowed | ||
regardless of location defined. | ||
|
||
```csharp | ||
public class SingleAttribute : Attribute { } | ||
|
||
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)] | ||
public class MultiAttribute : Attribute { } | ||
|
||
[AttributeUsage(AttributeTargets.Class)] | ||
public class ClassOnlyAttribute : Attribute { } | ||
|
||
/// file1.cs | ||
[main: Single] | ||
[main: Single] // error CS0579: Duplicate 'Single' attribute | ||
[main: Multi] | ||
[main: Multi] | ||
|
||
/// file2.cs | ||
|
||
[main: Single] // error CS0579: Duplicate 'Single' attribute | ||
[main: Multi] | ||
[main:ClassOnly] //error CS0592: Attribute 'ClassOnly' is not valid on this declaration type. It is only valid on 'class' declarations. | ||
``` | ||
|
||
## Open Questions | ||
|
||
### Targeting non simple entry points | ||
|
||
There is some complexity in identifying exactly which method is the entrypoint | ||
for regular (non-simple) entrypoints in the compiler. It currently happens | ||
fairly late and we will need to bring it forward in order just to bind for this | ||
to work. | ||
|
||
However, if we don't do it, then it pushes that complexity onto the generator | ||
author to identify which kind of entrypoint the user is using and change | ||
generation strategies accordingly. | ||
|
||
That might be considered a feature: source generators can't edit user code and | ||
one could argue that adding attributes to a regular entrypoint without a | ||
`partial` modifier is effectively editing it. The same argument then applies to | ||
simple programs. | ||
|
||
If we decide *not* to support source generation scenarios, then we could limit | ||
the syntactic location to be required to be in the top level syntax tree itself. | ||
|
||
An alternative solution would be to have the simple program entry point assigned | ||
a well-know speakable identifier, and make it `partial` by default. This would | ||
allow a generator to create the matching partial definition that includes the | ||
attribute. | ||
|
||
### Naming | ||
|
||
This proposal is using `main` as straw man syntax for the real value. We should | ||
decide exactly what to call it. Suggestions include `main` or `entrypoint`. | ||
|
||
### Attribute Target | ||
|
||
Should we introduce a corresponding `AttributeTargets.Main` that allows an | ||
attribute to specify that it only applies to main methods? Currently we don't, | ||
and users can apply any regular Method targeted attribute (or All) to the main | ||
method. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are not multiple entry points for programs with top level statements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There can be. Although its an error case, the compiler explicitly allows you to have multiple files with top level statements. We're saying here that we'll only apply the attributes to the first one (same as if you call getEntryPoint and there are multiple ones).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's an error case. The compiler explicitly does not allow it. Therefore, our handling of such an error case is an implementation detail, and doesn't belong in the specification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could simplify this to essentially
I agree we should avoid listing out how it works in cases like multiple files with top level statements. That is already an error scenario, basically an invalid program. Generally we don't spec out behaviors for scenarios like that.