From 9a60037912f70697ca20e64c807fc5bacd22a1a1 Mon Sep 17 00:00:00 2001 From: vsadov Date: Tue, 4 Apr 2017 15:19:11 -0700 Subject: [PATCH] CR feedback --- .../Symbols/Source/LocalFunctionSymbol.cs | 11 +++--- .../Source/SourceMemberMethodSymbol.cs | 2 +- .../Symbols/Source/SourcePropertySymbol.cs | 2 +- .../Portable/Syntax/SyntaxNodeExtensions.cs | 8 +++- .../Emit/CodeGen/CodeGenInParametersTests.cs | 38 +++++++++++++++++++ 5 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index 3edd5abdab0..2c579a5218f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -19,12 +19,12 @@ internal sealed class LocalFunctionSymbol : MethodSymbol private readonly Symbol _containingSymbol; private readonly DeclarationModifiers _declarationModifiers; private readonly ImmutableArray _typeParameters; - private readonly RefKind _refKind; private ImmutableArray _lazyParameters; private bool _lazyIsVarArg; private ImmutableArray _lazyTypeParameterConstraints; private TypeSymbol _lazyReturnType; + private RefKind _lazyRefKind; private TypeSymbol _iteratorElementType; // Lock for initializing lazy fields and registering their diagnostics @@ -73,7 +73,6 @@ internal sealed class LocalFunctionSymbol : MethodSymbol } _binder = binder; - _syntax.ReturnType.SkipRef(out _refKind); } /// @@ -184,7 +183,8 @@ internal override RefKind RefKind { get { - return _refKind; + ComputeReturnType(); + return _lazyRefKind; } } @@ -196,8 +196,7 @@ internal void ComputeReturnType() } var diagnostics = DiagnosticBag.GetInstance(); - RefKind refKind; - TypeSyntax returnTypeSyntax = _syntax.ReturnType.SkipRef(out refKind); + TypeSyntax returnTypeSyntax = _syntax.ReturnType.SkipRef(out _lazyRefKind); TypeSymbol returnType = _binder.BindType(returnTypeSyntax, diagnostics); if (IsAsync && returnType.SpecialType != SpecialType.System_Void && @@ -208,7 +207,7 @@ internal void ComputeReturnType() diagnostics.Add(ErrorCode.ERR_BadAsyncReturn, this.Locations[0]); } - Debug.Assert(refKind == RefKind.None + Debug.Assert(_lazyRefKind == RefKind.None || returnType.SpecialType != SpecialType.System_Void || returnTypeSyntax.HasErrors); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index 5db52b12422..7f0a1e0ce42 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -107,7 +107,7 @@ internal sealed class SourceMemberMethodSymbol : SourceMethodSymbol bool hasBlockBody = syntax.Body != null; _isExpressionBodied = !hasBlockBody && syntax.ExpressionBody != null; - syntax.ReturnType.SkipRef(out _refKind); + _refKind = syntax.ReturnType.GetRefKind(); if (hasBlockBody || _isExpressionBodied) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index c546818cd21..b2d09df8410 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -66,7 +66,7 @@ internal sealed class SourcePropertySymbol : PropertySymbol, IAttributeTargetSym _location = location; _containingType = containingType; _syntaxRef = syntax.GetReference(); - syntax.Type.SkipRef(out _refKind); + _refKind = syntax.Type.GetRefKind(); SyntaxTokenList modifiers = syntax.Modifiers; bodyBinder = bodyBinder.WithUnsafeRegionIfNecessary(modifiers); diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs index 869d826446a..a10bf16fffb 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs @@ -148,6 +148,12 @@ internal static SyntaxToken ExtractAnonymousTypeMemberName(this ExpressionSyntax } } + internal static RefKind GetRefKind(this TypeSyntax syntax) + { + syntax.SkipRef(out var refKind); + return refKind; + } + internal static TypeSyntax SkipRef(this TypeSyntax syntax, out RefKind refKind) { refKind = RefKind.None; @@ -158,7 +164,7 @@ internal static TypeSyntax SkipRef(this TypeSyntax syntax, out RefKind refKind) RefKind.RefReadOnly : RefKind.Ref; - syntax = ((RefTypeSyntax)syntax).Type; + syntax = refType.Type; } return syntax; diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs index 760bf3628c1..d50c7792c32 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs @@ -578,6 +578,44 @@ .maxstack 1 }"); } + [Fact, WorkItem(18357, "https://github.com/dotnet/roslyn/issues/18357")] + public void ReadonlyParamCannotReturnByRefNested() + { + var text = @" +class Program +{ + static ref readonly int M(in int arg1, in (int Alice, int Bob) arg2) + { + ref int M1(in int arg11, in (int Alice, int Bob) arg21) + { + bool b = true; + + if (b) + { + return ref arg11; + } + else + { + return ref arg21.Alice; + } + } + + return ref M1(arg1, arg2); + } +} +"; + + var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef }); + comp.VerifyDiagnostics( + // (12,28): error CS8406: Cannot use variable 'in int' as a ref or out value because it is a readonly variable + // return ref arg11; + Diagnostic(ErrorCode.ERR_RefReadonlyNotField, "arg11").WithArguments("variable", "in int").WithLocation(12, 28), + // (16,28): error CS8407: Members of variable 'in (int Alice, int Bob)' cannot be used as a ref or out value because it is a readonly variable + // return ref arg21.Alice; + Diagnostic(ErrorCode.ERR_RefReadonlyNotField2, "arg21.Alice").WithArguments("variable", "in (int Alice, int Bob)").WithLocation(16, 28) + ); + } + [Fact] public void ReadonlyParamOptional() { -- GitLab