You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Specify generic constraints added to support nullable reference types in C# 8 (#1178)
* Incorporate some text from #700
Bring in the normative text from #700.
Some text is removed because of the decision on normative language in our September meeting.
* fix build issues
* Edit pass
* Respond to feedback.
* port grammar, part 1
* Update standard/types.md
Co-authored-by: Nigel-Ecma <[email protected]>
* fix merge / rebase mishap
* Edits based on meeting feedback.
* Apply suggestions from code review
Co-authored-by: Nigel-Ecma <[email protected]>
* Apply suggestions from code review
Co-authored-by: Nigel-Ecma <[email protected]>
* grammar fixes
* Apply suggestions from code review
Co-authored-by: Nigel-Ecma <[email protected]>
* one last minor fix
* Rework description based on last meeting
Rework the description of nullable annotations on generic type parameters and generic type arguments.
We decided that these annotations should be specified in terms of only generating warnings, but never changing the semantics of a program.
* Use `nullable_type_attribute` in all type grammar
We'd used `'?'` and `nullable_type_attribute` in different places for the `?` annotation. Define `nullable_type_attribute` at first use, and use that consistently.
* Apply suggestions from code review
Co-authored-by: Jon Skeet <[email protected]>
* small grammar fix
Offline comment from @Nigel-Ecma
* updates from 10/30 meeting
This covers part 1, the comments in the files tab
* address comments in converstation tab
This commit addresses the comments in the conversation tab from the 10/30 meeting.
* additional feedback
This commit incorporates the comments on the conversation tab.
* Apply suggestions from code review
Co-authored-by: Nigel-Ecma <[email protected]>
* Replace nullable_type_attribute
with nullable_type_annotation
* typos
---------
Co-authored-by: Nigel-Ecma <[email protected]>
Co-authored-by: Jon Skeet <[email protected]>
@@ -434,12 +433,66 @@ Each *type_parameter_constraints_clause* consists of the token `where`, followed
434
433
435
434
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()`.
436
435
437
-
A primary constraint can be a class type, the ***reference type constraint***`class`, the ***value type constraint***`struct`, or the ***unmanaged type constraint***`unmanaged`.
436
+
A primary constraint can be a class type, the ***reference type constraint***`class`, the ***value type constraint***`struct`, the ***not null constraint***`notnull`or the ***unmanaged type constraint***`unmanaged`. The class type and the reference type constraint can include the *nullable_type_annotation*.
438
437
439
-
A secondary constraint can be a *type_parameter* or *interface_type*.
438
+
A secondary constraint can be an *interface_type* or *type_parameter*, optionally followed by a *nullable_type_annotation*. The presence of the nullable_type_annotatione* indicates that the type argument is allowed to be the nullable reference type that corresponds to a non-nullable reference type that satisfies the constraint.
440
439
441
440
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.
442
441
442
+
The class type, reference type constraint, and secondary constraints can include the nullable type annotation. The presence or absence of this annotation on the type parameter indicates the nullability expectations for the type argument:
443
+
444
+
- If the constraint does not include the nullable type annotation, the type argument is expected to be a non-nullable reference type. A compiler may issue a warning if the type argument is a nullable reference type.
445
+
- If the constraint includes the nullable type annotation, the constraint is satisfied by both a non-nullable reference type and a nullable reference type.
446
+
447
+
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.
448
+
449
+
> *Note*: To specify that a type argument is a nullable reference type, don't add the nullable type annotation as a constraint (use `T : class` or `T : BaseClass`), but use `T?` throughout the generic declaration to indicate the corresponding nullable reference type for the type argument. *end note*
450
+
451
+
<!-- Remove in C# 9, when this is allowed -->
452
+
The nullable type annotation, `?`, can't be used on an unconstrained type argument.
453
+
454
+
For a type parameter `T` when the type argument is a nullable reference type `C?`, instances of `T?` are interpreted as `C?`, not `C??`.
455
+
456
+
> *Example*: The following examples show how the nullability of a type argument impacts the nullability of a declaration of its type parameter:
>Whenthetypeargumentisanon-nullabletype, the `?` typeannotationindicatesthattheparameteristhecorrespondingnullabletype. Whenthetypeargumentisalreadyanullablereferencetype, theparameteristhatsamenullabletype.
491
+
>
492
+
> *endexample*
493
+
494
+
The ***notnull*** constraintspecifiesthatatypeargumentusedforthetypeparametershouldbeanon-nullablevaluetypeoranon-nullablereferencetype. Atypeargumentthatisn'tanon-nullablevaluetypeoranon-nullablereferencetypeisallowed, butthecompilermayproduceadiagnosticwarning.
495
+
443
496
Thevaluetypeconstraintspecifiesthatatypeargumentusedfor 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)) doesnotsatisfythevaluetypeconstraint. Atypeparameterhavingthevaluetypeconstraintshallnotalsohavethe*constructor_constraint*, althoughitmaybeusedasatypeargumentfor another type parameter with a *constructor_constraint*.
444
497
445
498
> *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*
@@ -604,7 +657,7 @@ The ***effective interface set*** of a type parameter `T` is defined as follows
The modifier `partial` is used when defining a class, struct, or interface type in multiple parts. The `partial` modifier is a contextual keyword ([§6.4.4](lexical-structure.md#644-keywords)) and only has special meaning immediately before one of the keywords `class`, `struct`, or `interface`.
673
726
674
-
Each part of a ***partial type*** declaration shall include a `partial` modifier and shall be declared in the same namespace or containing type as the other parts. The `partial` modifier indicates that additional parts of the type declaration might exist elsewhere, but the existence of such additional parts is not a requirement; it is valid for the only declaration of a type to include the `partial` modifier.
727
+
Each part of a ***partial type*** declaration shall include a `partial` modifier and shall be declared in the same namespace or containing type as the other parts. The `partial` modifier indicates that additional parts of the type declaration might exist elsewhere, but the existence of such additional parts is not a requirement; it is valid for the only declaration of a type to include the `partial` modifier. It is valid for only one declaration of a partial type to include the base class or implemented interfaces. However, all declarations of a base class or implemented interfaces must match, including the nullability of any specified type arguments.
675
728
676
729
All parts of a partial type shall be compiled together such that the parts can be merged at compile-time. Partial types specifically do not allow already compiled types to be extended.
677
730
@@ -878,7 +931,7 @@ All members of a generic class can use type parameters from any enclosing class,
878
931
> classC<V>
879
932
> {
880
933
> publicVf1;
881
-
> publicC<V> f2=null;
934
+
> publicC<V> f2;
882
935
>
883
936
> publicC(Vx)
884
937
> {
@@ -1055,17 +1108,17 @@ Non-nested types can have `public` or `internal` declared accessibility and have
Copy file name to clipboardExpand all lines: standard/expressions.md
+3-1Lines changed: 3 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -2929,13 +2929,15 @@ When the operand of a *typeof_expression* is a sequence of tokens that satisfies
2929
2929
- Evaluate the resulting *type_name*, while ignoring all type parameter constraints.
2930
2930
- The *unbound_type_name* resolves to the unbound generic type associated with the resulting constructed type ([§8.4](types.md#84-constructed-types)).
2931
2931
2932
+
It is an error for the type name to be a nullable reference type.
2933
+
2932
2934
The result of the *typeof_expression* is the `System.Type` object for the resulting unbound generic type.
2933
2935
2934
2936
The third form of *typeof_expression* consists of a `typeof` keyword followed by a parenthesized `void` keyword. The result of an expression of this form is the `System.Type` object that represents the absence of a type. The type object returned by `typeof(void)` is distinct from the type object returned for any type.
2935
2937
2936
2938
> *Note*: This special `System.Type` object is useful in class libraries that allow reflection onto methods in the language, where those methods wish to have a way to represent the return type of any method, including `void` methods, with an instance of `System.Type`. *end note*
2937
2939
2938
-
The `typeof` operator can be used on a type parameter. The result is the `System.Type` object for the run-time type that was bound to the type parameter. The `typeof` operator can also be used on a constructed type or an unbound generic type ([§8.4.4](types.md#844-bound-and-unbound-types)). The `System.Type` object for an unbound generic type is not the same as the `System.Type` object of the instance type ([§15.3.2](classes.md#1532-the-instance-type)). The instance type is always a closed constructed type at run-time so its `System.Type` object depends on the run-time type arguments in use. The unbound generic type, on the other hand, has no type arguments, and yields the same `System.Type` object regardless of runtime type arguments.
2940
+
The `typeof` operator can be used on a type parameter. It is a compile time error if the type name is known to be a nullable reference type. The result is the `System.Type` object for the run-time type that was bound to the type parameter. If the run-time type is a nullable reference type, the result is the corresponding non-nullable reference type. The `typeof` operator can also be used on a constructed type or an unbound generic type ([§8.4.4](types.md#844-bound-and-unbound-types)). The `System.Type` object for an unbound generic type is not the same as the `System.Type` object of the instance type ([§15.3.2](classes.md#1532-the-instance-type)). The instance type is always a closed constructed type at run-time so its `System.Type` object depends on the run-time type arguments in use. The unbound generic type, on the other hand, has no type arguments, and yields the same `System.Type` object regardless of runtime type arguments.
*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).
@@ -720,7 +726,7 @@ An *unmanaged_type* is any type that isn’t a *reference_type*, a *type_paramet
720
726
721
727
### 8.9.1 General
722
728
723
-
A *nullable reference type* is denoted by appending a `?` to a valid non-nullable reference type name. There is no semantic difference between a non-nullable reference type and its corresponding nullable type. Both a nullable reference and a non-nullable reference can contain either a reference to an object or `null`. The presence or absence of the `?` annotation declares whether an expression is intended to permit null values or not. A compiler can provide diagnostics when an expression is not used according to that intent. The null state of an expression is defined in [§8.9.5](types.md#895-nullabilities-and-null-states). An identity conversion exists among a nullable reference type and its corresponding non-nullable reference type ([§10.2.2](conversions.md#1022-identity-conversion)).
729
+
A *nullable reference type* is denoted by appending a *nullable_type_annotation* (`?`) to a non-nullable reference type. There is no semantic difference between a non-nullable reference type and its corresponding nullable type, both can either be a reference to an object or `null`. The presence or absence of the *nullable_type_annotation*declares whether an expression is intended to permit null values or not. A compiler may provide diagnostics when an expression is not used according to that intent. The null state of an expression is defined in [§8.9.5](types.md#895-nullabilities-and-null-states). An identity conversion exists among a nullable reference type and its corresponding non-nullable reference type ([§10.2.2](conversions.md#1022-identity-conversion)).
724
730
725
731
There are two forms of nullability for reference types:
726
732
@@ -729,7 +735,7 @@ There are two forms of nullability for reference types:
729
735
730
736
> *Note:* The types `R` and `R?` are represented by the same underlying type, `R`. A variable of that underlying type can either contain a reference to an object or be the value `null`, which indicates “no reference.” *end note*
731
737
732
-
The syntactic distinction between a *nullable reference type* and its corresponding *non-nullable reference type* enables a compiler to generate diagnostics. A compiler shall allow the `?` annotation as defined in [§8.2.1](types.md#821-general). The diagnostics shall be limited to warnings. Neither the presence or absence of nullable annotations, nor the state of the nullable context can change the compile time or runtime behavior of a program except for changes in any diagnostic messages generated at compile time.
738
+
The syntactic distinction between a *nullable reference type* and its corresponding *non-nullable reference type* enables a compiler to generate diagnostics. A compiler must allow the *nullable_type_annotation*as defined in [§8.2.1](types.md#821-general). The diagnostics must be limited to warnings. Neither the presence or absence of nullable annotations, nor the state of the nullable context can change the compile time or runtime behavior of a program except for changes in any diagnostic messages generated at compile time.
733
739
734
740
### 8.9.2 Non-nullable reference types
735
741
@@ -762,6 +768,9 @@ When the nullable context is ***disabled***:
762
768
- No warning shall be generated when a variable of an unannotated reference type is initialized with, or assigned a value of, `null`.
763
769
- No warning shall be generated when a variable of a reference type that possibly has the null value.
764
770
- For any reference type `T`, the annotation `?` in `T?` generates a message and the type `T?` is the same as `T`.
771
+
- For any type parameter constraint `where T : C?`, the annotation `?` in `C?` generates a message and the type `C?` is the same as `C`.
772
+
- For any type parameter constraint `where T : U?`, the annotation `?` in `U?` generates a message and the type `U?` is the same as `U`.
773
+
- The generic constraint `class?` generates a warning message. The type parameter must be a reference type.
765
774
> *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*
766
775
- The null-forgiving operator `!` ([§12.8.9](expressions.md#1289-null-forgiving-expressions)) has no effect.
767
776
@@ -839,6 +848,7 @@ When the nullable context is ***enabled***:
839
848
-Foranyreferencetype `T`, theannotation `?` in `T?` makes `T?` anullabletype, whereastheunannotated `T` isnon-nullable.
-Thecompilercanissueawarningifthenullabilityofatypeparameterdoesn't match the nullability of its corresponding type argument.
842
852
843
853
### 8.9.5 Nullabilities and null states
844
854
@@ -861,6 +871,8 @@ The ***default null state*** of an expression is determined by its type, and the
861
871
- Not null when its declaration is in text where the annotations flag is disabled.
862
872
- The default null state of a non-nullable reference type is not null.
863
873
874
+
> *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)` isthenullvalue. Becausenullisnotinthedomainforthenon-nullabletype, thestateismaybedefault. *endnote*
875
+
864
876
Adiagnosticcanbeproduced 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.
0 commit comments