Skip to content

Commit 9ae0fe6

Browse files
committed
Nullability: conversion behavior
1 parent 6de3cd5 commit 9ae0fe6

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

standard/types.md

+76
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,8 @@ A compiler is not required to perform any static analysis nor is it required to
859859
860860
**The remainder of this subclause is conditionally normative.**
861861
862+
#### 8.9.5.1 Flow analysis
863+
862864
A compiler that generates diagnostic warnings conforms to these rules.
863865
864866
Every expression has one of three ***null state***s:
@@ -1042,4 +1044,78 @@ A compiler may use any expression that dereferences a variable, property, or eve
10421044
>
10431045
> *end example*
10441046
1047+
#### 8.9.5.2 Type conversions
1048+
1049+
For the purpose of determining whether a conversion is *permitted*, a compiler must consider every nullable-annotated type to be equivalent to its unannotated version. The compiler may however issue warnings if the annotations of the types are not compatible.
1050+
1051+
(examples: `List<string>` to `IEnumerable<object?>`, or `List<string?>?` to `IEnumerable<object>`, ...)
1052+
1053+
A compiler may follow rules for interface variance ([§18.2.3.3](interfaces.md#18233-variance-conversion)), delegate variance ([§20.4](delegates.md#204-delegate-compatibility)), and array covariance ([§1.7.6](arrays.md#176-array-covariance)) in determining whether to issue a warning for type conversions.
1054+
(Do we need to list each type here? E.g. tuple types...)
1055+
1056+
> <!-- Example: {template:"code-in-class-lib", name:"NullVariance"} -->
1057+
> ```csharp
1058+
> #nullable enable
1059+
> public class C
1060+
> {
1061+
> public void M1(IEnumerable<string> p)
1062+
> {
1063+
> IEnumerable<string?> v1 = p; // No warning
1064+
> }
1065+
>
1066+
> public void M2(IEnumerable<string?> p)
1067+
> {
1068+
> IEnumerable<string> v1 = p; // Warning
1069+
> IEnumerable<string> v2 = p!; // No warning
1070+
> }
1071+
>
1072+
> public void M3(Action<string?> p)
1073+
> {
1074+
> Action<string> v1 = p; // No warning
1075+
> }
1076+
>
1077+
> public void M4(Action<string> p)
1078+
> {
1079+
> Action<string?> v1 = p; // Warning
1080+
> Action<string?> v2 = p!; // No warning
1081+
> }
1082+
>
1083+
> public void M5(string[] p)
1084+
> {
1085+
> string?[] v1 = p; // No warning
1086+
> }
1087+
>
1088+
> public void M6(string?[] p)
1089+
> {
1090+
> string[] v1 = p; // Warning
1091+
> string[] v2 = p!; // No warning
1092+
> }
1093+
> }
1094+
> ```
1095+
>
1096+
> *end example*
1097+
1098+
Types that are invariant likewise may produce a warning when the conversion differs only in the nullability of type arguments.
1099+
1100+
> <!-- Example: {template:"code-in-class-lib", name:"NullInvariance"} -->
1101+
> ```csharp
1102+
> #nullable enable
1103+
> public class C
1104+
> {
1105+
> public void M1(List<string> p)
1106+
> {
1107+
> List<string?> v1 = p; // Warning
1108+
> List<string?> v1 = p!; // No Warning
1109+
> }
1110+
>
1111+
> public void M2(List<string?> p)
1112+
> {
1113+
> List<string> v1 = p; // Warning
1114+
> List<string> v1 = p!; // No Warning
1115+
> }
1116+
> }
1117+
> ```
1118+
>
1119+
> *end example*
1120+
10451121
***End of conditionally normative text***

0 commit comments

Comments
 (0)