Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4d189c9
support ref fields and scoped
RexJaeschke Mar 28, 2026
5090756
support ref fields and scoped
RexJaeschke Mar 28, 2026
bdcc6e7
support ref fields and scoped
RexJaeschke Mar 28, 2026
0b9feaf
support ref fields and scoped
RexJaeschke Mar 28, 2026
093cafc
support ref fields and scoped
RexJaeschke Mar 28, 2026
01dc04c
support ref fields and scoped
RexJaeschke Mar 28, 2026
9e94934
support ref fields and scoped
RexJaeschke Mar 28, 2026
3def8ae
support ref fields and scoped
RexJaeschke Mar 28, 2026
04dfbaa
support ref fields and scoped
RexJaeschke Mar 28, 2026
125ca30
fix md formatting
RexJaeschke Mar 28, 2026
3383e40
fix md formatting
RexJaeschke Mar 28, 2026
bf61293
fix md formatting
RexJaeschke Mar 28, 2026
46ea4e8
fix md formatting
RexJaeschke Mar 28, 2026
ffcd060
fix md formatting
RexJaeschke Mar 28, 2026
6d1d99c
fix md formatting
RexJaeschke Mar 28, 2026
88dcdd2
Introduces the 4th safe-context value
BillWagner Apr 3, 2026
4af8da1
Method invocation rules
BillWagner Apr 3, 2026
23268bf
MAMM, declaration expressions, object initializers
BillWagner Apr 3, 2026
f8cff0d
Grammar corrections.
BillWagner Apr 3, 2026
94398b3
unsafe context changes
BillWagner Apr 3, 2026
e70903a
Parameter scope variance + UnscopedRef xref
BillWagner Apr 3, 2026
f5d75c1
Editorial fixes
BillWagner Apr 3, 2026
8e1286e
Add examples for complicated examples
BillWagner Apr 6, 2026
3322142
Add additional examples.
BillWagner Apr 6, 2026
ccec8c9
fix md formatting
RexJaeschke Apr 7, 2026
1f58337
Review and update ref fields
BillWagner May 4, 2026
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
65 changes: 52 additions & 13 deletions standard/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ A number of attributes affect the language in some way. These attributes include
- `System.Runtime.CompilerServices.EnumeratorCancellationAttribute` ([§23.5.8](attributes.md#2358-the-enumeratorcancellation-attribute)), which is used to specify parameter for the cancellation token in an asynchronous iterator.
- `System.Runtime.CompilerServices.ModuleInitializer` ([§23.5.9](attributes.md#2359-the-moduleinitializer-attribute)), which is used to mark a method as a module initializer.
- `System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute` and `System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute`, which are used to declare a custom interpolated string expression handler ([§23.5.9.1](attributes.md#23591-custom-interpolated-string-expression-handlers)) and to call one of its constructors, respectively.
- System.Diagnostics.CodeAnalysis.UnscopedRefAttribute (§UnscopedRefAttribute), which allows an otherwise implicitly scoped ref to be treated as not being scoped.

The Nullable static analysis attributes ([§23.5.7](attributes.md#2357-code-analysis-attributes)) can improve the correctness of warnings generated for nullabilities and null states ([§8.9.5](types.md#895-nullabilities-and-null-states)).

Expand Down Expand Up @@ -966,19 +967,19 @@ The attributes in this subclause are used to provide additional information to s

The code-analysis attributes are declared in namespace `System.Diagnostics.CodeAnalysis`.

**Attribute** | **Meaning**
------------------ | ------------------
`AllowNull` ([§23.5.7.2](attributes.md#23572-the-allownull-attribute)) | A non-nullable argument may be null.
`DisallowNull` ([§23.5.7.3](attributes.md#23573-the-disallownull-attribute)) | A nullable argument should never be null.
`MaybeNull` ([§23.5.7.6](attributes.md#23576-the-maybenull-attribute)) | A non-nullable return value may be null.
`NotNull` ([§23.5.7.10](attributes.md#235710-the-notnull-attribute)) | A nullable return value will never be null.
`MaybeNullWhen` ([§23.5.7.7](attributes.md#23577-the-maybenullwhen-attribute)) | A non-nullable argument may be null when the method returns the specified `bool` value.
`NotNullWhen` ([§23.5.7.12](attributes.md#235712-the-notnullwhen-attribute)) | A nullable argument won't be null when the method returns the specified `bool` value.
`NotNullIfNotNull` ([§23.5.7.11](attributes.md#235711-the-notnullifnotnull-attribute)) | A return value isn't null if the argument for the specified parameter isn't null.
`MemberNotNull` ([§23.5.7.8](attributes.md#23578-the-membernotnull-attribute)) | The listed member won't be null when the method returns.
`MemberNotNullWhen` ([§23.5.7.9](attributes.md#23579-the-membernotnullwhen-attribute)) | The listed member won't be null when the method returns the specified `bool` value.
`DoesNotReturn` ([§23.5.7.4](attributes.md#23574-the-doesnotreturn-attribute)) | This method never returns.
`DoesNotReturnIf` ([§23.5.7.5](attributes.md#23575-the-doesnotreturnif-attribute)) | This method never returns if the associated `bool` parameter has the specified value.
| **Attribute** | **Meaning** |
| ------------------ | ------------------ |
| `AllowNull` ([§23.5.7.2](attributes.md#23572-the-allownull-attribute)) | A non-nullable argument may be null. |
| `DisallowNull` ([§23.5.7.3](attributes.md#23573-the-disallownull-attribute)) | A nullable argument should never be null. |
| `MaybeNull` ([§23.5.7.6](attributes.md#23576-the-maybenull-attribute)) | A non-nullable return value may be null. |
| `NotNull` ([§23.5.7.10](attributes.md#235710-the-notnull-attribute)) | A nullable return value will never be null. |
| `MaybeNullWhen` ([§23.5.7.7](attributes.md#23577-the-maybenullwhen-attribute)) | A non-nullable argument may be null when the method returns the specified `bool` value. |
| `NotNullWhen` ([§23.5.7.12](attributes.md#235712-the-notnullwhen-attribute)) | A nullable argument won't be null when the method returns the specified `bool` value. |
| `NotNullIfNotNull` ([§23.5.7.11](attributes.md#235711-the-notnullifnotnull-attribute)) | A return value isn't null if the argument for the specified parameter isn't null. |
| `MemberNotNull` ([§23.5.7.8](attributes.md#23578-the-membernotnull-attribute)) | The listed member won't be null when the method returns. |
| `MemberNotNullWhen` ([§23.5.7.9](attributes.md#23579-the-membernotnullwhen-attribute)) | The listed member won't be null when the method returns the specified `bool` value. |
| `DoesNotReturn` ([§23.5.7.4](attributes.md#23574-the-doesnotreturn-attribute)) | This method never returns. |
| `DoesNotReturnIf` ([§23.5.7.5](attributes.md#23575-the-doesnotreturnif-attribute)) | This method never returns if the associated `bool` parameter has the specified value. |

The following subclauses in [§23.5.7](attributes.md#2357-code-analysis-attributes) are conditionally normative.

Expand Down Expand Up @@ -1223,6 +1224,44 @@ Specifies that a nullable argument will not be `null` when the method returns th
>
> *end example*

### §UnscopedRefAttribute The UnscopedRef attribute

There are several cases in which a ref is treated as being implicitly scoped (§scoped-modifier); that is, the ref is not allowed to escape a method. For example:

- `this` for struct instance methods.
- ref parameters that refer to ref struct types.
- out parameters.

This attribute is used in those situations where the ref should be allowed to escape.

This attribute may can be applied to any `ref` and it changes the ref-safe-context to be one level wider than its default. For example:

| UnscopedRef applied to | Original ref-safe-context | New ref-safe-context |
| --- | --- | --- |
| instance member | function-member | return-only |
| `in` / `ref` parameter | return-only | caller-context |
| `out` parameter | function-member | return-only |

When applying this attribute to an instance method of a struct it modifies the implicit `this` parameter; that is, `this` acts as an unannotated `ref` of the same type.

An instance method or property annotated with `[UnscopedRef]` has the ref-safe-context of `this` set to the *caller-context*.

A member annotated with `[UnscopedRef]` may not implement an interface.

It is an error to use `[UnscopedRef]` on

- A member that is not declared on a `struct`.
- A `static` member, `init` member, or constructor on a `struct`.
- A parameter marked `scoped`.
- A parameter passed by value.
- A parameter passed by reference that is not implicitly scoped.

See §scoped-modifier for more information.

### §ScopedRefAttribute The ScopedRef attribute

The name `System.Runtime.CompilerServices.ScopedRefAttribute` is reserved for compiler use. The compiler emits this attribute on a parameter when the parameter's `scoped` annotation differs from its default state, in order to encode the `scoped` modifier (§scoped-modifier) in metadata. This attribute is not permitted in source.

### 23.5.8 The EnumeratorCancellation attribute

Specifies the parameter representing the `CancellationToken` for an asynchronous iterator ([§15.15](classes.md#1515-synchronous-and-asynchronous-iterators)). The argument for this parameter shall be combined with the argument passed to `IAsyncEnumerable<T>.GetAsyncEnumerator(CancellationToken)`. This combined token shall be polled by `IAsyncEnumerator<T>.MoveNextAsync()` ([§15.15.5.2](classes.md#151552-advance-the-enumerator)). The tokens shall be combined into a single token as if by `CancellationToken.CreateLinkedTokenSource` and its `Token` property. The combined token will be canceled if either of the two source tokens are canceled. The combined token is seen as the argument to the asynchronous iterator method ([§15.15](classes.md#1515-synchronous-and-asynchronous-iterators)) in the body of that method.
Expand Down
8 changes: 4 additions & 4 deletions standard/basic-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -718,11 +718,11 @@ The following accessibility constraints exist:

Methods, instance constructors, indexers, and operators are characterized by their ***signature***s:

- The signature of a method consists of the name of the method, the number of type parameters, and the type and parameter-passing mode of each of its parameters, considered in the order left to right. For these purposes, any type parameter of the method that occurs in the type of a parameter is identified not by its name, but by its ordinal position in the type parameter list of the method. The signature of a method specifically does not include the return type, parameter names, type parameter names, type parameter constraints, the `params` or `this` parameter modifiers, nor whether parameters are required or optional.
- The signature of a method consists of the name of the method, the number of type parameters, and the type and parameter-passing mode of each of its parameters, considered in the order left to right. For these purposes, any type parameter of the method that occurs in the type of a parameter is identified not by its name, but by its ordinal position in the type parameter list of the method. The signature of a method specifically does not include the return type, parameter names, type parameter names, type parameter constraints, the `params`, `scoped`, or `this` parameter modifiers, nor whether parameters are required or optional.
- The signature of an instance constructor consists of the type and parameter-passing mode of each of its parameters, considered in the order left to right. The signature of an instance constructor specifically does not include the `params` modifier that may be specified for the right-most parameter, nor whether parameters are required or optional.
- The signature of an indexer consists of the type of each of its parameters, considered in the order left to right. The signature of an indexer specifically does not include the element type, nor does it include the `params` modifier that may be specified for the right-most parameter, nor whether parameters are required or optional.
- The signature of an operator consists of the name of the operator and the type of each of its parameters, considered in the order left to right. The signature of an operator specifically does not include the result type.
- The signature of a conversion operator consists of the source type and the target type. The implicit or explicit classification of a conversion operator is not part of the signature.
- The signature of an indexer consists of the type of each of its parameters, considered in the order left to right. The signature of an indexer specifically does not include the element type, or the `scoped` modifier, nor does it include the `params` modifier that may be specified for the right-most parameter, or the `scoped` modifier, nor whether parameters are required or optional.
- The signature of an operator consists of the name of the operator and the type of each of its parameters, considered in the order left to right. The signature of an operator specifically does not include the result type or the `scoped` modifier.
- The signature of a conversion operator consists of the source type and the target type. The implicit or explicit classification of a conversion operator is not part of the signature nor is the `scoped` modifier.
- Two signatures of the same member kind (method, instance constructor, indexer or operator) are considered to be the *same signatures* if they have the same name, number of type parameters, number of parameters, and parameter-passing modes, and an identity conversion exists between the types of their corresponding parameters ([§10.2.2](conversions.md#1022-identity-conversion)).

Signatures are the enabling mechanism for ***overloading*** of members in classes, structs, and interfaces:
Expand Down
23 changes: 18 additions & 5 deletions standard/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -1715,6 +1715,8 @@

A field declaration that declares multiple fields is equivalent to multiple declarations of single fields with the same attributes, modifiers, and type.

> *Note*: Inside a `ref struct`, a field may also be declared as a reference variable; see §Ref-Fields. *end note*

Check failure on line 1719 in standard/classes.md

View workflow job for this annotation

GitHub Actions / lint

Blank line inside blockquote

standard/classes.md:1719 MD028/no-blanks-blockquote Blank line inside blockquote https://github.com/DavidAnson/markdownlint/blob/v0.40.0/doc/md028.md
> *Example*:
>
> <!-- Example: {template:"standalone-lib-without-using", name:"Fields1", ignoredWarnings:["CS0649"]} -->
Expand Down Expand Up @@ -2270,8 +2272,9 @@

parameter_modifier
: parameter_mode_modifier
| 'this' parameter_mode_modifier?
| parameter_mode_modifier? 'this'
| 'this' 'scoped'? parameter_mode_modifier?
| 'scoped'? parameter_mode_modifier? 'this'
| 'scoped' parameter_mode_modifier?
;

parameter_mode_modifier
Expand All @@ -2287,7 +2290,11 @@

The parameter list consists of one or more comma-separated parameters of which only the last may be a *parameter_array*.

A *fixed_parameter* consists of an optional set of *attributes* ([§23](attributes.md#23-attributes)); an optional `in`, `out`, `ref`, or `this` modifier; a *type*; an *identifier*; and an optional *default_argument*. Each *fixed_parameter* declares a parameter of the given type with the given name. The `this` modifier designates the method as an extension method and is only allowed on the first parameter of a static method in a non-generic, non-nested static class. If the parameter is a `struct` type or a type parameter constrained to a `struct`, the `this` modifier may be combined with either the `ref` or `in` modifier, but not the `out` modifier. Extension methods are further described in [§15.6.10](classes.md#15610-extension-methods). A *fixed_parameter* with a *default_argument* is known as an ***optional parameter***, whereas a *fixed_parameter* without a *default_argument* is a ***required parameter***. A required parameter shall not appear after an optional parameter in a *parameter_list*.
A *fixed_parameter* consists of an optional set of *attributes* ([§23](attributes.md#23-attributes)); an optional `this` modifier; an optional `scoped` modifier; an optional `in`, `out`, `ref` modifier; a *type*; an *identifier*; and an optional *default_argument*. Each *fixed_parameter* declares a parameter of the given type with the given name. The `this` modifier designates the method as an extension method and is only allowed on the first parameter of a static method in a non-generic, non-nested static class. If the parameter is a `struct` type or a type parameter constrained to a `struct`, the `this` modifier may be combined with either the `ref` or `in` modifier, but not the `out` modifier. Extension methods are further described in [§15.6.10](classes.md#15610-extension-methods). A *fixed_parameter* with a *default_argument* is known as an ***optional parameter***, whereas a *fixed_parameter* without a *default_argument* is a ***required parameter***. A required parameter shall not appear after an optional parameter in a *parameter_list*.

An output parameter implicitly has the `scoped` modifier.

For a discussion of `scoped`, see §scoped-modifier.

A parameter with a `ref`, `out` or `this` modifier cannot have a *default_argument*. An input parameter may have a *default_argument*. The *expression* in a *default_argument* shall be one of the following:

Expand Down Expand Up @@ -2335,7 +2342,7 @@
- Reference parameters ([§15.6.2.3.3](classes.md#156233-reference-parameters)).
- Parameter arrays ([§15.6.2.4](classes.md#15624-parameter-arrays)).

> *Note*: As described in [§7.6](basic-concepts.md#76-signatures-and-overloading), the `in`, `out`, and `ref` modifiers are part of a method’s signature, but the `params` modifier is not. *end note*
> *Note*: As described in [§7.6](basic-concepts.md#76-signatures-and-overloading), the `in`, `out`, and `ref` modifiers are part of a method’s signature, but the `params` and `scoped` modifiers are not. *end note*

#### 15.6.2.2 Value parameters

Expand Down Expand Up @@ -2369,6 +2376,8 @@

> *Note*: The primary purpose of input parameters is for efficiency. When the type of a method parameter is a large struct (in terms of memory requirements), it is useful to be able to avoid copying the whole value of the argument when calling the method. Input parameters allow methods to refer to existing values in memory, while providing protection against unwanted changes to those values. *end note*

An input parameter may carry the `scoped` modifier (§scoped-modifier) or the `[UnscopedRef]` attribute (§UnscopedRefAttribute).

##### 15.6.2.3.3 Reference parameters

A parameter declared with a `ref` modifier is a ***reference parameter***. For definite-assignment rules, see [§9.2.6](variables.md#926-reference-parameters).
Expand Down Expand Up @@ -2432,14 +2441,18 @@
>
> *end example*

For a `struct` type, within an instance method, instance accessor ([§12.2.1](expressions.md#1221-general)), or instance constructor with a constructor initializer, the `this` keyword behaves exactly as a reference parameter of the struct type ([§12.8.14](expressions.md#12814-this-access)).
For a `struct` type, within an instance method, instance accessor ([§12.2.1](expressions.md#1221-general)), or instance constructor with a constructor initializer, the `this` keyword behaves exactly as a reference parameter of the struct type ([§12.8.14](expressions.md#12814-this-access)). The `this` parameter of a struct instance method is implicitly `scoped ref` (§scoped-modifier).

A reference parameter may carry the `scoped` modifier (§scoped-modifier) or the `[UnscopedRef]` attribute (§UnscopedRefAttribute).

##### 15.6.2.3.4 Output parameters

A parameter declared with an `out` modifier is an ***output parameter***. For definite-assignment rules, see [§9.2.7](variables.md#927-output-parameters).

A method declared as an optional partial method ([§15.6.9.2](classes.md#15692-optional-partial-methods)) shall not have output parameters.

An output parameter is implicitly `scoped` (§scoped-modifier); the `[UnscopedRef]` attribute (§UnscopedRefAttribute) may be applied to widen its ref-safe-context.

> *Note*: Output parameters are typically used in methods that produce multiple return values. *end note*
<!-- markdownlint-disable MD028 -->

Expand Down
Loading
Loading