Skip to content

Commit 0247b99

Browse files
committed
Add examples for complicated examples
Add three examples from the speclet for the most complicated rules for `scoped` ref.
1 parent dbb2869 commit 0247b99

1 file changed

Lines changed: 84 additions & 0 deletions

File tree

standard/structs.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,37 @@ For the purpose of these rules, a given argument `expr` passed to parameter `p`:
10261026
10271027
A property invocation (either `get` or `set`) is treated as a method invocation of the underlying method by the above rules.
10281028
1029+
> *Example*: The following illustrates how `scoped` affects the safe-context of a method's return value:
1030+
>
1031+
> <!-- Example: {template:"standalone-lib-without-using", name:"MethodInvocationSafeContext", expectedErrors:["CS8347"]} -->
1032+
> ```csharp
1033+
> ref struct RS
1034+
> {
1035+
> public ref int RefField;
1036+
> public RS(ref int i) { RefField = ref i; }
1037+
> }
1038+
>
1039+
> class C
1040+
> {
1041+
> static RS CreateAndCapture(ref int value)
1042+
> {
1043+
> // OK: ref-safe-context of `ref value` is caller-context,
1044+
> // safe-context contributed is caller-context.
1045+
> return new RS(ref value);
1046+
> }
1047+
>
1048+
> static RS CreateWithoutCapture(scoped ref int value)
1049+
> {
1050+
> // Error: `value` is scoped ref so it does not contribute
1051+
> // ref-safe-context. The constructor needs ref-safe-context
1052+
> // of caller-context but `value` only has function-member.
1053+
> return new RS(ref value);
1054+
> }
1055+
> }
1056+
> ```
1057+
>
1058+
> *end example*
1059+
10291060
#### §method-arguments-must-match Method arguments must match
10301061
10311062
For any method invocation `e.M(a1, a2, ... aN)`:
@@ -1048,6 +1079,29 @@ For any method invocation `e.M(a1, a2, ... aN)`:
10481079
10491080
The presence of `scoped` allows developers to reduce the friction this rule creates by marking parameters which are not returned as `scoped`. This removes their arguments from (1) in both cases above and provides greater flexibility to callers.
10501081
1082+
> *Example*: The following illustrates how the method-arguments-must-match rule prevents a value with a narrower safe-context from being stored into a `ref` argument with a wider safe-context:
1083+
>
1084+
> <!-- Example: {template:"standalone-lib-without-using", name:"MethodArgsMustMatch", expectedErrors:["CS8350"]} -->
1085+
> ```csharp
1086+
> ref struct R { }
1087+
>
1088+
> class C
1089+
> {
1090+
> static void F0(ref R a, scoped ref R b) { }
1091+
>
1092+
> static void F1(ref R x, scoped R y)
1093+
> {
1094+
> // Error: The narrowest safe-context is function-member (from `y`)
1095+
> // but `x` is a ref argument of a ref struct type whose
1096+
> // safe-context is caller-context. It must be assignable by
1097+
> // a value with that narrowest safe-context, which fails.
1098+
> F0(ref x, ref y);
1099+
> }
1100+
> }
1101+
> ```
1102+
>
1103+
> *end example*
1104+
10511105
#### §declaration-expression-safe-context Infer safe-context of declaration expressions
10521106
10531107
The safe-context of a declaration variable from an `out` argument (`M(x, out var y)`) or deconstruction (`(var x, var y) = M()`) is the narrowest of the following:
@@ -1058,6 +1112,36 @@ The safe-context of a declaration variable from an `out` argument (`M(x, out var
10581112
- The safe-context of any argument where its corresponding parameter is not `out` and has safe-context of return-only or wider.
10591113
- The ref-safe-context of any argument where its corresponding parameter has ref-safe-context of return-only or wider.
10601114
1115+
> *Example*: The following illustrates how the safe-context of an `out` declaration variable is inferred from the other arguments to the invocation:
1116+
>
1117+
> <!-- Example: {template:"standalone-lib-without-using", name:"DeclarationExprSafeContext", expectedErrors:["CS8352"], ignoredWarnings:["CS0168"]} -->
1118+
> ```csharp
1119+
> ref struct RS
1120+
> {
1121+
> public RS(ref int x) { }
1122+
>
1123+
> static void M0(RS input, out RS output) => output = input;
1124+
>
1125+
> static RS M1()
1126+
> {
1127+
> var i = 0;
1128+
> var rs1 = new RS(ref i); // safe-context of rs1 is function-member
1129+
> M0(rs1, out var rs2); // safe-context of rs2 is function-member
1130+
> return rs2; // Error: rs2 cannot escape function-member
1131+
> }
1132+
>
1133+
> static void M2(RS rs1)
1134+
> {
1135+
> M0(rs1, out scoped var rs2); // scoped forces safe-context to
1136+
> // declaration-block
1137+
> }
1138+
> }
1139+
> ```
1140+
>
1141+
> In `M1`, the safe-context of `rs2` is the narrowest of *caller-context* and the safe-context of `rs1` (*function-member*), which is *function-member*. Therefore `rs2` cannot be returned. In `M2`, the `scoped` modifier forces the safe-context of `rs2` to *declaration-block*.
1142+
>
1143+
> *end example*
1144+
10611145
#### §object-initializer-safe-context Object initializer safe context
10621146
10631147
The safe-context of an object initializer expression is the narrowest of:

0 commit comments

Comments
 (0)