Skip to content
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

Specify generic constraints added to support nullable reference types in C# 8 #1178

Merged
merged 25 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0ba30fe
Incorporate some text from #700
BillWagner Sep 18, 2024
d53bf64
fix build issues
BillWagner Sep 18, 2024
1d3075f
Edit pass
BillWagner Sep 18, 2024
36c53e8
Respond to feedback.
BillWagner Sep 20, 2024
acab572
port grammar, part 1
BillWagner Sep 25, 2024
9536d97
Update standard/types.md
BillWagner Sep 25, 2024
fcb1f91
fix merge / rebase mishap
BillWagner Oct 9, 2024
ae11fa0
Edits based on meeting feedback.
BillWagner Oct 10, 2024
7313a53
Apply suggestions from code review
BillWagner Oct 10, 2024
18c0e14
Apply suggestions from code review
BillWagner Oct 10, 2024
ab57573
grammar fixes
BillWagner Oct 10, 2024
6cc9989
Apply suggestions from code review
BillWagner Oct 10, 2024
7fcfcb1
one last minor fix
BillWagner Oct 10, 2024
1e15bd3
Rework description based on last meeting
BillWagner Oct 22, 2024
021cffe
Use `nullable_type_attribute` in all type grammar
BillWagner Oct 23, 2024
adb40f4
Apply suggestions from code review
BillWagner Oct 28, 2024
c37ce7c
small grammar fix
BillWagner Oct 29, 2024
1b175c2
updates from 10/30 meeting
BillWagner Nov 12, 2024
1326634
address comments in converstation tab
BillWagner Nov 12, 2024
53057ff
additional feedback
BillWagner Nov 13, 2024
4df2c34
Merge branch 'draft-v8' into nullable-type-parameters
BillWagner Nov 13, 2024
c2b8b79
Apply suggestions from code review
BillWagner Nov 20, 2024
88f74e8
Replace nullable_type_attribute
BillWagner Nov 20, 2024
5574018
Merge remote-tracking branch 'upstream/draft-v8' into nullable-type-p…
BillWagner Nov 20, 2024
3afa99e
typos
BillWagner Nov 20, 2024
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
47 changes: 26 additions & 21 deletions standard/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,33 +396,32 @@ type_parameter_constraints_clauses
: type_parameter_constraints_clause
| type_parameter_constraints_clauses type_parameter_constraints_clause
;

type_parameter_constraints_clause
: 'where' type_parameter ':' type_parameter_constraints
;

type_parameter_constraints
: primary_constraint
| secondary_constraints
: primary_constraint (',' secondary_constraints)? (',' constructor_constraint)?
| secondary_constraints (',' constructor_constraint)?
| constructor_constraint
| primary_constraint ',' secondary_constraints
| primary_constraint ',' constructor_constraint
| secondary_constraints ',' constructor_constraint
| primary_constraint ',' secondary_constraints ',' constructor_constraint
;

primary_constraint
: class_type
| 'class'
: class_type nullable_type_attribute?
| 'class' nullable_type_attribute?
| 'struct'
| 'notnull'
| 'unmanaged'
;

secondary_constraint
: interface_type nullable_type_attribute?
| type_parameter nullable_type_attribute?
;

secondary_constraints
: interface_type
| type_parameter
| secondary_constraints ',' interface_type
| secondary_constraints ',' type_parameter
: secondary_constraint (',' secondary_constraint)*
;

constructor_constraint
Expand All @@ -434,12 +433,16 @@ Each *type_parameter_constraints_clause* consists of the token `where`, followed

The list of constraints given in a `where` clause can include any of the following components, in this order: a single primary constraint, one or more secondary constraints, and the constructor constraint, `new()`.

A primary constraint can be a class type, the ***reference type constraint*** `class`, the ***value type constraint*** `struct`, or the ***unmanaged type constraint*** `unmanaged`.
A primary constraint can be a class type, the ***reference type constraint*** `class`, the ***not null constraint*** `notnull`, the ***value type constraint*** `struct` or the ***unmanaged type constraint*** `unmanaged`.

A secondary constraint can be a *type_parameter* or *interface_type*.
A secondary constraint can be a *type_parameter* or *interface_type*, optionally followed by a *nullable_type_attribute*.

The reference type constraint specifies that a type argument used for the type parameter shall be a reference type. All class types, interface types, delegate types, array types, and type parameters known to be a reference type (as defined below) satisfy this constraint.

The class type, reference type constraint, and secondary constraints can include the nullable type attribute. The nullability of the type argument need not match the nullability of the type parameter. The compiler may issue a warning if the nullability of the type parameter doesn't match the nullability of the type argument.

The ***not null*** constraint specifies that a type argument used for the type parameter should be a non-nullable value type or a non-nullable reference type. A type argument that isn't a non-nullable value type or a non-nullable reference type is allowed, but the compiler may produce a diagnostic warning.

