Skip to content

Commit 08bba1a

Browse files
committed
Add examples for complicated examples
Add three examples from the speclet for the most complicated rules for `scoped` ref.
1 parent 7638352 commit 08bba1a

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
@@ -1024,6 +1024,37 @@ For the purpose of these rules, a given argument `expr` passed to parameter `p`:
10241024
10251025
A property invocation (either `get` or `set`) is treated as a method invocation of the underlying method by the above rules.
10261026
1027+
> *Example*: The following illustrates how `scoped` affects the safe-context of a method's return value:
1028+
>
1029+
> <!-- Example: {template:"standalone-lib-without-using", name:"MethodInvocationSafeContext", expectedErrors:["CS8347"]} -->
1030+
> ```csharp
1031+
> ref struct RS
1032+
> {
1033+
> public ref int RefField;
1034+
> public RS(ref int i) { RefField = ref i; }
1035+
> }
1036+
>
1037+
> class C
1038+
> {
1039+
> static RS CreateAndCapture(ref int value)
1040+
> {
1041+
> // OK: ref-safe-context of `ref value` is caller-context,
1042+
> // safe-context contributed is caller-context.
1043+
> return new RS(ref value);
1044+
> }
1045+
>
1046+
> static RS CreateWithoutCapture(scoped ref int value)
1047+
> {
1048+
> // Error: `value` is scoped ref so it does not contribute
1049+
> // ref-safe-context. The constructor needs ref-safe-context
1050+
> // of caller-context but `value` only has function-member.
1051+
> return new RS(ref value);
1052+
> }
1053+
> }
1054+
> ```
1055+
>
1056+
> *end example*
1057+
10271058
#### §method-arguments-must-match Method arguments must match
10281059
10291060
For any method invocation `e.M(a1, a2, ... aN)`:
@@ -1046,6 +1077,29 @@ For any method invocation `e.M(a1, a2, ... aN)`:
10461077
10471078
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.
10481079
1080+
> *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:
1081+
>
1082+
> <!-- Example: {template:"standalone-lib-without-using", name:"MethodArgsMustMatch", expectedErrors:["CS8350"]} -->
1083+
> ```csharp
1084+
> ref struct R { }
1085+
>
1086+
> class C
1087+
> {
1088+
> static void F0(ref R a, scoped ref R b) { }
1089+
>
1090+
> static void F1(ref R x, scoped R y)
1091+
> {
1092+
> // Error: The narrowest safe-context is function-member (from `y`)
1093+
> // but `x` is a ref argument of a ref struct type whose
1094+
> // safe-context is caller-context. It must be assignable by
1095+
> // a value with that narrowest safe-context, which fails.
1096+
> F0(ref x, ref y);
1097+
> }
1098+
> }
1099+
> ```
1100+
>
1101+
> *end example*
1102+
10491103
#### §declaration-expression-safe-context Infer safe-context of declaration expressions
10501104
10511105
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:
@@ -1056,6 +1110,36 @@ The safe-context of a declaration variable from an `out` argument (`M(x, out var
10561110
- The safe-context of any argument where its corresponding parameter is not `out` and has safe-context of return-only or wider.
10571111
- The ref-safe-context of any argument where its corresponding parameter has ref-safe-context of return-only or wider.
10581112
1113+
> *Example*: The following illustrates how the safe-context of an `out` declaration variable is inferred from the other arguments to the invocation:
1114+
>
1115+
> <!-- Example: {template:"standalone-lib-without-using", name:"DeclarationExprSafeContext", expectedErrors:["CS8352"], ignoredWarnings:["CS0168"]} -->
1116+
> ```csharp
1117+
> ref struct RS
1118+
> {
1119+
> public RS(ref int x) { }
1120+
>
1121+
> static void M0(RS input, out RS output) => output = input;
1122+
>
1123+
> static RS M1()
1124+
> {
1125+
> var i = 0;
1126+
> var rs1 = new RS(ref i); // safe-context of rs1 is function-member
1127+
> M0(rs1, out var rs2); // safe-context of rs2 is function-member
1128+
> return rs2; // Error: rs2 cannot escape function-member
1129+
> }
1130+
>
1131+
> static void M2(RS rs1)
1132+
> {
1133+
> M0(rs1, out scoped var rs2); // scoped forces safe-context to
1134+
> // declaration-block
1135+
> }
1136+
> }
1137+
> ```
1138+
>
1139+
> 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*.
1140+
>
1141+
> *end example*
1142+
10591143
#### §object-initializer-safe-context Object initializer safe context
10601144
10611145
The safe-context of an object initializer expression is the narrowest of:

0 commit comments

Comments
 (0)