From a56b8351a35f8389048bf623b8910637d44ca708 Mon Sep 17 00:00:00 2001 From: Alireza Habibi Date: Tue, 6 Dec 2016 23:21:00 +0330 Subject: [PATCH] Clarify error message when this is returned by reference --- .../Portable/Binder/Binder_Statements.cs | 10 ++- .../Semantics/RefLocalsAndReturnsTests.cs | 65 +++++++++++-------- 2 files changed, 44 insertions(+), 31 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index c06786850b85a..3e095c8e05818 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -1147,8 +1147,6 @@ static private ErrorCode GetThisLvalueError(BindValueKind kind) return ErrorCode.ERR_AddrOnReadOnlyLocal; case BindValueKind.IncrementDecrement: return ErrorCode.ERR_IncrementLvalueExpected; - case BindValueKind.RefReturn: - return ErrorCode.ERR_RefReturnStructThis; } } @@ -1572,9 +1570,15 @@ private bool CheckIsVariable(SyntaxNode node, BoundExpression expr, BindValueKin var thisref = expr as BoundThisReference; if (thisref != null) { + if (kind == BindValueKind.RefReturn) + { + Error(diagnostics, thisref.Type.IsValueType ? ErrorCode.ERR_RefReturnStructThis : ErrorCode.ERR_RefReadonlyLocal, node, ThisParameterSymbol.SymbolName); + return false; + } + // We will already have given an error for "this" used outside of a constructor, // instance method, or instance accessor. Assume that "this" is a variable if it is in a struct. - if (!thisref.Type.IsValueType || kind == BindValueKind.RefReturn) + if (!thisref.Type.IsValueType) { // CONSIDER: the Dev10 name has angle brackets (i.e. "") Error(diagnostics, GetThisLvalueError(kind), node, ThisParameterSymbol.SymbolName); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs index cabae1fcb9d95..24fb2cb88268c 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefLocalsAndReturnsTests.cs @@ -595,37 +595,46 @@ static ref char Test1() } } - + public class C + { + public ref C M() + { + return ref this; + } + } }"; var comp = CreateCompilationRef(text); comp.VerifyDiagnostics( - // (10,24): error CS8170: Struct members cannot return 'this' or other instance members by reference - // return ref this; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithArguments("this").WithLocation(10, 24), - // (15,24): error CS8170: Struct members cannot return 'this' or other instance members by reference - // return ref x; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "x").WithArguments("this").WithLocation(15, 24), - // (20,24): error CS8170: Struct members cannot return 'this' or other instance members by reference - // return ref this.x; - Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this.x").WithArguments("this").WithLocation(20, 24), - // (36,32): error CS8168: Cannot return local 'M1' by reference because it is not a ref local - // return ref Foo(ref M1); - Diagnostic(ErrorCode.ERR_RefReturnLocal, "M1").WithArguments("M1").WithLocation(36, 32), - // (36,24): error CS8164: Cannot return by reference a result of 'Test.Foo(ref char)' because the argument passed to parameter 'arg' cannot be returned by reference - // return ref Foo(ref M1); - Diagnostic(ErrorCode.ERR_RefReturnCall, "Foo(ref M1)").WithArguments("Test.Foo(ref char)", "arg").WithLocation(36, 24), - // (41,32): error CS8169: Cannot return a member of local 'M2' by reference because it is not a ref local - // return ref Foo(ref M2.x); - Diagnostic(ErrorCode.ERR_RefReturnLocal2, "M2").WithArguments("M2").WithLocation(41, 32), - // (41,24): error CS8164: Cannot return by reference a result of 'Test.Foo(ref char)' because the argument passed to parameter 'arg' cannot be returned by reference - // return ref Foo(ref M2.x); - Diagnostic(ErrorCode.ERR_RefReturnCall, "Foo(ref M2.x)").WithArguments("Test.Foo(ref char)", "arg").WithLocation(41, 24), - // (46,32): error CS8168: Cannot return local 'M2' by reference because it is not a ref local - // return ref Foo(ref M2).x; - Diagnostic(ErrorCode.ERR_RefReturnLocal, "M2").WithArguments("M2").WithLocation(46, 32), - // (46,24): error CS8165: Cannot return by reference a member of result of 'Test.Foo(ref Test.S1)' because the argument passed to parameter 'arg' cannot be returned by reference - // return ref Foo(ref M2).x; - Diagnostic(ErrorCode.ERR_RefReturnCall2, "Foo(ref M2)").WithArguments("Test.Foo(ref Test.S1)", "arg").WithLocation(46, 24)); + // (10,24): error CS8170: Struct members cannot return 'this' or other instance members by reference + // return ref this; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithArguments("this").WithLocation(10, 24), + // (15,24): error CS8170: Struct members cannot return 'this' or other instance members by reference + // return ref x; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "x").WithArguments("this").WithLocation(15, 24), + // (20,24): error CS8170: Struct members cannot return 'this' or other instance members by reference + // return ref this.x; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this.x").WithArguments("this").WithLocation(20, 24), + // (36,32): error CS8168: Cannot return local 'M1' by reference because it is not a ref local + // return ref Foo(ref M1); + Diagnostic(ErrorCode.ERR_RefReturnLocal, "M1").WithArguments("M1").WithLocation(36, 32), + // (36,24): error CS8164: Cannot return by reference a result of 'Test.Foo(ref char)' because the argument passed to parameter 'arg' cannot be returned by reference + // return ref Foo(ref M1); + Diagnostic(ErrorCode.ERR_RefReturnCall, "Foo(ref M1)").WithArguments("Test.Foo(ref char)", "arg").WithLocation(36, 24), + // (41,32): error CS8169: Cannot return a member of local 'M2' by reference because it is not a ref local + // return ref Foo(ref M2.x); + Diagnostic(ErrorCode.ERR_RefReturnLocal2, "M2").WithArguments("M2").WithLocation(41, 32), + // (41,24): error CS8164: Cannot return by reference a result of 'Test.Foo(ref char)' because the argument passed to parameter 'arg' cannot be returned by reference + // return ref Foo(ref M2.x); + Diagnostic(ErrorCode.ERR_RefReturnCall, "Foo(ref M2.x)").WithArguments("Test.Foo(ref char)", "arg").WithLocation(41, 24), + // (46,32): error CS8168: Cannot return local 'M2' by reference because it is not a ref local + // return ref Foo(ref M2).x; + Diagnostic(ErrorCode.ERR_RefReturnLocal, "M2").WithArguments("M2").WithLocation(46, 32), + // (46,24): error CS8165: Cannot return by reference a member of result of 'Test.Foo(ref Test.S1)' because the argument passed to parameter 'arg' cannot be returned by reference + // return ref Foo(ref M2).x; + Diagnostic(ErrorCode.ERR_RefReturnCall2, "Foo(ref M2)").WithArguments("Test.Foo(ref Test.S1)", "arg").WithLocation(46, 24), + // (58,24): error CS1605: Cannot use 'this' as a ref or out value because it is read-only + // return ref this; + Diagnostic(ErrorCode.ERR_RefReadonlyLocal, "this").WithArguments("this").WithLocation(58, 24)); } [Fact]