Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion standard/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@

The attribute `System.Runtime.CompilerServices.CallerMemberNameAttribute` is allowed on optional parameters when there is a standard implicit conversion ([§10.4.2](conversions.md#1042-standard-implicit-conversions)) from `string` to the parameter’s type.

If a function invocation from a location within the body of a function member or within an attribute applied to the function member itself or its return type, parameters or type parameters in source code omits an optional parameter with the `CallerMemberNameAttribute`, then a string literal representing the name of that member is used as an argument to the invocation instead of the default parameter value.
If a function invocation from a location within the body of a function member or within an attribute applied to the function member itself or its return type, parameters or type parameters in source code omits an optional parameter with the `CallerMemberNameAttribute`, then a string literal representing the name of that member is used as an argument to the invocation instead of the default parameter value. (In the case of a function invocation from a top-level statement (§top-level-statements), the member name is that generated by the implementation.)

For invocations that occur within generic methods, only the method name itself is used, without the type parameter list.

Expand Down Expand Up @@ -958,7 +958,7 @@
> {
> if (!isNull)
> {
> throw new ArgumentException(argumentName, $"argument {argumentName} can't be null");

Check warning on line 961 in standard/attributes.md

View workflow job for this annotation

GitHub Actions / Markdown to Word Converter

standard/attributes.md#L961

MDC032::Line length 86 > maximum 81
> }
> }
>
Expand Down
183 changes: 180 additions & 3 deletions standard/basic-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@

## 7.1 Application startup

A program may be compiled either as a ***class library*** to be used as part of other applications, or as an ***application*** that may be started directly. The mechanism for determining this mode of compilation is implementation-defined and external to this specification.
### §app-startup-general General

A program may be compiled either as a ***class library*** to be used as part of other applications, or as an ***application*** that may be started directly. The mechanism for determining this mode of compilation is implementation-specific and external to this specification.

The entry point of an application may be specified in either of the following ways:

1. Explicitly, by declaring a method with appropriate characteristics (§named-entry-point).
1. Implicitly, by using top-level statements (§top-level-statements).

### §named-entry-point Using a named entry point

A program compiled as an application shall contain at least one method qualifying as an entry point by satisfying the following requirements:

Expand Down Expand Up @@ -47,6 +56,166 @@ If the effective entry point’s return type is `int`, the return value from the

Other than the situations listed above, entry point methods behave like those that are not entry points in every respect. In particular, if the entry point is invoked at any other point during the application’s lifetime, such as by regular method invocation, there is no special handling of the method: if there is a parameter, it may have an initial value of `null`, or a non-`null` value referring to an array that contains null references. Likewise, the return value of the entry point has no special significance other than in the invocation from the execution environment.

### §top-level-statements Using top-level statements

Any one compilation unit ([§14.2](namespaces.md#142-compilation-units) in an application may contain one or more *statement_list*s—collectively called ***top-level statements***—in which case, the meaning is as if those *statement_list*s were combined in the block body of a static method within a partial class called `Program` in the global namespace, as follows:

```csharp
partial class Program
{
static «AsyncAndReturnType» «Main»(string[] args)
{
// top-level statements
}
}
```

The class name `Program` shall be referenceable by name from within the application. However, the method name `«Main»` is used here for illustrative purposes only. The actual name generated by the implementation is unspecified, and cannot be referenced by name from within the application. It is, however, available via the attribute `System.Runtime.CompilerServices.CallerMemberName` ([§23.5.6.4](attributes.md#23564-the-callermembername-attribute)).

The method is designated as the entry point of the program. Explicitly declared methods (including static ones called `Main`) that by convention could be considered as entry point candidates (§named-entry-point) shall be ignored for that purpose.

The entry-point method has one parameter, `string[] args`. This parameter is in scope within the top-level statements and not otherwise. Regular name conflict/shadowing rules apply.

Async operations are allowed in top-level statements to the degree they are allowed in statements within a named async entry-point method. However, they are not required.

The tokens that are generated in place of `«AsyncAndReturnType»` are determined based on operations used by the top-level statements, as follows:

| **Top-level code contains** | **Generated entry-point signature**
| ----------------------- | -------------------------------
| No `await` or `return` with value | `private static void «Main»(string[] args)`
| `return` with value only | `private static int «Main»(string[] args)`
| `await` only | `private static async Task «Main»(string[] args)`
| `await` and `return` with value | `private static async Task<int> «Main»(string[] args)`

This is illustrated by the following sets of top-level statements:

**Set 1**

<!-- Example: {template:"standalone-console-without-using", name:"TopLevelStatements2A", expectedOutput:["cmd-line args length = 0"]} -->
```csharp
using System;
Console.WriteLine($"cmd-line args length = {args.Length}");
C c = new C();
public class C {}
```

whose implementation-generated code is

<!-- Example: {template:"standalone-console-without-using", name:"TopLevelStatements2B", expectedOutput:["cmd-line args length = 0"]} -->
```csharp
using System;
partial class Program
{
static void «Main»(string[] args)
{
Console.WriteLine($"cmd-line args length = {args.Length}");
C c = new C();
}
}
public class C {}
```

*Note*: As required by the grammar for *compilation_unit* ([§14.2](namespaces.md#142-compilation-units)), top-level statements must come after *using_directive*s and before *namespace_member_declaration*s, such as types. *end note*

**Set 2**

<!-- Example: {template:"standalone-console-without-using", name:"TopLevelStatements3A", expectedOutput:["Hi!"]} -->
```csharp
System.Console.WriteLine("Hi!");
return 2;
```

whose implementation-generated code is

<!-- Example: {template:"standalone-console-without-using", name:"TopLevelStatements3B", expectedOutput:["Hi!"]} -->
```csharp
partial class Program
{
static int «Main»(string[] args)
{
System.Console.WriteLine("Hi!");
return 2;
}
}
```

**Set 3**

<!-- Example: {template:"standalone-console-without-using", name:"TopLevelStatements4A", expectedOutput:["Hi!"]} -->
```csharp
using System;
using System.Threading.Tasks;
await Task.Delay(1000);
Console.WriteLine("Hi!");
```

whose implementation-generated code is

<!-- Example: {template:"standalone-console-without-using", name:"TopLevelStatements4B", expectedOutput:["Hi!"]} -->
```csharp
using System;
using System.Threading.Tasks;
partial class Program
{
static async Task «Main»(string[] args)
{
await Task.Delay(1000);
Console.WriteLine("Hi!");
}
}
```

**Set 4**

<!-- Example: {template:"standalone-console-without-using", name:"TopLevelStatements5A", expectedOutput:["Hi!"]} -->
```csharp
using System;
using System.Threading.Tasks;
await Task.Delay(1000);
Console.WriteLine("Hi!");
return 0;
```

whose implementation-generated code is

<!-- Example: {template:"standalone-console-without-using", name:"TopLevelStatements5B", expectedOutput:["Hi!"]} -->
```csharp
using System;
using System.Threading.Tasks;
partial class Program
{
static async Task<int> «Main»(string[] args)
{
await Task.Delay(1000);
Console.WriteLine("Hi!");
return 0;
}
}
```

The implementation-generated class `Program` can be augmented by user-written code that declares one or more partial classes called `Program`.

> *Example*: Consider the following:
>
> <!-- Example: {template:"standalone-console-without-using", name:"TopLevelStatements6"} -->
> ```csharp
> M1(); // call top-level static local function M1
> M2(); // call top-level non-static local function M2
>
> static void M1() { } // static local function
> void M2() { } // non-static local function
>
> Program.M1(); // call static method M1
> new Program().M2(); // call non-static method M2
> partial class Program
> {
> static void M1() { } // static method
> void M2() { } // non-static method
> }
> ```
>
> As the first two declarations for `M1` and `M2` get wrapped inside the generated entry-point method, they are local functions. However, the second two declarations are methods, as they are declared inside a class rather than a method. *end example*

## 7.2 Application termination

***Application termination*** returns control to the execution environment.
Expand Down Expand Up @@ -602,8 +771,8 @@ The ***scope*** of a name is the region of program text within which it is possi

- The scope of a namespace member declared by a *namespace_member_declaration* ([§14.6](namespaces.md#146-namespace-member-declarations)) with no enclosing *namespace_declaration* is the entire program text.
- The scope of a namespace member declared by a *namespace_member_declaration* within a *namespace_declaration* whose fully qualified name is `N`, is the *namespace_body* of every *namespace_declaration* whose fully qualified name is `N` or starts with `N`, followed by a period.
- The scope of a name defined by an *extern_alias_directive* ([§14.4](namespaces.md#144-extern-alias-directives)) extends over the *using_directive*s, *global_attributes* and *namespace_member_declaration*s of its immediately containing *compilation_unit* or *namespace_body*. An *extern_alias_directive* does not contribute any new members to the underlying declaration space. In other words, an *extern_alias_directive* is not transitive, but, rather, affects only the *compilation_unit* or *namespace_body* in which it occurs.
- The scope of a name defined or imported by a *using_directive* ([§14.5](namespaces.md#145-using-directives)) extends over the *global_attributes* and *namespace_member_declaration*s of the *compilation_unit* or *namespace_body* in which the *using_directive* occurs. A *using_directive* may make zero or more namespace or type names available within a particular *compilation_unit* or *namespace_body*, but does not contribute any new members to the underlying declaration space. In other words, a *using_directive* is not transitive but rather affects only the *compilation_unit* or *namespace_body* in which it occurs.
- The scope of a name defined by an *extern_alias_directive* ([§14.4](namespaces.md#144-extern-alias-directives)) extends over the *using_directive*s, *global_attributes*, *statement_list*s, and *namespace_member_declaration*s of its immediately containing *compilation_unit* or *namespace_body*. An *extern_alias_directive* does not contribute any new members to the underlying declaration space. In other words, an *extern_alias_directive* is not transitive, but, rather, affects only the *compilation_unit* or *namespace_body* in which it occurs.
- The scope of a name defined or imported by a *using_directive* ([§14.5](namespaces.md#145-using-directives)) extends over the *global_attributes*, *statement_list*s, and *namespace_member_declaration*s of the *compilation_unit* or *namespace_body* in which the *using_directive* occurs. A *using_directive* may make zero or more namespace or type names available within a particular *compilation_unit* or *namespace_body*, but does not contribute any new members to the underlying declaration space. In other words, a *using_directive* is not transitive but rather affects only the *compilation_unit* or *namespace_body* in which it occurs.
Comment on lines +774 to +775
Copy link
Contributor

Choose a reason for hiding this comment

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

I just made these two edits (after working on the V10 feature "File-Scoped Namespaces," which further changes these two bullet items). Now that top-level statements (statement_lists) are permitted immediately before namespace_member_declarations, we need to make sure those statements are in the scope of these two directives.

- The scope of a type parameter declared by a *type_parameter_list* on a *class_declaration* ([§15.2](classes.md#152-class-declarations)) is the *class_base*, *type_parameter_constraints_clause*s, and *class_body* of that *class_declaration*.
> *Note*: Unlike members of a class, this scope does not extend to derived classes. *end note*
- The scope of a type parameter declared by a *type_parameter_list* on a *struct_declaration* ([§16.2](structs.md#162-struct-declarations)) is the *struct_interfaces*, *type_parameter_constraints_clause*s, and *struct_body* of that *struct_declaration*.
Expand Down Expand Up @@ -708,6 +877,14 @@ Within the scope of a local variable, it is a compile-time error to refer to the
>
> *end note*

As described in §top-level-statements, top-level source tokens are enclosed by the generated entry-point method.

For the purpose of simple-name evaluation, once the global namespace is reached, first, an attempt is made to evaluate the name within the generated entry point method and only if this attempt fails is the evaluation within the global namespace declaration performed.

This could lead to name shadowing of namespaces and types declared within the global namespace as well as to shadowing of imported names.

If the simple name evaluation occurs outside of the top-level statements and the evaluation yields a top-level local variable or function, a compile-time error results.

### 7.7.2 Name hiding

#### 7.7.2.1 General
Expand Down
4 changes: 2 additions & 2 deletions standard/namespaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ Using directives ([§14.5](namespaces.md#145-using-directives)) are provided to

## 14.2 Compilation units

A *compilation_unit* consists of zero or more *extern_alias_directive*s followed by zero or more *using_directive*s followed by zero or one *global_attributes* followed by zero or more *namespace_member_declaration*s. The *compilation_unit* defines the overall structure of the input.
A *compilation_unit* consists of zero or more *extern_alias_directive*s followed by zero or more *using_directive*s followed by zero or one *global_attributes* followed by zero or more *statement_list*s followed by zero or more *namespace_member_declaration*s. The *compilation_unit* defines the overall structure of the input.

```ANTLR
compilation_unit
: extern_alias_directive* using_directive* global_attributes?
namespace_member_declaration*
statement_list* namespace_member_declaration*
;
```

Expand Down
1 change: 1 addition & 0 deletions standard/portability-issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ A conforming implementation is required to document its choice of behavior in ea

## B.4 Unspecified behavior

1. The name of the entry-point method generated to contain top-level statements (§top-level-statements).
1. The time at which the finalizer (if any) for an object is run, once that object has become eligible for finalization ([§7.9](basic-concepts.md#79-automatic-memory-management)).
1. The representation of `true` ([§8.3.9](types.md#839-the-bool-type)).
1. The value of the result when converting out-of-range values from `float` or `double` values to an integral type in an `unchecked` context ([§10.3.2](conversions.md#1032-explicit-numeric-conversions)).
Expand Down
Loading