Skip to content
Open
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/arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ Elements of arrays created by *array_creation_expression*s are always initialize

Array elements are accessed using the *array access* variant of *element_access* expressions ([§12.8.12.2](expressions.md#128122-array-access)) of the form `A[I₁, I₂, ..., Iₓ]`, where `A` is an expression of an array type and each `Iₑ` is an expression of type `int`, `uint`, `long`, `ulong`, or can be implicitly converted to one or more of these types. The result of an array access is a variable reference ([§9.5](variables.md#95-variable-references)) to the array element selected by the indices.

Array elements of single-dimensional arrays can also be accessed using an array access expression where the sole index, `I₁`, is an expression of type `Index`, `Range`, or can be implicitly converted to one or both of these types. If `I₁` is of type `Index`, or has been implicitly converted to that type, then the result of the array access is a variable reference to the array element selected by the index value. If `I₁` is of type `Range`, or has been implicitly converted to that type, then the result of the element access is a new array formed from a shallow copy of the array elements with indices in the `Range`, maintaining the element order.
Array elements of single-dimensional arrays can also be accessed using an array access expression where the sole index, `I₁`, is an expression of type `Index`, `Range`, or can be implicitly converted to one or both of these types. If `I₁` is of type `Index`, or has been implicitly converted to that type, then the result of the array access is a variable reference to the array element selected by the index value. If `I₁` is of type `Range`, or has been implicitly converted to that type, then the result of the array access is a new array formed from a shallow copy of the array elements with indices in the `Range`, maintaining the element order.

The elements of an array can be enumerated using a `foreach` statement ([§13.9.5](statements.md#1395-the-foreach-statement)).

Expand Down
2 changes: 1 addition & 1 deletion standard/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -1074,7 +1074,7 @@ It is an error if the `System.Runtime.CompilerServices.EnumeratorCancellation` a

- The `EnumeratorCancellation` attribute is applied to a parameter of a type other than `CancellationToken`,
- or if the `EnumeratorCancellation` attribute is applied to a parameter on a method that is not an asynchronous iterator ([§15.15](classes.md#1515-synchronous-and-asynchronous-iterators)),
- or if the `EnumeratorCancellation` attribute is applied to a parameter on a method that returns an asynchronous enumerable interface ([§15.15.3](classes.md#15153-enumerable-interfaces)) rather than an asynchronous enumerator interface ([§15.15.2](classes.md#15152-enumerator-interfaces)).
- or if the `EnumeratorCancellation` attribute is applied to a parameter on a method that returns an asynchronous enumerator interface ([§15.15.2](classes.md#15152-enumerator-interfaces)) rather than an asynchronous enumerable interface ([§15.15.3](classes.md#15153-enumerable-interfaces)).

The iterator will not have access to the `CancellationToken` argument for `GetAsyncEnumerator` when no attributes have this parameter.

Expand Down
2 changes: 1 addition & 1 deletion standard/basic-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ Depending on the context in which a member declaration takes place, only certain
> *Note*: A type declared as a member of a class can have any of the permitted kinds of declared accessibility, whereas a type declared as a member of a namespace can have only `public` or `internal` declared accessibility. *end note*
- Struct members can have `public`, `internal`, or `private` declared accessibility and default to `private` declared accessibility because structs are implicitly sealed. Struct members introduced in a `struct` (that is, not inherited by that struct) cannot have `protected`, `protected internal`, or `private protected` declared accessibility.
> *Note*: A type declared as a member of a struct can have `public`, `internal`, or `private` declared accessibility, whereas a type declared as a member of a namespace can have only `public` or `internal` declared accessibility. *end note*
- Interface members implicitly have `public` declared accessibility. No access modifiers are allowed on interface member declarations.
- Interface members implicitly have `public` declared accessibility.
- Enumeration members implicitly have `public` declared accessibility. No access modifiers are allowed on enumeration member declarations.

### 7.5.3 Accessibility domains
Expand Down
2 changes: 1 addition & 1 deletion standard/conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ The following conversions are classified as explicit conversions:
- Explicit nullable conversions ([§10.3.4](conversions.md#1034-explicit-nullable-conversions))
- Explicit tuple conversions ([§10.3.6](conversions.md#1036-explicit-tuple-conversions))
- Explicit reference conversions ([§10.3.5](conversions.md#1035-explicit-reference-conversions))
- Explicit interface conversions
- Explicit interface conversions (§10.3.5)
- Unboxing conversions ([§10.3.7](conversions.md#1037-unboxing-conversions))
- Explicit type parameter conversions ([§10.3.8](conversions.md#1038-explicit-conversions-involving-type-parameters))
- User-defined explicit conversions ([§10.3.9](conversions.md#1039-user-defined-explicit-conversions))
Expand Down
2 changes: 1 addition & 1 deletion standard/expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5077,7 +5077,7 @@ The null coalescing operator is right-associative, meaning that operations are g

The type of the expression `a ?? b` depends on which implicit conversions are available on the operands. In order of preference, the type of `a ?? b` is `A₀`, `A`, or `B`, where `A` is the type of `a` (provided that `a` has a type), `B` is the type of `b`(provided that `b` has a type), and `A₀` is the underlying type of `A` if `A` is a nullable value type, or `A` otherwise. Specifically, `a ?? b` is processed as follows:

- If `A` exists and is an unmanaged type ([§8.8](types.md#88-unmanaged-types)) or known to be a non-nullable value type, a compile-time error occurs.
- If `A` exists and is a non-nullable value type or a pointer type in unsafe code, a compile-time error occurs.
- Otherwise, if `A` exists and `b` is a dynamic expression, the result type is `dynamic`. At run-time, `a` is first evaluated. If `a` is not `null`, `a` is converted to `dynamic`, and this becomes the result. Otherwise, `b` is evaluated, and this becomes the result.
- Otherwise, if `A` exists and is a nullable value type and an implicit conversion exists from `b` to `A₀`, the result type is `A₀`. At run-time, `a` is first evaluated. If `a` is not `null`, `a` is unwrapped to type `A₀`, and this becomes the result. Otherwise, `b` is evaluated and converted to type `A₀`, and this becomes the result.
- Otherwise, if `A` exists and an implicit conversion exists from `b` to `A`, the result type is `A`. At run-time, `a` is first evaluated. If `a` is not `null`, `a` becomes the result. Otherwise, `b` is evaluated and converted to type `A`, and this becomes the result.
Expand Down
12 changes: 6 additions & 6 deletions standard/interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ A type T is ***output-unsafe*** if one of the following holds:

- `T` is a contravariant type parameter
- `T` is an array type with an output-unsafe element type
- `T` is an interface or delegate type `Sᵢ,... Aₑ` constructed from a generic type `S<Xᵢ, ... Xₑ>` where for at least one `Aᵢ` one of the following holds:
- `T` is an interface or delegate type `S<Aᵢ,... Aₑ>` constructed from a generic type `S<Xᵢ, ... Xₑ>` where for at least one `Aᵢ` one of the following holds:
- `Xᵢ` is covariant or invariant and `Aᵢ` is output-unsafe.
- `Xᵢ` is contravariant or invariant and `Aᵢ` is input-unsafe.

Expand Down Expand Up @@ -440,7 +440,7 @@ Interface properties are declared using *property_declaration*s ([§15.7.1](clas
> *Note*: As an interface cannot contain instance fields, an interface property cannot be an instance auto-property, as that would require the declaration of implicit hidden instance fields. *end note*

- The type of an interface property shall be output-safe if there is a get accessor, and shall be input-safe if there is a set accessor.
- An interface method declaration that has a block body or expression body as a *method_body* is `virtual`; the `virtual` modifier is not required, but is allowed.
- An interface property or interface property accessor declaration that has a block body or expression body is `virtual`; the `virtual` modifier is not required, but is allowed.
- An instance *property_declaration* that has no implementation is `abstract`; the `abstract` modifier is not required, but is allowed. It is *never* considered to be an automatically implemented property ([§15.7.4](classes.md#1574-automatically-implemented-properties)).

### 19.4.5 Interface events
Expand All @@ -451,9 +451,9 @@ Interface events are declared using *event_declaration*s ([§15.8.1](classes.md#

- *event_modifier* shall not include `override`.
- A derived interface may implement an abstract interface event declared in a base interface ([§15.8.5](classes.md#1585-virtual-sealed-override-and-abstract-accessors)).
- It is a compile-time error for *variable_declarators* in an instance *event_declaration* to contain any *variable_initializer*s.
- An instance event with the `virtual` or `sealed` modifiers must declare accessors. It is *never* considered to be an automatically implemented field-like event ([§15.8.2](classes.md#1582-field-like-events)).
- An instance event with the `abstract` modifier must not declare accessors.
- It is a compile-time error for *variable_declarators* in an interface *event_declaration* to contain any *variable_initializer*s.
- An interface event with the `virtual` or `sealed` modifiers must declare accessors. It is *never* considered to be an automatically implemented field-like event ([§15.8.2](classes.md#1582-field-like-events)).
- An interface event with the `abstract` modifier must not declare accessors.
- The type of an interface event shall be input-safe.

### 19.4.6 Interface indexers
Expand Down Expand Up @@ -1463,7 +1463,7 @@ When a class implements an interface, it implicitly also implements all that int

### 19.6.8 Abstract classes and interfaces

Like a non-abstract class, an abstract class shall provide implementations for all abstract members of the interfaces that are listed in the base class list of the class or struct which do not have a reachable implementation; where an implementation can become unreachable due to reabstraction [§19.4.3](interfaces.md#1943-interface-methods). However, an abstract class is permitted to map interface methods onto abstract methods.
Like a non-abstract class, an abstract class shall provide implementations for all abstract members of the interfaces that are listed in the base class list of the class which do not have a reachable implementation; where an implementation can become unreachable due to reabstraction [§19.4.3](interfaces.md#1943-interface-methods). However, an abstract class is permitted to map interface methods onto abstract methods.

> *Example*:
>
Expand Down
2 changes: 1 addition & 1 deletion standard/patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ The runtime type of the value is tested against the *type* in the pattern using

Given a pattern input value ([§11.1](patterns.md#111-general)) *e*, if the *simple_designation* is *discard_designation*, it denotes a discard ([§9.2.9.2](variables.md#9292-discards)), and the value of *e* is not bound to anything. (Although a declared variable with the name `_` may be in scope at that point, that named variable is not seen in this context.) Otherwise, if the *simple_designation* is *single_variable_designation*, a local variable ([§9.2.9](variables.md#929-local-variables)) of the given type named by the given identifier is introduced. That local variable is assigned the value of the pattern input value when the pattern *matches* the value.

Certain combinations of static type of the pattern input value and the given type are considered incompatible and result in a compile-time error. A value of static type `E` is said to be ***pattern compatible*** with the type `T` if there exists an identity conversion, an implicit or explicit reference conversion, a boxing conversion, or an unboxing conversion from `E` to `T`, or if either `E` or `T` is an open type ([§8.4.3](types.md#843-open-and-closed-types)). A declaration pattern naming a type `T` is *applicable to* every type `E` for which `E` is pattern compatible with `T`.
Certain combinations of static type of the pattern input value and the given type are considered incompatible and result in a compile-time error. A value of static type `E` is said to be ***pattern compatible*** with the type `T` if there exists an identity conversion, an implicit or explicit reference conversion, a boxing conversion, an unboxing conversion, or an implicit or explicit nullable value type conversion from `E` to `T`, or if either `E` or `T` is an open type ([§8.4.3](types.md#843-open-and-closed-types)). A declaration pattern naming a type `T` is *applicable to* every type `E` for which `E` is pattern compatible with `T`.

> *Note*: The support for open types can be most useful when checking types that may be either struct or class types, and boxing is to be avoided. *end note*
<!-- markdownlint-disable MD028 -->
Expand Down
3 changes: 1 addition & 2 deletions standard/portability-issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,8 @@ A conforming implementation is required to document its choice of behavior in ea
1. The mechanism for determining whether a program is compiled as a class library or as an application. ([§7.1](basic-concepts.md#71-application-startup))
1. The policy or mechanisms used by an implementation for the creation and destruction of application domains. ([§7.1](basic-concepts.md#71-application-startup))
1. The exit code if the effective entry point method terminates due to an exception. ([§7.2](basic-concepts.md#72-application-termination))
1. Whether or not finalizers are run as part of application termination. ([§7.2](basic-concepts.md#72-application-termination))
1. Whether or not finalizers are run as part of application termination. ([§7.2](basic-concepts.md#72-application-termination), §7.9)
1. Whether APIs allow a finalizer to be run more than once. ([§7.9](basic-concepts.md#79-automatic-memory-management))
1. Whether or not finalizers are run as part of application termination. ([§7.9](basic-concepts.md#79-automatic-memory-management))
1. The API surface provided by `Expression<TDelegate>` beyond the requirement for a `Compile` method. ([§8.6](types.md#86-expression-tree-types))
1. The precise structure of the expression tree, as well as the exact process for creating it, when an anonymous function is converted to an expression-tree. ([§10.7.3](conversions.md#1073-evaluation-of-lambda-expression-conversions-to-expression-tree-types))
1. The reason a conversion to a compatible delegate type may fail at compile-time. ([§10.7.3](conversions.md#1073-evaluation-of-lambda-expression-conversions-to-expression-tree-types))
Expand Down
2 changes: 1 addition & 1 deletion standard/statements.md
Original file line number Diff line number Diff line change
Expand Up @@ -1937,7 +1937,7 @@ non_ref_local_variable_declaration

A ***resource type*** is either a class or non-ref struct that implements either or both of the `System.IDisposable` or `System.IAsyncDisposable` interfaces, which includes a single parameterless method named `Dispose` and/or `DisposeAsync`; or a ref struct that includes a method named `Dispose` having the same signature as that declared by `System.IDisposable`. Code that is using a resource can call `Dispose` or `DisposeAsync` to indicate that the resource is no longer needed.

If the form of *resource_acquisition* is *local_variable_declaration* then the type of the *local_variable_declaration* shall be either `dynamic` or a resource type. If the form of *resource_acquisition* is *expression* then this expression shall have a resource type. If `await` is present, the resource type shall implement `System.IAsyncDisposable`. A `ref struct` type cannot be the resource type for a `using` statement with the `await` modifier.
If the form of *resource_acquisition* is *non_ref_local_variable_declaration* then the type of the *non_ref_local_variable_declaration* shall be either `dynamic` or a resource type. If the form of *resource_acquisition* is *expression* then this expression shall have a resource type. If `await` is present, the resource type shall implement `System.IAsyncDisposable`. A `ref struct` type cannot be the resource type for a `using` statement with the `await` modifier.

Local variables declared in a *resource_acquisition* are read-only, and shall include an initializer. A compile-time error occurs if the embedded statement attempts to modify these local variables (via assignment or the `++` and `--` operators), take the address of them, or pass them as reference or output parameters.

Expand Down
14 changes: 8 additions & 6 deletions standard/structs.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,18 @@ It is a compile-time error if a ref struct type is used in any of the following

- As the element type of an array.
- As the declared type of a field of a class or a struct that does not have the `ref` modifier.
- Being boxed to `System.ValueType` or `System.Object`.
- As a type argument.
- As the type of a tuple element.
- An async method.
- An iterator.
- There is no conversion from a `ref struct` type to the type `object` or the type `System.ValueType`.
- In an async method.
- In an iterator.
- As the receiver type for a method group conversion to a delegate type.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The existing text makes it clear this is only for instance methods. I haven't looked up the precise definition for "receiver type for a method group conversion" - maybe that only terminology only works for instance methods only, but I wouldn't want a reader to think that Action<string> x = SomeRefStructType.StaticMethodAcceptingString; is invalid, if that makes sense.

- As a captured variable in a lambda expression or a local function.

In addition, the following restrictions apply to a `ref struct` type:

- A `ref struct` type shall not be boxed to `System.ValueType` or `System.Object`.
- A `ref struct` type shall not be declared to implement any interface.
- An instance method declared in `object` or in `System.ValueType` but not overridden in a `ref struct` type shall not be called with a receiver of that `ref struct` type.
- An instance method of a `ref struct` type shall not be captured by method group conversion to a delegate type.
- A ref struct shall not be captured by a lambda expression or a local function.

> *Note*: A `ref struct` shall not declare `async` instance methods nor use a `yield return` or `yield break` statement within an instance method, because the implicit `this` parameter cannot be used in those contexts. *end note*

Expand Down
2 changes: 1 addition & 1 deletion standard/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ The finite set of values of type `decimal` are of the form (–1)ᵛ × *c* × 1

A `decimal` is represented as an integer scaled by a power of ten. For `decimal`s with an absolute value less than `1.0m`, the value is exact to at least the 28th decimal place. For `decimal`s with an absolute value greater than or equal to `1.0m`, the value is exact to at least 28 digits. Contrary to the `float` and `double` data types, decimal fractional numbers such as `0.1` can be represented exactly in the decimal representation. In the `float` and `double` representations, such numbers often have non-terminating binary expansions, making those representations more prone to round-off errors.

If either operand of a binary operator is of `decimal` type then standard numeric promotions are applied, as detailed in [§12.4.7](expressions.md#1247-numeric-promotions), and the operation is performed with `double` precision.
If either operand of a binary operator is of `decimal` type then standard numeric promotions are applied, as detailed in [§12.4.7](expressions.md#1247-numeric-promotions), and the operation is performed with `decimal` precision.

The result of an operation on values of type `decimal` is that which would result from calculating an exact result (preserving scale, as defined for each operator) and then rounding to fit the representation. Results are rounded to the nearest representable value, and, when a result is equally close to two representable values, to the value that has an even number in the least significant digit position (this is known as “banker’s rounding”). That is, results are exact to at least the 28th decimal place. Note that rounding may produce a zero value from a non-zero value.

Expand Down
2 changes: 1 addition & 1 deletion standard/unsafe-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ A *pointer_type* is written as an *unmanaged_type* ([§8.8](types.md#88-unmanage

```ANTLR
pointer_type
: value_type ('*')+
: unmanaged_type ('*')+
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This change does introduce a left recursion in the grammar. In 8.8, an unmanaged_type is defined in the grammar as a value_type or a pointer_type. Then, in the prose the value_type is constrained to the builtin value types, enum types, and struct types whose members are only other unmanaged types in that list (paraphrasing here in the comment).

It's true that a pointer_type can only refer to an unmanaged_type, as written in the prose in line 120. But, to avoid the recursion, a bit fix might be to revert this change and expand the prose on line 120.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

cc @Nigel-Ecma for thoughts on the impact of introducing left recursion.

| 'void' ('*')+
;
```
Expand Down
Loading