Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions proposals/csharp-11.0/low-level-struct-improvements.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
Low Level Struct Improvements
====
# Low Level Struct Improvements

[!INCLUDE[Specletdisclaimer](../speclet-disclaimer.md)]

Expand Down Expand Up @@ -411,6 +410,30 @@ Span<int> ComplexScopedRefExample(scoped ref Span<int> span)
}
```

#### Rules for object initializers

The *safe-context* of an object initializer expression is narrowest of:

1. The *safe-context* of the constructor call.
2. The *safe-context* arguments to member initializer indexers that can escape to the receiver (can escape to *caller-context*)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be ref-safe-context of ref arguments to indexers (specifically, an in argument)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a case of practically speaking no. The in part of an indexer can't escape into this because it's return only. Hmm ... guess you could if it was [UnscopedRef]. Not sure if we have good testing for that. The 99% case is the value is what matters.

Spec wise can say both thogugh.

3. The *safe-context* of the RHS of assignments in member initializers to non-readonly setters or *ref-safe-context* in case of ref assignment.

Another way of modeling this is to think of any argument to a member initializer that can be assigned to the receiver as being an argument to the constructor. This is because the member initializer is effectively a constructor call.

```c#
Span<int> heapSpan = default;
Span<int> stackSpan = stackalloc int[42];
var x = new S(ref heapSpan)
{
Field = stackSpan;
}

// Can be modeled as
var x = new S(ref heapSpan, stackSpan)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot it be modeled simply as this?

var x = new S(ref heapSpan);
x.Field = stackSpan;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing it that way would mean that the safe-context of x is calling method because only heapSpan is used in the variable declaration. The motivation for putting all of the other values in the constructor is to solve issues like this.

```

This modeling is important because it demonstrates that our [MAMM][rules-method-arguments-must-match] need to account specially for member initializers. Consider that this particular case needs to be illegal as it allows for a value with a narrower *safe-context* to be assigned to a higher one.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the link be (#rules-method-arguments-must-match) instead?


### Method arguments must match
<a name="rules-method-arguments-must-match"></a>

Expand Down