Skip to content

Commit 83427e7

Browse files
authored
Merge pull request #1242 from dotnet/nullability/conversions
Nullability: conversion behavior
2 parents 58b1da7 + 09a691d commit 83427e7

File tree

1 file changed

+130
-7
lines changed

1 file changed

+130
-7
lines changed

standard/types.md

Lines changed: 130 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,8 @@ A compiler is not required to perform any static analysis nor is it required to
855855
856856
**The remainder of this subclause is conditionally normative.**
857857
858+
#### §flow-analysis Flow analysis
859+
858860
A compiler that generates diagnostic warnings conforms to these rules.
859861
860862
Every expression has one of three ***null state***s:
@@ -921,10 +923,10 @@ A compiler can update the null state of a variable as part of its analysis.
921923
> int length = p.Length; // Warning: p is maybe null
922924
>
923925
> string s = p; // No warning. p is not null
924-
>
926+
>
925927
> if (s != null)
926928
> {
927-
> int l2 = s.Length; // No warning. s is not null
929+
> int l2 = s.Length; // No warning. s is not null
928930
> }
929931
> int l3 = s.Length; // Warning. s is maybe null
930932
> }
@@ -994,13 +996,13 @@ A compiler can treat a property ([§15.7](classes.md#157-properties)) as either
994996
> {
995997
> get
996998
> {
997-
> string tmp = _field;
998-
> _field = null;
999-
> return tmp;
999+
> string tmp = _field;
1000+
> _field = null;
1001+
> return tmp;
10001002
> }
10011003
> set
10021004
> {
1003-
> _field = value;
1005+
> _field = value;
10041006
> }
10051007
> }
10061008
>
@@ -1027,7 +1029,7 @@ A compiler may use any expression that dereferences a variable, property, or eve
10271029
> public class C
10281030
> {
10291031
> private C? child;
1030-
>
1032+
>
10311033
> public void M()
10321034
> {
10331035
> _ = child.child.child; // Warning. Dereference possible null value
@@ -1038,4 +1040,125 @@ A compiler may use any expression that dereferences a variable, property, or eve
10381040
>
10391041
> *end example*
10401042
1043+
#### §type-conversions Type conversions
1044+
1045+
A compiler that generates diagnostic warnings conforms to these rules.
1046+
1047+
> *Note:* Differences in top-level or nested nullability annotations in types do not affect whether conversion between the types is permitted, since there is no semantic difference between a non-nullable reference type and its corresponding nullable type ([§8.9.1](types.md#891-general)). *end note*
1048+
1049+
A compiler may issue a warning when nullability annotations differ between two types, either top-level or nested, when the conversion is narrowing.
1050+
1051+
> *Example*: Types differing in top-level annotations
1052+
>
1053+
> <!-- Example: {template:"code-in-class-lib", name:"TopLevelNullabilityConversionWarnings", ignoredWarnings:["CS8600"]} -->
1054+
> ```csharp
1055+
> #nullable enable
1056+
> public class C
1057+
> {
1058+
> public void M1(string p)
1059+
> {
1060+
> _ = (string?)p; // No warning, widening
1061+
> }
1062+
>
1063+
> public void M2(string? p)
1064+
> {
1065+
> _ = (string)p; // Warning, narrowing
1066+
> _ = (string)p!; // No warning, suppressed
1067+
> }
1068+
> }
1069+
> ```
1070+
>
1071+
> *end example*
1072+
<!-- markdownlint-disable MD028 -->
1073+
1074+
<!-- markdownlint-enable MD028 -->
1075+
> *Example*: Types differing in nested nullability annotations
1076+
>
1077+
> <!-- Example: {template:"code-in-class-lib", name:"NestedNullabilityConversionWarnings", ignoredWarnings:["CS8619"]} -->
1078+
> ```csharp
1079+
> #nullable enable
1080+
> public class C
1081+
> {
1082+
> public void M1((string, string) p)
1083+
> {
1084+
> _ = ((string?, string?))p; // No warning, widening
1085+
> }
1086+
>
1087+
> public void M2((string?, string?) p)
1088+
> {
1089+
> _ = ((string, string))p; // Warning, narrowing
1090+
> _ = ((string, string))p!; // No warning, suppressed
1091+
> }
1092+
> }
1093+
> ```
1094+
>
1095+
> *end example*
1096+
1097+
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 covariance17.6) in determining whether to issue a warning for type conversions.
1098+
1099+
> <!-- Example: {template:"code-in-class-lib", name:"NullVariance", ignoredWarnings:["CS8619"]} -->
1100+
> ```csharp
1101+
> #nullable enable
1102+
> public class C
1103+
> {
1104+
> public void M1(IEnumerable<string> p)
1105+
> {
1106+
> IEnumerable<string?> v1 = p; // No warning
1107+
> }
1108+
>
1109+
> public void M2(IEnumerable<string?> p)
1110+
> {
1111+
> IEnumerable<string> v1 = p; // Warning
1112+
> IEnumerable<string> v2 = p!; // No warning
1113+
> }
1114+
>
1115+
> public void M3(Action<string?> p)
1116+
> {
1117+
> Action<string> v1 = p; // No warning
1118+
> }
1119+
>
1120+
> public void M4(Action<string> p)
1121+
> {
1122+
> Action<string?> v1 = p; // Warning
1123+
> Action<string?> v2 = p!; // No warning
1124+
> }
1125+
>
1126+
> public void M5(string[] p)
1127+
> {
1128+
> string?[] v1 = p; // No warning
1129+
> }
1130+
>
1131+
> public void M6(string?[] p)
1132+
> {
1133+
> string[] v1 = p; // Warning
1134+
> string[] v2 = p!; // No warning
1135+
> }
1136+
> }
1137+
> ```
1138+
>
1139+
> *end example*
1140+
1141+
A compiler may issue a warning when nullability differs in either direction in types which do not permit a variant conversion.
1142+
1143+
> <!-- Example: {template:"code-in-class-lib", name:"NullInvariance", ignoredWarnings:["CS8619"]} -->
1144+
> ```csharp
1145+
> #nullable enable
1146+
> public class C
1147+
> {
1148+
> public void M1(List<string> p)
1149+
> {
1150+
> List<string?> v1 = p; // Warning
1151+
> List<string?> v2 = p!; // No warning
1152+
> }
1153+
>
1154+
> public void M2(List<string?> p)
1155+
> {
1156+
> List<string> v1 = p; // Warning
1157+
> List<string> v2 = p!; // No warning
1158+
> }
1159+
> }
1160+
> ```
1161+
>
1162+
> *end example*
1163+
10411164
***End of conditionally normative text***

0 commit comments

Comments
 (0)