diff --git a/standard/basic-concepts.md b/standard/basic-concepts.md index eecbb6ba7..0b3a880d4 100644 --- a/standard/basic-concepts.md +++ b/standard/basic-concepts.md @@ -773,7 +773,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 by an *extern_alias_directive* ([§14.4](namespaces.md#144-extern-alias-directives)) extends over the *global_using_directive*s, *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 *global_using_directive* extends over the *global_attributes* and *namespace_member_declaration*s of all the *compilation_unit*s in the program. - 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 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* @@ -1098,15 +1099,15 @@ where: > *Note*: Non-type members (constants, fields, methods, properties, indexers, operators, instance constructors, finalizers, and static constructors) and type members with a different number of type parameters are ignored when determining the meaning of the *namespace_or_type_name*. *end note* - Otherwise, for each namespace `N`, starting with the namespace in which the *namespace_or_type_name* occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located: - If `x` is zero and `I` is the name of a namespace in `N`, then: - - If the location where the *namespace_or_type_name* occurs is enclosed by a namespace declaration for `N` and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with a namespace or type, then the *namespace_or_type_name* is ambiguous and a compile-time error occurs. + - If the location where the *namespace_or_type_name* occurs is enclosed by a namespace declaration for `N` and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with a namespace or type, or any namespace declaration for `N` in the program contains a *global_using_alias_directive* that associates the name `I` with a namespace or type, then the *namespace_or_type_name* is ambiguous and a compile-time error occurs. - Otherwise, `R₀` refers to the namespace named `I` in `N`. - Otherwise, if `N` contains an accessible type having name `I` and `x` type parameters, then: - - If `x` is zero and the location where the *namespace_or_type_name* occurs is enclosed by a namespace declaration for `N` and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with a namespace or type, then the *namespace_or_type_name* is ambiguous and a compile-time error occurs. + - If `x` is zero and the location where the *namespace_or_type_name* occurs is enclosed by a namespace declaration for `N` and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with a namespace or type, or any namespace declaration for `N` in the program contains a *global_using_alias_directive* that associates the name `I` with a namespace or type, then the *namespace_or_type_name* is ambiguous and a compile-time error occurs. - Otherwise, `R₀` refers to the type constructed with the given type arguments. - Otherwise, if the location where the *namespace_or_type_name* occurs is enclosed by a namespace declaration for `N`: - - If `x` is zero and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with an imported namespace or type, then `R₀` refers to that namespace or type. - - Otherwise, if the namespaces imported by the *using_namespace_directive*s of the namespace declaration contain exactly one type having name `I` and `x` type parameters, then `R₀` refers to that type constructed with the given type arguments. - - Otherwise, if the namespaces imported by the *using_namespace_directive*s of the namespace declaration contain more than one type having name `I` and `x` type parameters, then the *namespace_or_type_name* is ambiguous and a compile-time error occurs. + - If `x` is zero and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with an imported namespace or type, or any namespace declaration for `N` in the program contains a *global_using_alias_directive* that associates the name `I` with an imported namespace or type, then `R₀` refers to that namespace or type. + - Otherwise, if the namespaces imported by the *using_namespace_directive*s of the namespace declaration and the namespaces and type declarations imported by the *global_using_namespace_directive*s and *global_using_static_directive*s of any namespace declaration for `N` in the program contain exactly one type having name `I` and `x` type parameters, then `R₀` refers to that type constructed with the given type arguments. + - Otherwise, if the namespaces imported by the *using_namespace_directive*s of the namespace declaration and the namespaces and type declarations imported by the *global_using_namespace_directive*s and *global_using_static_directive*s of any namespace declaration for `N` in the program contain more than one type having name `I` and `x` type parameters, then the *namespace_or_type_name* is ambiguous and a compile-time error occurs. - Otherwise, the *namespace_or_type_name* is undefined and a compile-time error occurs. If `R₀` has been resolved successfully the trailing part of the *namespace_or_type_name* is resolved. The trailing grammar fragment consists of `k ≥ 0` repetitions, with each repetition further resolving the referenced namespace or type. diff --git a/standard/expressions.md b/standard/expressions.md index d73b34946..968ea2f20 100644 --- a/standard/expressions.md +++ b/standard/expressions.md @@ -1593,15 +1593,15 @@ A *simple_name* is either of the form `I` or of the form `I`, - Otherwise, the result is the same as a member access ([§12.8.7](expressions.md#1287-member-access)) of the form `T.I` or `T.I`. - Otherwise, for each namespace `N`, starting with the namespace in which the *simple_name* occurs, continuing with each enclosing namespace (if any), and ending with the global namespace, the following steps are evaluated until an entity is located: - If `e` is zero and `I` is the name of a namespace in `N`, then: - - If the location where the *simple_name* occurs is enclosed by a namespace declaration for `N` and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with a namespace or type, then the *simple_name* is ambiguous and a compile-time error occurs. + - If the location where the *simple_name* occurs is enclosed by a namespace declaration for `N` and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with a namespace or type, or any namespace declaration for `N` in the program contains a *global_using_alias_directive* that associates the name `I` with a namespace or type, then the *simple_name* is ambiguous and a compile-time error occurs. - Otherwise, the *simple_name* refers to the namespace named `I` in `N`. - Otherwise, if `N` contains an accessible type having name `I` and `e` type parameters, then: - - If `e` is zero and the location where the *simple_name* occurs is enclosed by a namespace declaration for `N` and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with a namespace or type, then the *simple_name* is ambiguous and a compile-time error occurs. + - If `e` is zero and the location where the *simple_name* occurs is enclosed by a namespace declaration for `N` and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with a namespace or type, or any namespace declaration for `N` in the program contains a *global_using_alias_directive* that associates the name `I` with a namespace or type, then the *simple_name* is ambiguous and a compile-time error occurs. - Otherwise, the *namespace_or_type_name* refers to the type constructed with the given type arguments. - Otherwise, if the location where the *simple_name* occurs is enclosed by a namespace declaration for `N`: - - If `e` is zero and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with an imported namespace or type, then the *simple_name* refers to that namespace or type. - - Otherwise, if the namespaces imported by the *using_namespace_directive*s of the namespace declaration contain exactly one type having name `I` and `e` type parameters, then the *simple_name* refers to that type constructed with the given type arguments. - - Otherwise, if the namespaces imported by the *using_namespace_directive*s of the namespace declaration contain more than one type having name `I` and `e` type parameters, then the *simple_name* is ambiguous and a compile-time error occurs. + - If `e` is zero and the namespace declaration contains an *extern_alias_directive* or *using_alias_directive* that associates the name `I` with an imported namespace or type, or any namespace declaration for `N` in the program contains a *global_using_alias_directive* that associates the name `I` with an imported namespace or type, then the *simple_name* refers to that namespace or type. + - Otherwise, if the namespaces imported by the *using_namespace_directive*s of the namespace declaration and the namespaces and type declarations imported by the *global_using_namespace_directive*s and *global_using_static_directive*s of any namespace declaration for `N` in the program contain exactly one type having name `I` and `e` type parameters, then the *simple_name* refers to that type constructed with the given type arguments. + - Otherwise, if the namespaces imported by the *using_namespace_directive*s of the namespace declaration and the namespaces and type declarations imported by the *global_using_namespace_directive*s and *global_using_static_directive*s of any namespace declaration for `N` in the program contain more than one type having name `I` and `e` type parameters, then the *simple_name* is ambiguous and a compile-time error occurs. > *Note*: This entire step is exactly parallel to the corresponding step in the processing of a *namespace_or_type_name* ([§7.8](basic-concepts.md#78-namespace-and-type-names)). *end note* - Otherwise, if `e` is zero and `I` is the identifier `_`, the *simple_name* is a *simple discard*, which is a form of declaration expression ([§12.20](expressions.md#1220-declaration-expressions)). - Otherwise, the *simple_name* is undefined and a compile-time error occurs. @@ -2120,7 +2120,8 @@ The search for `C` proceeds as follows: - Starting with the closest enclosing namespace declaration, continuing with each enclosing namespace declaration, and ending with the containing compilation unit, successive attempts are made to find a candidate set of extension methods: - If the given namespace or compilation unit directly contains non-generic type declarations `Cᵢ` with eligible extension methods `Mₑ`, then the set of those extension methods is the candidate set. - - If namespaces imported by using namespace directives in the given namespace or compilation unit directly contain non-generic type declarations `Cᵢ` with eligible extension methods `Mₑ`, then the set of those extension methods is the candidate set. + - If types `Ci` imported by *using_static_declarations* and directly declared in namespaces imported by *using_namespace_directive*s in the given namespace or compilation unit **and, if containing compilation unit is reached, imported by *global_using_static_declarations* and directly declared in namespaces imported by *global_using_namespace_directive*s in the program** directly contain eligible extension methods `Mₑ`, then the set of those extension methods is the candidate set. +- `Mₑ`, then the set of those extension methods is the candidate set. - If no candidate set is found in any enclosing namespace declaration or compilation unit, a compile-time error occurs. - Otherwise, overload resolution is applied to the candidate set as described in [§12.6.4](expressions.md#1264-overload-resolution). If no single best method is found, a compile-time error occurs. - `C` is the type within which the best method is declared as an extension method. diff --git a/standard/namespaces.md b/standard/namespaces.md index d5145d5a7..1af780c1a 100644 --- a/standard/namespaces.md +++ b/standard/namespaces.md @@ -8,11 +8,11 @@ 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 *statement_list*s 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 *global_using_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? + : extern_alias_directive* global_using_directive* using_directive* global_attributes? statement_list* namespace_member_declaration* ; ``` @@ -126,7 +126,7 @@ extern_alias_directive ; ``` -The scope of an *extern_alias_directive* extends over the *using_directive*s, *global_attributes* and *namespace_member_declaration*s of its immediately containing *compilation_unit* or *namespace_body*. +The scope of an *extern_alias_directive* extends over *global_using_directive*s, the *using_directive*s, *global_attributes* and *namespace_member_declaration*s of its immediately containing *compilation_unit* or *namespace_body*. Within a compilation unit or namespace body that contains an *extern_alias_directive*, the identifier introduced by the *extern_alias_directive* can be used to reference the aliased namespace. It is a compile-time error for the *identifier* to be the word `global`. @@ -155,6 +155,86 @@ An error occurs if a program declares an extern alias for which no external defi > The program declares the existence of the extern aliases `X` and `Y`, but the actual definitions of the aliases are external to the program. The identically named `N.B` classes can now be referenced as `X.N.B` and `Y.N.B`, or, using the namespace alias qualifier, `X::N.B` and `Y::N.B`. > *end example* +### §global-using-directives-general General + +A ***global using directive*** is a using directive ([§14.5](namespaces.md#145-using-directives)) at the top level of a compilation unit. + +```ANTLR +global_using_directive + : global_using_alias_directive + | global_using_namespace_directive + | global_using_static_directive + ; +``` + +> *Note*: The scope of a *global_using_directive* extends over the *namespace_member_declaration*s of all compilation units within the program. The scope of a *global_using_directive* specifically does not include other *global_using_directive*s. Thus, peer *global_using_directive*s or those from a different compilation unit do not affect each other, and the order in which they are written is insignificant. The scope of a *global_using_directive* specifically does not include *using_directive*s immediately contained in any compilation unit of the program. +> +> The effect of adding a *global_using_directive* to a program can be thought of as the effect of adding a similar *using_directive* that resolves to the same target namespace or type to every compilation unit of the program. However, the target of a *global_using_directive* is resolved in the context of the compilation unit that contains it. *end note* + +### §global-using-alias-directives Global using alias directives + +A *global_using_alias_directive* introduces an identifier that serves as an alias for a namespace or type within the program. + +```ANTLR +global_using_alias_directive + : 'global' using_alias_directive + ; +``` + +Within member declarations in any compilation unit of a program that contains a *global_using_alias_directive*, the *identifier* introduced by the *global_using_alias_directive* can be used to reference the given namespace or type. + +The *identifier* of a *global_using_alias_directive* shall be unique within the declaration space of any compilation unit of a program that contains the *global_using_alias_directive*. + +Just like regular members, names introduced by *global_using_alias_directive*s are hidden by similarly named members in nested scopes. + +The order in which *global_using_alias_directive*s are written has no significance, and resolution of the *namespace_or_type_name* referenced by a *global_using_alias_directive* is not affected by the *global_using_alias_directive* itself or by other *global_using_directive*s or *using_directive*s in the program. In other words, the *namespace_or_type_name* of a *global_using_alias_directive* is resolved as if the immediately containing compilation unit had no *using_directive*s and the entire containing program had no *global_using_directive*s. A *global_using_alias_directive* may however be affected by *extern_alias_directive*s in the immediately containing compilation unit. + +A *global_using_alias_directive* can create an alias for any namespace or type. + +Accessing a namespace or type through an alias yields exactly the same result as accessing that namespace or type through its declared name. + +Using aliases can name a closed constructed type, but cannot name an unbound generic type declaration without supplying type arguments. + +### §global-using-namespace-directives Global using namespace directives + +A *global_using_namespace_directive* imports the types contained in a namespace into the program, enabling the identifier of each type to be used without qualification. + +```ANTLR +global_using_namespace_directive + : 'global' using_namespace_directive + ; +``` + +Within member declarations in a program that contains a *global_using_namespace_directive*, the types contained in the given namespace can be referenced directly. + +A *global_using_namespace_directive* imports the types contained in the given namespace, but specifically does not import nested namespaces. + +Unlike a *global_using_alias_directive*, a *global_using_namespace_directive* may import types whose identifiers are already defined within a compilation unit of the program. In effect, in a given compilation unit, names imported by any *global_using_namespace_directive* in the program are hidden by similarly named members in the compilation unit. + +When more than one namespace or type imported by *global_using_namespace_directive*s or *global_using_static_directive*s in the same program contain types by the same name, references to that name as a *type_name* are considered ambiguous. + +Furthermore, when more than one namespace or type imported by *global_using_namespace_directive*s or *global_using_static_directive*s in the same program contain types or members by the same name, references to that name as a *simple_name* are considered ambiguous. + +The *namespace_name* referenced by a *global_using_namespace_directive* is resolved in the same way as the *namespace_or_type_name* referenced by a *global_using_alias_directive*. Thus, *global_using_namespace_directive*s in the same program do not affect each other and can be written in any order. + +### §global-using-static-directives Global using static directives + +A *global_using_static_directive* imports the nested types and static members contained directly in a type declaration into the containing program, enabling the identifier of each member and type to be used without qualification. + +```ANTLR +global_using_static_directive + : 'global' using_static_directive + ; +``` + +Within member declarations in a program that contains a *global_using_static_directive*, the accessible nested types and static members (except extension methods) contained directly in the declaration of the given type can be referenced directly. + +A *global_using_static_directive* specifically does not import extension methods directly as static methods, but makes them available for extension method invocation. + +A *global_using_static_directive* only imports members and types declared directly in the given type, not members and types declared in base classes. + +Ambiguities between multiple *global_using_namespace_directive*s and *global_using_static_directives* are discussed in §global-using-namespace-directives. + ## 14.5 Using directives ### 14.5.1 General @@ -355,7 +435,7 @@ Just like regular members, names introduced by *alias_directives* are hidden by > > *end example* -The order in which *extern_alias_directive*s are written has no significance. Likewise, the order in which *using_alias_directive*s are written has no significance, but all *using_alias_directives* shall come after all *extern_alias_directive*s in the same compilation unit or namespace body. Resolution of the *namespace_or_type_name* referenced by a *using_alias_directive* is not affected by the *using_alias_directive* itself or by other *using_directive*s in the immediately containing compilation unit or namespace body, but may be affected by *extern_alias_directive*s in the immediately containing compilation unit or namespace body. In other words, the *namespace_or_type_name* of a *using_alias_directive* is resolved as if the immediately containing compilation unit or namespace body had no *using_directive*s but has the correct set of *extern_alias_directive*s. +The order in which *extern_alias_directive*s are written has no significance. Likewise, the order in which *using_alias_directive*s are written has no significance, but all *using_alias_directives* shall come after all *extern_alias_directive*s in the same compilation unit or namespace body. Resolution of the *namespace_or_type_name* referenced by a *using_alias_directive* is not affected by the *using_alias_directive* itself or by other *using_directive*s in the immediately containing compilation unit or namespace body, but may be affected by *extern_alias_directive*s in the immediately containing compilation unit or namespace body. And, if the *using_alias_directive* is immediately contained in a compilation unit, is not affected by the *global_using_directive*s in the program. In other words, the *namespace_or_type_name* of a *using_alias_directive* is resolved as if the immediately containing compilation unit or namespace body had no *using_directive*s and, if the *using_alias_directive* is immediately contained in a compilation unit, the program had no *global_using_directive*s** but has the correct set of *extern_alias_directive*s. > *Example*: In the following code > @@ -809,8 +889,8 @@ Using this notation, the meaning of a *qualified_alias_member* is determined as - Otherwise, if the global namespace contains a type named `I` that has `e` type parameters, then the *qualified_alias_member* refers to that type constructed with the given type arguments. - Otherwise, the *qualified_alias_member* is undefined and a compile-time error occurs. - Otherwise, starting with the namespace declaration ([§14.3](namespaces.md#143-namespace-declarations)) immediately containing the *qualified_alias_member* (if any), continuing with each enclosing namespace declaration (if any), and ending with the compilation unit containing the *qualified_alias_member*, the following steps are evaluated until an entity is located: - - If the namespace declaration or compilation unit contains a *using_alias_directive* that associates N with a type, then the *qualified_alias_member* is undefined and a compile-time error occurs. - - Otherwise, if the namespace declaration or compilation unit contains an *extern_alias_directive* or *using_alias_directive* that associates `N` with a namespace, then: + - If the namespace declaration or compilation unit contains a *using_alias_directive* that associates N with a type, or when a compilation unit is reached, the program contains a *global_using_alias_directive* that associates `N` with a type, then the *qualified_alias_member* is undefined and a compile-time error occurs. + - Otherwise, if the namespace declaration or compilation unit contains an *extern_alias_directive* or *using_alias_directive* that associates `N` with a namespace, or when a compilation unit is reached, the program contains a *global_using_alias_directive* that associates `N` with a namespace, then: - If the namespace associated with `N` contains a namespace named `I` and `e` is zero, then the *qualified_alias_member* refers to that namespace. - Otherwise, if the namespace associated with `N` contains a non-generic type named `I` and `e` is zero, then the *qualified_alias_member* refers to that type. - Otherwise, if the namespace associated with `N` contains a type named `I` that has `e` type parameters, then the *qualified_alias_member* refers to that type constructed with the given type arguments.