diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index 1dd7c3f82440a8345269e484f4066f15e40b7749..3d3afbb82e99c58df8d2544413dc50ce13a762b9 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -1115,7 +1115,8 @@ private bool CheckPropertyValueKind(SyntaxNode node, BoundExpression expr, BindV uint escapeTo = scopeOfTheContainingExpression; // collect all writeable ref-like arguments, including receiver - if (receiverOpt?.Type?.IsByRefLikeType == true) + var receiverType = receiverOpt?.Type; + if (receiverType?.IsByRefLikeType == true && receiverType?.IsReadOnly == false) { escapeTo = GetValEscape(receiverOpt, scopeOfTheContainingExpression); } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs index 8252374e5a05c69598c9744fea15e956097be0ae..952614c59616da84db2fee6f7910c06bc3569ada 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefEscapingTests.cs @@ -1299,5 +1299,48 @@ public S2 M2() Diagnostic(ErrorCode.ERR_RefReturnStructThis, "x").WithArguments("this").WithLocation(31, 28) ); } + + [WorkItem(21880, "https://github.com/dotnet/roslyn/issues/21880")] + [Fact()] + public void MemberOfReadonlyRefLikeEscape() + { + var text = @" + public static class Program + { + public static void Main() + { + // OK, SR is readonly + new SR().TryGet(out int value1); + + // not OK, TryGet can write into the instance + new SW().TryGet(out int value2); + } + } + + public readonly ref struct SR + { + public void TryGet(out int result) + { + result = 1; + } + } + + public ref struct SW + { + public void TryGet(out int result) + { + result = 1; + } + } +"; + CreateCompilationWithMscorlibAndSpan(text).VerifyDiagnostics( + // (10,33): error CS8168: Cannot return local 'value2' by reference because it is not a ref local + // new SW().TryGet(out int value2); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "int value2").WithArguments("value2").WithLocation(10, 33), + // (10,13): error CS8524: This combination of arguments to 'SW.TryGet(out int)' is disallowed because it may expose variables referenced by parameter 'result' outside of their declaration scope + // new SW().TryGet(out int value2); + Diagnostic(ErrorCode.ERR_CallArgMixing, "new SW().TryGet(out int value2)").WithArguments("SW.TryGet(out int)", "result").WithLocation(10, 13) + ); + } } }