The value type constraint specifies that a type argument used for the type parameter shall be a non-nullable value type. All non-nullable struct types, enum types, and type parameters having the value type constraint satisfy this constraint. Note that although classified as a value type, a nullable value type ([§8.3.12](types.md#8312-nullable-value-types)) does not satisfy the value type constraint. A type parameter having the value type constraint shall not also have the *constructor_constraint*, although it may be used as a type argument for another type parameter with a *constructor_constraint*.

> *Note*: The `System.Nullable<T>` type specifies the non-nullable value type constraint for `T`. Thus, recursively constructed types of the forms `T??` and `Nullable<Nullable<T>>` are prohibited. *end note*
Expand Down Expand Up @@ -604,7 +607,9 @@ The ***effective interface set*** of a type parameter `T` is defined as follows
- If `T` has no *interface_type* constraints but has *type_parameter* constraints, its effective interface set is the union of the effective interface sets of its *type_parameter* constraints.
- If `T` has both *interface_type* constraints and *type_parameter* constraints, its effective interface set is the union of the set of dynamic erasures of its *interface_type* constraints and the effective interface sets of its *type_parameter* constraints.

A type parameter is *known to be a reference type* if it has the reference type constraint or its effective base class is not `object` or `System.ValueType`.
A type parameter is *known to be a non-nullable reference type* if it has the non-nullable reference type constraint or its effective base class is not `object` or `System.ValueType`.

A type parameter is *known to be a reference type* if it has the reference type constraint or it is known to be a non-nullable reference type.

Values of a constrained type parameter type can be used to access the instance members implied by the constraints.

Expand Down Expand Up @@ -878,7 +883,7 @@ All members of a generic class can use type parameters from any enclosing class,
> class C<V>
> {
> public V f1;
> public C<V> f2 = null;
> public C<V> f2;
>
> public C(V x)
> {
Expand Down Expand Up @@ -1055,17 +1060,17 @@ Non-nested types can have `public` or `internal` declared accessibility and have
> private class Node
> {
> public object Data;
> public Node Next;
> public Node? Next;
>
> public Node(object data, Node next)
> public Node(object data, Node? next)
> {
> this.Data = data;
> this.Next = next;
> }
> }
>
> private Node first = null;
> private Node last = null;
> private Node? first = null;
> private Node? last = null;
>
> // Public interface
> public void AddToFront(object o) {...}
Expand Down
23 changes: 17 additions & 6 deletions standard/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ The types of the C# language are divided into two main categories: ***reference

```ANTLR
type
: reference_type
| value_type
: value_type
| reference_type
| type_parameter
| pointer_type // unsafe code support
;
Expand Down Expand Up @@ -76,8 +76,13 @@ delegate_type
;

nullable_reference_type
: non_nullable_reference_type '?'
: non_nullable_reference_type nullable_type_attribute
;

nullable_type_attribute
: '?'
;

```

*pointer_type* is available only in unsafe code ([§23.3](unsafe-code.md#233-pointer-types)). *nullable_reference_type* is discussed further in [§8.9](types.md#89-reference-types-and-nullability).
Expand Down Expand Up @@ -206,7 +211,7 @@ enum_type
;

nullable_value_type
: non_nullable_value_type '?'
: non_nullable_value_type nullable_type_attribute
;
```

Expand Down Expand Up @@ -537,11 +542,11 @@ type_arguments
;

type_argument
: type
: type nullable_type_attribute?
;
```

Each type argument shall satisfy any constraints on the corresponding type parameter ([§15.2.5](classes.md#1525-type-parameter-constraints)).
Each type argument shall satisfy any constraints on the corresponding type parameter ([§15.2.5](classes.md#1525-type-parameter-constraints)). A reference type argument whose nullability doesn’t match the nullability of the type parameter satisfies the constraint; however a warning may be issued.

### 8.4.3 Open and closed types

Expand Down Expand Up @@ -762,6 +767,9 @@ When the nullable context is ***disabled***:
- No warning shall be generated when a variable of an unannotated reference type is initialized with, or assigned a value of, `null`.
- No warning shall be generated when a variable of a reference type that possibly has the null value.
- For any reference type `T`, the annotation `?` in `T?` generates a message and the type `T?` is the same as `T`.
- For any type parameter constraint `where T : C?`, the annotation `?` in `C?` generates a message and the type `C?` is the same as `C`.
- For any type parameter constraint `where T : U?`, the annotation `?` in `U?` generates a message and the type `U?` is the same as `U`.
- The generic constraint `class?` generates a warning message. The type parameter must be a reference type.
> *Note*: This message is characterized as “informational” rather than “warning,” so as not to confuse it with the state of the nullable warning setting, which is unrelated. *end note*
- The null-forgiving operator `!` ([§12.8.9](expressions.md#1289-null-forgiving-expressions)) has no effect.

Expand Down Expand Up @@ -839,6 +847,7 @@ When the nullable context is ***enabled***:
- For any reference type `T`, the annotation `?` in `T?` makes `T?` a nullable type, whereas the unannotated `T` is non-nullable.
- The compiler can use static flow analysis to determine the null state of any reference variable. When nullable warnings are enabled, a reference variable’s null state ([§8.9.5](types.md#895-nullabilities-and-null-states)) is either *not null*, *maybe null*, or *maybe default* and
- The null-forgiving operator `!` ([§12.8.9](expressions.md#1289-null-forgiving-expressions)) sets the null state of its operand to *not null*.
- The compiler can issue a warning if the nullability of a type parameter doesn't match the nullability of its corresponding type argument.

### 8.9.5 Nullabilities and null states

Expand All @@ -861,6 +870,8 @@ The ***default null state*** of an expression is determined by its type, and the
- Not null when its declaration is in text where the annotations flag is disabled.
- The default null state of a non-nullable reference type is not null.

> *Note:* The *maybe default* state is used with unconstrained type parameters when the type is a non-nullable type, such as `string` and the expression `default(T)` is the null value. Because null is not in the domain for the non-nullable type, the state is maybe default. *end note*

A diagnostic can be produced when a variable ([§9.2.1](variables.md#921-general)) of a non-nullable reference type is initialized or assigned to an expression that is maybe null when that variable is declared in text where the annotation flag is enabled.

The compiler can update the null state of a variable as part of its analysis.
Expand Down
Loading