Closed jcouv closed 5 years ago
FYI @VSadov @OmarTawfik I'll start gathering ideas for test plan.
After talking with @cston, it seems that we need to add tests for both EnC and EE for:
I was going to do that in #18715, but this is getting too big of a PR, so I'll keep it for later.
cc @VSadov @jcouv
Is this doc up-to-date, so I can review it to see what's needed to make the debugging experience good?
Turns out it isn't. Specifically https://github.com/dotnet/csharplang/blob/master/proposals/readonly-ref.md#metadata-representaion.
@tmat for metadata representation specifically, I've the work to enable that in #18715. Basically, we added a new attribute to the framework (IsReadOnlyAttribute) and we will use that to annotate parameters and return types.
@OmarTawfik So we are not using custom modifiers anywhere? Last time I heard we used a mix. How do we mark local variables that are readonly ref
? A specification clarifying these questions would be useful.
@tmat the plan (in a future PR) is to use modreqs on parameters and return types to break older compilers and other languages from using it (until they support the feature). @VSadov can you please comment on the local variables? is there anything I'm missing?
@OmarTawfik Could you update the spec please?
@tmat. Yes. I'll send a PR out later.
@OmarTawfik Thanks!
@jcouv about this part:
ref readonly string M(ref readonly string s = "hello") { return ref s; }.
Same with value type. (gives a unsafe-to-escape diagnostic)
The current design doesn't prohibit such scenario. Can you explain?
Write a test plan for "ref readonly", "readonly structs", "ref and ref readonly extensions" and "ref ternary"
LDM
in
syntax from initial release? (merged)ref readonly
at call site (for those who dislike auto-ref)? (yes, but we're switching toin
as keyword)Spec
in
parameters are not allowed in iterator or async methodsvar x = stackalloc ...
is pointer type for compat reasons, butcondition ? stackalloc ... : stackalloc ...
isSpan
)Misc
ref readonly
,in
,return ref ...
,ref
ternary,in
versusref readonly
readonly struct
ref readonly
at call site, CodeStyle for call site (for those who don't like auto-ref)Ref readonly parameters
[x] Spec exists
[x] test passing too many modifiers ("ref readonly in" or "in ref readonly", etc)
[x] verify API declaration and usage from compilation, image, metadata-only image and ref assembly
[x] ref readonly property from metadata with different attributes on getter and property
[x] Where is it allowed or blocked?
out
orparams
(expect error)ref readonly
is disallowed: in local declarationsref readonly var x = y;
, in front of expressionsvar x = ref readonly y;
,return ref readonly
,foreach (readonly ref i in ...)
in
andref readonly
in lambdain
in delegatein
in local functionin
in async and iterator methods (disallowed)in
orref readonly
at call site (disallowed)ref
andreadonly
does matter (what is the error? should we offer a fixer?)in
in pattern-based lowering:Deconstruct
method within
parameters is not applicable for deconstructionin
in builder typeGetEnumerator(in int count = 10)
(see #19742)[x] OHI
ref/out/in
(we only consider types)M(1);
withvoid M(ref readonly int i) { }
andvoid M(int i) { }
in situation of ambiguity (because of inheritance or extension methods)[x] verify
in
is invariant (because of CLR limitation, just likeout
)[ ] Verify that IL for copy versus no-copy
M(someInArg, async M2(), someOtherInArg)
someInArg
could be local, constant,RefReadonlyM(refReadonlyField)
,someArray[index]
,field
[ ] No writes allowed:
ref
in S s
, thens.Mutate();
) (also allowed, operating on a temp copy, verify IL. But no copy ifS
is readonly struct)in
through is ok[ ]
in
parameters cannot be captured (lambda/async/iterator)[x]
in
allowed in indexer and operator parameters[x] test VB interop (calling blocked because modreq on overridable members and delegate/interface methods, but allowed on non-overridable members)
[x] taking pointer to ref readonly parameter (in unsafe code) is disallowed
[x] passing
nameof
expression asin
argument (expect copy?)Ref readonly returns
[x] Spec exists
[x]
in
syntax disallowed in method declaration[x]
ref readonly
return in async method (no syntax for it)[x]
ref readonly
return on operator is disallowed (no syntax for it)[x]
ref readonly
on indexer (allowed)[x]
readonly
is disallowed inreturn
statement[x] signature needs exact match in OHI
in
andref
[x] ref-readonly-returning lambda?
[x] calling with a discard (no syntax for it?)
[x] metadata:
IsReadOnlyAttribute
gets embbeded if not found, disallowed in sourceInAttribute
modreq present butIsReadOnlyAttribute
is missing, then cannot load metadataIsReadOnlyAttribute
is present, butInAttribute
modreq is missing, then can load and this absence of modreq will be carried over when overriding.Readonly struct
readonly
on class declaration and other illegal membersreadonly
is floating, butref
must be next tostruct
inreadonly ref struct
partial
must be beforeref
orstruct
(but what about thereadonly
?)in
structreadonly
on half a partial struct (allowed, just like other modifiers)Obsolete
attribute given by user wins. There should be a warning.void M(in S s)
withM(this)
, but notvoid M(ref S s)
.void M(S s)
withM(this)
, but that will make a copy.this
cannot be captured by lambda or otherthis
is disallowedRef ternary
(b ? ref x : ref y).M()
whereM
is ref extension method, regular extension method (error), regular method (error)x
ory
or both are readonly structs?M(b ? ref x : ref y)
wherevoid M(in ...)
, I expect no temporary.b ? ref M() : ref M2()
whereref readonly C M()
(and same for M2), expect the ternary is readonlyb ? ref this : ref this
wherethis
refers to a readonly struct, is the ternary readonly?b
is known to be constant (compiler knows which branch will be executed)?b ? ref x : y
b1 ? ref (b2 ? ref x : ref y) : ref z
ref x ?? ref y
b ? ref x : ref default
(disallowed)in
argument (M(in condition ? ref x : ref y);
)Ref readonly extension methods
ref readonly S Extension(ref readonly this S s) { return ref s; }
void RRExtension<T>(ref readonly this T t) { ... }
(expect error)42.RRExtension()
(ok, but makes temporary)readonlyField.RRExtension()
(expect no temporary)refReadonlyParameter.RRExtension()
(expect no temporary)M().RRExtension()
(expect no temporary)this.RRExtension()
(ref readonly ternary).RRExtension()
(expect no temporary)Ref-like types and safety (Span)
ref readonly string M(ref readonly string s = "hello") { return ref s; }
. Same with value type. (gives a unsafe-to-escape diagnostic)dynamic d = stackalloc int[10];
Span<dynamic> d = stackalloc dynamic[10];
Misc
(b ? ref x : ref x).foo()
x.y.foo() // ref may be inferred
IsReadOnly
andIsByRefLike
are disallowed in sourceSee also