-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test Plan for Span<T>, aka interior pointer, aka stackonly struct #20127
Comments
|
@jaredpar I see that you are the test and review resource for this feature. It wasn't clear to me how much of that you've delegated. Please let me know if I am on the hook for further work aside from the open issues in the draft spec. [Note from @gafter: I have been assigned the test resource for this.] |
For ref reassignment will this work with non ref structs; e.g. array elements Pattern I've wanted to express (poor pseudo code): ref var e1 = ref _array[0];
while(el.NotCorrect)
{
if ((uint)e1.Next >= (uint)_array.Length)
{
break;
}
ref el = ref _array[e1.Next];
}
if (el.NotCorrect)
{
var oldLength = _array.Length;
_array = new var[oldLength * 2];
// *** reassignment here
ref e1 = ref _array[oldLength];
}
// Do something with el
// Rather than create a second array lookup here
// ref var e2 = ref _array[index]; You can do the general reassignment in the loop body (by the ref being local to loop); however then you need to pass the int indexer out and do a second array lookup to work with it; when you have already found the |
@benaadams Yes, once we add support for ref reassignment that would work. But we are not adding ref reassignment in 7.2. |
I've added a championed proposal for ref reassignment. dotnet/csharplang#933 |
* dotnet/master: Report binding error for typed LINQ query on a type expression (dotnet#22412) clean up more refactoring Fixed tests fix test after rebase one more test CR feedback Allow taking unmanaged/pinned addresses of readonly variables. Fix typo in INotifyCompletion API in doc (dotnet#22417) Fix serialization of attribute data to account for named params argument (dotnet#22231) Create tests to cover test plans dotnet#19216 and dotnet#20127 (dotnet#22284) Checked uses of RefKind.RefReadOnly String rename Check for null before registering incremental analyzer in work coordinator. clean up Create tests to cover test plans dotnet#19216 and dotnet#20127
The test plan is a gate on integrating a feature. Since this feature has been integrated, closing this test plan. |
That doesn't seem right. Checking 18 out of 161 defeats the purpose and seems like a joke. If I were to choose two items to push on, I'd ask to consolidate the docs for this feature and bullets for the test plan (to act as a reminder when working on next feature). |
@jcouv While I agree, we integrated before the developer identified tests for these bullet items, and no tests have ever been identified for those bullets. We did not follow the defined process for feature development (i.e. test plan checked off before feature integrated). But that is, in practice, what we did. I'll reopen and assign to the developer to enact your suggestion. |
Vlad updated the docs: https://github.com/dotnet/csharplang/blob/master/proposals/csharp-7.2/readonly-ref.md We still need to update the test plan. |
@gafter |
This feature has long since shipped. |
This is a test plan for the feature set variously known as "stackonly structs", "interior pointer", and "Span" targeting milestone 15.6 (C# 7.2), which is related to (but different from) slicing.
See also
Declarations and types
ref struct
declarationsref
as a modifier on astruct
declarationref
modifier must appear immediately before thestruct
keyword (no interveningpublic
)ref struct
type cannot be partial (neitherref partial struct
norpartial ref struct
are accepted)ref struct
type may be genericref struct
type may contain an instance field of anotherref struct
typestruct
, nor a class, may contain a field of aref struct
typeref struct
type declaration may not contain a base clause. It therefore cannot be declared to extend any interface type.base
in the body of any method, property, etc in aref struct
type.ref struct
type declaration may not contain an iterator instance method.ref struct
type declaration may not contain an async instance method.ref struct
type declaration may contain a static iterator method, and a static async method.ref struct
type may not be embedded.use of
ref struct
typesref struct
type may not be used as a type argument to aclass
,struct
,delegate
, or method.System.Nullable
with a type argument of aref struct
type, even implicitly.e.M
returns a value of aref struct
type,e?.M()
is an error.ref struct
type as a type argument, an error is given.ref struct
type may not be converted to a delegateref struct
type (e.g.GetHashCode
) may not be converted to a delegateref struct
type (even if the container is aref struct
type)ref struct
type as the element type of an array typeref struct
type.ref struct
type.ref struct
type, e.g.(1, span)
(null, span)
has no natural type and is converted to a tuple type that does not contain an element of aref struct
type (e.g. by the use of a user-defined conversion), e.g.(string, int) x = (null, span);
where the span's type contains a conversion toint
.Deconstruct
method may output one or more values of aref struct
type.ref struct
types can be written to implement theforeach
pattern, in which case theforeach
statement should work with an iterator variable of aref struct
type.ref struct
types can be written to implement theforeach
pattern with an element type of aref struct
type that contains aDeconstruct
method, in which case theforeach
statement should work with a pair of iterator variables ofref struct
types.ref struct
type may be captured in a lambda or local function.ref struct
type may be declared in an iterator or async method.ref struct
type may not require spilling inasync
code, e.g. it is an error (possibly reported during emit) to compile an expression such asM(span1, await e)
.ref struct
type toobject
orValueType
.ref struct
typeobject
or inSystem.ValueType
but not overridden in aref struct
type may be called with a receiver of thatref struct
type.ref struct
type.ref struct
type is nullable.ref struct
type.ref struct
type is nullable.ref struct
type (left, and right)ref struct
typeref struct
types.async
or an iterator method.ref struct
types, delegate types, and methods can be declared which permit the use of Linq with a sequence of value of aref struct
type represented by, e.g.,Span<T>
.ref struct
type cannot be awaited, even if it is otherwise task-like. (is this right?)Restrictions on
stackalloc
Tests should demonstrate that
stackalloc
can only be usedstackalloc
works in an initializerstackalloc
works in a ternary in an initializerstackalloc
works in a nested ternary in an initializerstackalloc
does not work as an operand to a method invocation, e.g.M(stackalloc int[1])
stackalloc
result and the variable's type.ref struct
typestackalloc
is an error if parenthesizedstackalloc
is an error if either operand of??
stackalloc
is an error if subject to an explicit cast, e.g.var x = (myspan)stackalloc int[10];
var x = stackalloc int[10];
is an error unless in anunsafe
context, becausex
is of typeint*
.Span<int> x = stackalloc int[10];
is not an error outside anunsafe
context.T x = stackalloc int[10];
is an error outside anunsafe
context if it required a user-defined conversion fromint*
toT
T x = stackalloc int[10];
is permitted outside anunsafe
context if it required a user-defined conversion fromSpan<int>
toT
stackalloc
restrictions regarding where it may appear.Tests should demonstrate that the compiler rejects an attempt to use
stackalloc
(#21918)catch
block (with or without a catch parameter).localloc
instruction). [This cannot occur ifstackalloc
is restricted to local variable initializers]finally
block.Miscellaneous
ref struct
type from metadataref struct
type from metadata (hand verify)ref struct
type is declared with an explicit[Obsolete]
attributeref struct
type acts as such in separate compilation scenariosref struct
type from VB produces a compile-time error.ITypeSymbol
orTypeSymbol
is aref struct
type.ref struct
value cannot be used in an expression tree, even as an intermediate result. (?)ref struct
type, either to or fromdynamic
.ref struct
type may be used in an object, collection, or dictionary initializer for a type whose API was designed to permit this.this
parameter of aref struct
type.ref struct
type may not be used as a fill-in in string interpolation due to the need to box the value.APIs
T1 x = stackalloc int[10];
, the semantic model should report that thestackalloc
expression has the typeint*
and a converted type ofT1
T1
isint*
int*
toT1
Span<int>
toT1
.stackalloc int[10]
appears as some appropriate kind of conversion.stackalloc
expression in any other syntactic context than a local variable initializer context has the typeSpan<T>
.Escape safety rules
Each test bullet below of the form "Show that x is (ref-)safe-to-escape y but/and no further.", this is intended to require a test that demonstrates that x is (ref-)safe-to-escape to y, and a separate test that demonstrates that x is not (ref-)safe-to-escape the enclosing scope of y.
Parameters
ref struct
type is ref-safe-to-escape to the top level of a method, but no further, no matter the ref mode of the parameter.ref
,in
, orout
parameter that is not of aref struct
type is ref-safe-to-escape from the entire method.this
parameter of a struct type that is not aref struct
type is ref-safe-to-escape to the top level of a method, but no further.ref struct
type is ref-safe-to-escape to the top level of a method, but no further.ref struct
type is safe-to-escape (by value) from the entire method. Show this for thethis
parameter as well.Locals
ref struct
type and any other type).ref struct
type does not require an initializer, in which case it is safe to return. TODO: The spec needs to say thisref struct
type that is declared as the iterator variable of aforeach
loop is safe-to-escape the same as the loop's expression, and no further.ref struct
type that is declared in a local variable declaration is safe-to-escape the same as the variable's initializer, and no further.ref struct
type is explicitly the type of a pattern variable.ref struct
type is implicitly the type of a pattern variable.out
variables are safe to return.out
variables participate in the no mixing rule.ref struct
type.ref struct
type.2017-09-15 Review of the test plan stopped here
Fields
e
is a reference type, thate.F
is ref-safe-to-escape from the entire method.e
is a value type, its ref-safe-to-escape is the same as the ref-safe-to-escape ofe
, but no further.e.F
is aref struct
type, it is safe-to-escape the same as the safe-to-escape ofe
, but no further.Multi-operand expression forms
c ? e1 : e2
where the result is aref struct
type, that the safe-to-escape of the result is the narrowest among the safe-to-escape ofe1
ande2
.e1
is aref struct
type bute2
is not (the safe-to-escape is taken frome1
)e2
is aref struct
type bute1
is not (the safe-to-escape is taken frome2
)e1
ande2
areref struct
types (the safe-to-escape is the smallest of the two)e1
nore2
areref struct
types (the result is safe to return)c ? ref e1 : ref e2
,e1
ande2
agreeref-safe-to-escape* of the result is the same as the *ref-safe-to-escape* of
e1`, but no further.Method invocation
e1.M(e2, ...)
is ref-safe-to-escape the smallest of the following scopes (but no further) (a pair of positive/negative tests for each of these)ref
andout
argument expressionsref struct
typesin
parameter for which there is a corresponding expression that is an lvalue, its ref-safe-to-escapein
parameter for which there is a no corresponding expression, the immediately enclosing scoperef struct
returning method invocatione1.M(e2, ...)
is safe-to-escape the smallest of the following scopes (but no further) (a pair of positive/negative tests for each of these)ref
andout
argument expressionsref struct
typesin
parameter for which there is a corresponding expression that is an lvalue, its ref-safe-to-escapein
parameter for which there is a no corresponding expression, the immediately enclosing scoperef d.F
whered
is of type dynamice1 + e2
where the result is aref struct
type, that the safe-to-escape of the result is the narrowest among the safe-to-escape ofe1
ande2
.e1
is aref struct
type bute2
is not (the safe-to-escape is taken frome1
)e2
is aref struct
type bute1
is not (the safe-to-escape is taken frome2
)e1
ande2
areref struct
types (the safe-to-escape is the smallest of the two)e1
nore2
areref struct
types (the result is safe to return)ref
result follows the method invocation rules: both theref-safe-to-escape
is taken from the safe-to-escape of the receiver.ref struct
type follows the method invocation rules: thesafe-to-escape
is taken from the safe-to-escape of the receiver.ref struct
type, its result is safe-to-escape the smallest of the following scopes (but no further) (a pair of positive/negative tests for each of these)ref
andout
argument expressionsref struct
typesin
parameter for which there is a corresponding expression that is an lvalue, its ref-safe-to-escapein
parameter for which there is a no corresponding expression, the immediately enclosing scopereturn ref await e;
, where the type ofe
is a custom value task whoseGetResult()
method is ref-returning, we should be returning the returned ref, not a ref to a copy of its value. In particular, if the returned ref is ref-safe-to-return, then there should be no error.stackalloc
stackalloc
expression is safe-to-escape to the top level of the method, but no further.default
default
ordefault(T)
expression is safe-to-escape from the entire enclosing method (i.e. it is safe to return)Other
default
value of aref struct
type is safe to return (i.e. escape from the whole method).Constraints in expressions
ref e1 = ref e2
, the ref-safe-to-escape ofe2
must be at least as wide a scope as the ref-safe-to-escape ofe1
.return ref e1
, the ref-safe-to-escape ofe1
must be ref-safe-to-escape from the entire method.return e1
, the safe-to-escape ofe1
must be safe-to-escape from the entire method.e1 = e2
, if the type ofe1
is aref struct
type, then the safe-to-escape ofe2
must be at least as wide a scope as the safe-to-escape ofe1
.ref
orout
argument to aref struct
type (including the receiver), with safe-to-escape E1, thenref
orout
argument (excluding the receiver and arguments ofref struct
types) may have a narrower ref-safe-to-escape than E1; andThe text was updated successfully, but these errors were encountered: