提交 067fd90d 编写于 作者: V vsadov

Implements binding for `ref readonly` returns and `in` parameters.

NOTE: binding of `ref readonly` parameters is NYI
上级 a83794bb
......@@ -113,24 +113,31 @@ internal partial class Binder
type = BindType(typeSyntax, diagnostics);
foreach (var modifier in p.Modifiers)
{
if (modifier.Kind() == SyntaxKind.RefKeyword)
{
refKind = RefKind.Ref;
allValue = false;
break;
}
else if (modifier.Kind() == SyntaxKind.OutKeyword)
{
refKind = RefKind.Out;
allValue = false;
break;
}
else if (modifier.Kind() == SyntaxKind.ParamsKeyword)
var modKind = modifier.Kind();
switch(modifier.Kind())
{
// This was a parse error in the native compiler;
// it is a semantic analysis error in Roslyn. See comments to
// changeset 1674 for details.
Error(diagnostics, ErrorCode.ERR_IllegalParams, p);
case SyntaxKind.RefKeyword:
refKind = RefKind.Ref;
allValue = false;
break;
case SyntaxKind.OutKeyword:
refKind = RefKind.Out;
allValue = false;
break;
case SyntaxKind.InKeyword:
refKind = RefKind.RefReadOnly;
allValue = false;
break;
case SyntaxKind.ParamsKeyword:
// This was a parse error in the native compiler;
// it is a semantic analysis error in Roslyn. See comments to
// changeset 1674 for details.
Error(diagnostics, ErrorCode.ERR_IllegalParams, p);
break;
}
}
}
......
......@@ -106,7 +106,7 @@ bool Cci.ISignature.ReturnValueIsByRef
{
get
{
return UnderlyingMethod.RefKind == RefKind.Ref;
return UnderlyingMethod.RefKind.IsManagedReference();
}
}
......
......@@ -226,7 +226,7 @@ bool Cci.ISignature.ReturnValueIsByRef
{
get
{
return this.RefKind == RefKind.Ref;
return this.RefKind.IsManagedReference();
}
}
......
......@@ -188,7 +188,7 @@ bool Cci.ISignature.ReturnValueIsByRef
get
{
CheckDefinitionInvariantAllowEmbedded();
return this.RefKind == RefKind.Ref;
return this.RefKind.IsManagedReference();
}
}
......
......@@ -8814,12 +8814,6 @@ private void ParseDeclarationModifiers(SyntaxListBuilder list)
SyntaxKind k;
while (IsDeclarationModifier(k = this.CurrentToken.ContextualKind) || IsAdditionalLocalFunctionModifier(k))
{
// "ref readonly" is not a modifier, in our syntax.
if (k == SyntaxKind.RefKeyword && this.PeekToken(1).Kind == SyntaxKind.ReadOnlyKeyword)
{
break;
}
SyntaxToken mod;
if (k == SyntaxKind.AsyncKeyword)
{
......
......@@ -115,8 +115,8 @@ Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.ReadOnlyKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.RefKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.Type.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.WithReadOnlyKeyword(Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.WithRefKeyword(Microsoft.CodeAnalysis.SyntaxToken refKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.WithType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
......@@ -298,8 +298,8 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedVariableDesignat
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefExpression(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SingleVariableDesignation(Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ThrowExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ThrowExpression(Microsoft.CodeAnalysis.SyntaxToken throwKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax
......
......@@ -64,6 +64,10 @@ public override void VisitProperty(IPropertySymbol symbol)
{
AddRefIfRequired();
}
else if (symbol.ReturnsByRefReadonly)
{
AddRefReadonlyIfRequired();
}
AddCustomModifiersIfRequired(symbol.RefCustomModifiers);
......@@ -237,6 +241,10 @@ public override void VisitMethod(IMethodSymbol symbol)
{
AddRefIfRequired();
}
else if (symbol.ReturnsByRefReadonly)
{
AddRefReadonlyIfRequired();
}
AddCustomModifiersIfRequired(symbol.RefCustomModifiers);
......@@ -709,6 +717,17 @@ private void AddRefIfRequired()
}
}
private void AddRefReadonlyIfRequired()
{
if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeRef))
{
AddKeyword(SyntaxKind.RefKeyword);
AddSpace();
AddKeyword(SyntaxKind.ReadOnlyKeyword);
AddSpace();
}
}
private void AddRefKindIfRequired(RefKind refKind)
{
if (format.ParameterOptions.IncludesOption(SymbolDisplayParameterOptions.IncludeParamsRefOut))
......@@ -723,6 +742,12 @@ private void AddRefKindIfRequired(RefKind refKind)
AddKeyword(SyntaxKind.RefKeyword);
AddSpace();
break;
case RefKind.RefReadOnly:
AddKeyword(SyntaxKind.RefKeyword);
AddSpace();
AddKeyword(SyntaxKind.ReadOnlyKeyword);
AddSpace();
break;
}
}
}
......
......@@ -174,6 +174,10 @@ public override void VisitNamedType(INamedTypeSymbol symbol)
{
AddRefIfRequired();
}
else if (invokeMethod.ReturnsByRefReadonly)
{
AddRefReadonlyIfRequired();
}
if (invokeMethod.ReturnsVoid)
{
......
......@@ -175,7 +175,6 @@ public bool ReturnsByRef
{
get
{
Debug.Assert(this.RefKind != RefKind.Out);
return this.RefKind == RefKind.Ref;
}
}
......
......@@ -51,9 +51,14 @@ protected override sealed Symbol OriginalSymbolDefinition
}
/// <summary>
/// Indicates whether or not the method returns by reference
/// Indicates whether or not the property returns by reference
/// </summary>
public bool ReturnsByRef { get { return this.RefKind != RefKind.None; } }
public bool ReturnsByRef { get { return this.RefKind == RefKind.Ref; } }
/// <summary>
/// Indicates whether or not the property returns a readonly reference
/// </summary>
public bool ReturnsByRefReadonly { get { return this.RefKind == RefKind.RefReadOnly ; } }
/// <summary>
/// Gets the ref kind of the property.
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
internal static partial class RefKindExtensions
{
public static SyntaxToken GetToken(this RefKind refKind)
public static bool IsManagedReference(this RefKind refKind)
{
if (refKind == RefKind.Out)
{
return SyntaxFactory.Token(SyntaxKind.OutKeyword);
}
if (refKind == RefKind.Ref)
{
return SyntaxFactory.Token(SyntaxKind.RefKeyword);
}
return default(SyntaxToken);
Debug.Assert(refKind <= RefKind.RefReadOnly);
return refKind != RefKind.None;
}
public static RefKind GetRefKind(this SyntaxKind syntaxKind)
......
......@@ -31,19 +31,19 @@ internal static class ParameterHelpers
foreach (var parameterSyntax in syntax.Parameters)
{
SyntaxToken outKeyword;
SyntaxToken refKeyword;
SyntaxToken argPassingKeyword;
SyntaxToken paramsKeyword;
SyntaxToken thisKeyword;
var refKind = GetModifiers(parameterSyntax.Modifiers, out outKeyword, out refKeyword, out paramsKeyword, out thisKeyword);
var refKind = GetModifiers(parameterSyntax.Modifiers, out argPassingKeyword, out paramsKeyword, out thisKeyword);
if (parameterSyntax.IsArgList)
{
arglistToken = parameterSyntax.Identifier;
// The native compiler produces "Expected type" here, in the parser. Roslyn produces
// the somewhat more informative "arglist not valid" error.
if (paramsKeyword.Kind() != SyntaxKind.None || outKeyword.Kind() != SyntaxKind.None ||
refKeyword.Kind() != SyntaxKind.None || thisKeyword.Kind() != SyntaxKind.None)
if (paramsKeyword.Kind() != SyntaxKind.None ||
argPassingKeyword.Kind() != SyntaxKind.None ||
thisKeyword.Kind() != SyntaxKind.None)
{
// CS1669: __arglist is not valid in this context
diagnostics.Add(ErrorCode.ERR_IllegalVarArgs, arglistToken.GetLocation());
......@@ -59,13 +59,12 @@ internal static class ParameterHelpers
Debug.Assert(parameterSyntax.Type != null);
var parameterType = binder.BindType(parameterSyntax.Type, diagnostics);
if (!allowRefOrOut && (refKind != RefKind.None))
if (!allowRefOrOut && (refKind == RefKind.Ref || refKind == RefKind.Out))
{
var outOrRefKeyword = (outKeyword.Kind() != SyntaxKind.None) ? outKeyword : refKeyword;
Debug.Assert(outOrRefKeyword.Kind() != SyntaxKind.None);
Debug.Assert(argPassingKeyword.Kind() != SyntaxKind.None);
// error CS0631: ref and out are not valid in this context
diagnostics.Add(ErrorCode.ERR_IllegalRefParam, outOrRefKeyword.GetLocation());
diagnostics.Add(ErrorCode.ERR_IllegalRefParam, argPassingKeyword.GetLocation());
}
var parameter = SourceParameterSymbol.Create(
......@@ -178,26 +177,20 @@ internal static class ParameterHelpers
Conversion conversion = binder.Conversions.ClassifyImplicitConversionFromExpression(defaultExpression, parameterType, ref useSiteDiagnostics);
diagnostics.Add(defaultExpression.Syntax, useSiteDiagnostics);
SyntaxToken outKeyword;
SyntaxToken refKeyword;
SyntaxToken argPassingKeyword;
SyntaxToken paramsKeyword;
SyntaxToken thisKeyword;
GetModifiers(parameterSyntax.Modifiers, out outKeyword, out refKeyword, out paramsKeyword, out thisKeyword);
var refKind = GetModifiers(parameterSyntax.Modifiers, out argPassingKeyword, out paramsKeyword, out thisKeyword);
// CONSIDER: We are inconsistent here regarding where the error is reported; is it
// CONSIDER: reported on the parameter name, or on the value of the initializer?
// CONSIDER: Consider making this consistent.
if (outKeyword.Kind() == SyntaxKind.OutKeyword)
//PROTOTYPE(refReadonly): do we allow optional values for "In" parameters?
if (refKind != RefKind.None)
{
// error CS1741: A ref or out parameter cannot have a default value
diagnostics.Add(ErrorCode.ERR_RefOutDefaultValue, outKeyword.GetLocation());
hasErrors = true;
}
else if (refKeyword.Kind() == SyntaxKind.RefKeyword)
{
// error CS1741: A ref or out parameter cannot have a default value
diagnostics.Add(ErrorCode.ERR_RefOutDefaultValue, refKeyword.GetLocation());
diagnostics.Add(ErrorCode.ERR_RefOutDefaultValue, argPassingKeyword.GetLocation());
hasErrors = true;
}
else if (paramsKeyword.Kind() == SyntaxKind.ParamsKeyword)
......@@ -344,12 +337,11 @@ internal static MethodSymbol FindContainingGenericMethod(Symbol symbol)
return null;
}
private static RefKind GetModifiers(SyntaxTokenList modifiers, out SyntaxToken outKeyword, out SyntaxToken refKeyword, out SyntaxToken paramsKeyword, out SyntaxToken thisKeyword)
private static RefKind GetModifiers(SyntaxTokenList modifiers, out SyntaxToken argPassingKeyword, out SyntaxToken paramsKeyword, out SyntaxToken thisKeyword)
{
var refKind = RefKind.None;
outKeyword = default(SyntaxToken);
refKeyword = default(SyntaxToken);
argPassingKeyword = default(SyntaxToken);
paramsKeyword = default(SyntaxToken);
thisKeyword = default(SyntaxToken);
......@@ -358,19 +350,26 @@ private static RefKind GetModifiers(SyntaxTokenList modifiers, out SyntaxToken o
switch (modifier.Kind())
{
case SyntaxKind.OutKeyword:
outKeyword = modifier;
argPassingKeyword = modifier;
if (refKind == RefKind.None)
{
refKind = RefKind.Out;
}
break;
case SyntaxKind.RefKeyword:
refKeyword = modifier;
argPassingKeyword = modifier;
if (refKind == RefKind.None)
{
refKind = RefKind.Ref;
}
break;
case SyntaxKind.InKeyword:
argPassingKeyword = modifier;
if (refKind == RefKind.None)
{
refKind = RefKind.RefReadOnly;
}
break;
case SyntaxKind.ParamsKeyword:
paramsKeyword = modifier;
break;
......
......@@ -136,7 +136,11 @@ internal static TypeSyntax SkipRef(this TypeSyntax syntax, out RefKind refKind)
refKind = RefKind.None;
if (syntax.Kind() == SyntaxKind.RefType)
{
refKind = RefKind.Ref;
var refType = (RefTypeSyntax)syntax;
refKind = refType.ReadOnlyKeyword.Kind() == SyntaxKind.ReadOnlyKeyword ?
RefKind.RefReadOnly :
RefKind.Ref;
syntax = ((RefTypeSyntax)syntax).Type;
}
......
......@@ -71,6 +71,7 @@
<Compile Include="Attributes\AttributeTests_Synthesized.cs" />
<Compile Include="Attributes\AttributeTests_Tuples.cs" />
<Compile Include="Attributes\AttributeTests_WellKnownAttributes.cs" />
<Compile Include="CodeGen\CodeGenInParametersTests.cs" />
<Compile Include="CodeGen\CodeGenCapturing.cs" />
<Compile Include="CodeGen\CodeGenRefReadonlyReturnTests.cs" />
<Compile Include="Emit\BinaryCompatibility.cs" />
......
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
[CompilerTrait(CompilerFeature.ReadonlyReferences)]
public class CodeGenInParametersTests : CompilingTestBase
{
[Fact]
public void RefReturnArrayAccess()
{
var text = @"
class Program
{
static ref readonly int M(in int x)
{
return ref x;
}
}
";
var comp = CompileAndVerify(text, parseOptions: TestOptions.Regular, verify: false);
comp.VerifyIL("Program.M(ref readonly int)", @"
{
// Code size 2 (0x2)
.maxstack 1
IL_0000: ldarg.0
IL_0001: ret
}");
}
}
}
......@@ -5461,6 +5461,208 @@ private static void RefReturnInternal(Compilation comp)
SymbolDisplayPartKind.Punctuation);
}
[Fact]
public void RefReadonlyReturn()
{
var sourceA =
@"public delegate ref readonly int D();
public class C
{
public ref readonly int F(in int i) => ref i;
int _p;
public ref readonly int P => ref _p;
public ref readonly int this[in int i] => ref _p;
}";
var compA = CreateCompilationWithMscorlib(sourceA);
compA.VerifyDiagnostics();
var refA = compA.EmitToImageReference();
// From C# symbols.
RefReadonlyReturnInternal(compA);
var compB = CreateVisualBasicCompilation(GetUniqueName(), "", referencedAssemblies: new[] { MscorlibRef, refA });
compB.VerifyDiagnostics();
// From VB symbols.
//PROTOTYPE(refReadonly): metadata emit and VB NYI
//RefReadonlyReturnInternal(compB);
}
private static void RefReadonlyReturnInternal(Compilation comp)
{
var formatBase = new SymbolDisplayFormat(
memberOptions: SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeType,
parameterOptions: SymbolDisplayParameterOptions.IncludeType | SymbolDisplayParameterOptions.IncludeParamsRefOut,
propertyStyle: SymbolDisplayPropertyStyle.ShowReadWriteDescriptor,
delegateStyle: SymbolDisplayDelegateStyle.NameAndSignature,
miscellaneousOptions: SymbolDisplayMiscellaneousOptions.UseSpecialTypes);
var formatWithoutRef = formatBase.WithMemberOptions(
SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeType);
var formatWithRef = formatBase.WithMemberOptions(
SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeType | SymbolDisplayMemberOptions.IncludeRef);
var formatWithoutTypeWithRef = formatBase.WithMemberOptions(
SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeRef);
var global = comp.GlobalNamespace;
var type = global.GetTypeMembers("C").Single();
var method = type.GetMembers("F").Single();
var property = type.GetMembers("P").Single();
var indexer = type.GetMembers().Where(m => m.Kind == SymbolKind.Property && ((IPropertySymbol)m).IsIndexer).Single();
var @delegate = global.GetTypeMembers("D").Single();
// Method without IncludeRef.
Verify(
SymbolDisplay.ToDisplayParts(method, formatWithoutRef),
"int F(ref readonly int)",
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.MethodName,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Punctuation);
// Property without IncludeRef.
Verify(
SymbolDisplay.ToDisplayParts(property, formatWithoutRef),
"int P { get; }",
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.PropertyName,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Punctuation);
// Indexer without IncludeRef.
Verify(
SymbolDisplay.ToDisplayParts(indexer, formatWithoutRef),
"int this[ref readonly int] { get; }",
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Punctuation);
// Delegate without IncludeRef.
Verify(
SymbolDisplay.ToDisplayParts(@delegate, formatWithoutRef),
"int D()",
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.DelegateName,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Punctuation);
// Method with IncludeRef.
Verify(
SymbolDisplay.ToDisplayParts(method, formatWithRef),
"ref readonly int F(ref readonly int)",
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.MethodName,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Punctuation);
// Property with IncludeRef.
Verify(
SymbolDisplay.ToDisplayParts(property, formatWithRef),
"ref readonly int P { get; }",
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.PropertyName,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Punctuation);
// Indexer with IncludeRef.
Verify(
SymbolDisplay.ToDisplayParts(indexer, formatWithRef),
"ref readonly int this[ref readonly int] { get; }",
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Punctuation);
// Delegate with IncludeRef.
Verify(
SymbolDisplay.ToDisplayParts(@delegate, formatWithRef),
"ref readonly int D()",
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.DelegateName,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Punctuation);
// Method without IncludeType, with IncludeRef.
Verify(
SymbolDisplay.ToDisplayParts(method, formatWithoutTypeWithRef),
"F(ref readonly int)",
SymbolDisplayPartKind.MethodName,
SymbolDisplayPartKind.Punctuation,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword,
SymbolDisplayPartKind.Punctuation);
}
[WorkItem(5002, "https://github.com/dotnet/roslyn/issues/5002")]
[Fact]
public void AliasInSpeculativeSemanticModel()
......@@ -5593,5 +5795,70 @@ async unsafe Task<int> Local(ref int* x, out char? c)
SymbolDisplayPartKind.ParameterName, // c
SymbolDisplayPartKind.Punctuation); // )
}
[Fact]
[CompilerTrait(CompilerFeature.LocalFunctions)]
public void LocalFunction3()
{
var srcTree = SyntaxFactory.ParseSyntaxTree(@"
using System.Threading.Tasks;
class C
{
void M()
{
async unsafe Task<int> Local(in int* x, out char? c)
{
}
}
}");
var root = srcTree.GetRoot();
var comp = CreateCompilationWithMscorlib45(new[] { srcTree });
var semanticModel = comp.GetSemanticModel(comp.SyntaxTrees.Single());
var local = root.DescendantNodes()
.Where(n => n.Kind() == SyntaxKind.LocalFunctionStatement)
.Single();
var localSymbol = Assert.IsType<LocalFunctionSymbol>(
semanticModel.GetDeclaredSymbol(local));
Verify(localSymbol.ToDisplayParts(SymbolDisplayFormat.TestFormat),
"System.Threading.Tasks.Task<System.Int32> Local(ref readonly System.Int32* x, out System.Char? c)",
SymbolDisplayPartKind.NamespaceName, // System
SymbolDisplayPartKind.Punctuation, // .
SymbolDisplayPartKind.NamespaceName, // Threading
SymbolDisplayPartKind.Punctuation, // .
SymbolDisplayPartKind.NamespaceName, // Tasks
SymbolDisplayPartKind.Punctuation, // .
SymbolDisplayPartKind.ClassName, // Task
SymbolDisplayPartKind.Punctuation, // <
SymbolDisplayPartKind.NamespaceName, // System
SymbolDisplayPartKind.Punctuation, // .
SymbolDisplayPartKind.StructName, // Int32
SymbolDisplayPartKind.Punctuation, // >
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.MethodName, // Local
SymbolDisplayPartKind.Punctuation, // (
SymbolDisplayPartKind.Keyword, // ref
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword, // readonly
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.NamespaceName, // System
SymbolDisplayPartKind.Punctuation, // .
SymbolDisplayPartKind.StructName, // Int32
SymbolDisplayPartKind.Punctuation, // *
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.ParameterName, // x
SymbolDisplayPartKind.Punctuation, // ,
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.Keyword, // out
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.NamespaceName, // System
SymbolDisplayPartKind.Punctuation, // .
SymbolDisplayPartKind.StructName, // Char
SymbolDisplayPartKind.Punctuation, // ?
SymbolDisplayPartKind.Space,
SymbolDisplayPartKind.ParameterName, // c
SymbolDisplayPartKind.Punctuation); // )
}
}
}
......@@ -729,6 +729,8 @@ public void RefReturningDelegate()
var global = comp.GlobalNamespace;
var d = global.GetMembers("D")[0] as NamedTypeSymbol;
Assert.True(d.DelegateInvokeMethod.ReturnsByRef);
Assert.False(d.DelegateInvokeMethod.ReturnsByRefReadonly);
Assert.Equal(RefKind.Ref, d.DelegateInvokeMethod.RefKind);
Assert.Equal(RefKind.Ref, ((MethodSymbol)d.GetMembers("EndInvoke").Single()).RefKind);
}
......@@ -737,16 +739,54 @@ public void RefReturningDelegate()
[CompilerTrait(CompilerFeature.ReadonlyReferences)]
public void RefReadonlyReturningDelegate()
{
var source = @"delegate ref readonly int D();";
var source = @"delegate ref readonly int D(in int arg);";
var comp = CreateCompilationWithMscorlib45(source);
comp.VerifyDiagnostics();
var global = comp.GlobalNamespace;
var d = global.GetMembers("D")[0] as NamedTypeSymbol;
//PROTOTYPE(readonlyRefs): this will work as regular RefKind.Ref for now since binding is NYI
Assert.Equal(RefKind.Ref, d.DelegateInvokeMethod.RefKind);
Assert.Equal(RefKind.Ref, ((MethodSymbol)d.GetMembers("EndInvoke").Single()).RefKind);
Assert.False(d.DelegateInvokeMethod.ReturnsByRef);
Assert.True(d.DelegateInvokeMethod.ReturnsByRefReadonly);
Assert.Equal(RefKind.RefReadOnly, d.DelegateInvokeMethod.RefKind);
Assert.Equal(RefKind.RefReadOnly, ((MethodSymbol)d.GetMembers("EndInvoke").Single()).RefKind);
Assert.Equal(RefKind.RefReadOnly, d.DelegateInvokeMethod.Parameters[0].RefKind);
}
[Fact]
public void ReadonlyRefsInlambda()
{
var source = @"
class C
{
public delegate ref readonly T DD<T>(in T arg);
public static void Main()
{
DD<int> d1 = (in int a) => ref a;
DD<int> d2 = delegate(in int a){return ref a;};
}
}";
var tree = SyntaxFactory.ParseSyntaxTree(source, options: TestOptions.Regular);
var compilation = CreateCompilationWithMscorlib45(new SyntaxTree[] { tree }).VerifyDiagnostics();
var model = compilation.GetSemanticModel(tree);
ExpressionSyntax lambdaSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<ParenthesizedLambdaExpressionSyntax>().Single();
var lambda = (LambdaSymbol)model.GetSymbolInfo(lambdaSyntax).Symbol;
Assert.False(lambda.ReturnsByRef);
Assert.True(lambda.ReturnsByRefReadonly);
Assert.Equal(lambda.Parameters[0].RefKind, RefKind.RefReadOnly);
lambdaSyntax = tree.GetCompilationUnitRoot().DescendantNodes().OfType<AnonymousMethodExpressionSyntax>().Single();
lambda = (LambdaSymbol)model.GetSymbolInfo(lambdaSyntax).Symbol;
Assert.False(lambda.ReturnsByRef);
Assert.True(lambda.ReturnsByRefReadonly);
Assert.Equal(lambda.Parameters[0].RefKind, RefKind.RefReadOnly);
}
}
}
......@@ -526,8 +526,38 @@ class C
Assert.NotNull(p.GetMethod);
Assert.False(p.GetMethod.IsImplicitlyDeclared);
Assert.True(p.IsExpressionBodied);
//PROTOTYPE(readonlyRefs): binding is currently NYI so it is "Ref" for now.
Assert.Equal(RefKind.Ref, p.GetMethod.RefKind);
Assert.Equal(RefKind.RefReadOnly, p.GetMethod.RefKind);
Assert.False(p.ReturnsByRef);
Assert.False(p.GetMethod.ReturnsByRef);
Assert.True(p.ReturnsByRefReadonly);
Assert.True(p.GetMethod.ReturnsByRefReadonly);
}
[Fact]
public void ReadonlyRefReturningExpressionBodiedIndexer()
{
var comp = CreateCompilationWithMscorlib45(@"
class C
{
int field = 0;
public ref readonly int this[in int arg] => ref field;
}");
comp.VerifyDiagnostics();
var global = comp.GlobalNamespace;
var c = global.GetTypeMember("C");
var p = c.GetMember<SourcePropertySymbol>("this[]");
Assert.Null(p.SetMethod);
Assert.NotNull(p.GetMethod);
Assert.False(p.GetMethod.IsImplicitlyDeclared);
Assert.True(p.IsExpressionBodied);
Assert.Equal(RefKind.RefReadOnly, p.GetMethod.RefKind);
Assert.Equal(RefKind.RefReadOnly, p.GetMethod.Parameters[0].RefKind);
Assert.False(p.ReturnsByRef);
Assert.False(p.GetMethod.ReturnsByRef);
Assert.True(p.ReturnsByRefReadonly);
Assert.True(p.GetMethod.ReturnsByRefReadonly);
}
}
}
......@@ -135,10 +135,11 @@ static void Use<T>(T dummy)
}
}
";
//PROTOTYPE(readonlyRefs): binding now falls back on regular "Ref", otherwise there should be one more error on the local declaration
var comp = CreateCompilationWithMscorlib45(text, new[] { ValueTupleRef, SystemRuntimeFacadeRef });
comp.VerifyDiagnostics(
// (7,9): error CS1073: Unexpected token 'ref'
// ref readonly int local = ref (new int[1])[0];
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(7, 9),
// (9,10): error CS1073: Unexpected token 'ref'
// (ref readonly int, ref readonly int Alice)? t = null;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(9, 10),
......@@ -147,7 +148,8 @@ static void Use<T>(T dummy)
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(9, 28),
// (11,41): error CS1073: Unexpected token 'ref'
// System.Collections.Generic.List<ref readonly int> x = null;
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(11, 41));
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(11, 41)
);
}
}
}
......@@ -791,7 +791,8 @@ ImmutableArray<ICustomModifier> RefCustomModifiers
{
get;
}
//PROTOTYPE(readonlyRefs): need to add another API to distinguish readonly, for now treat them the same
/// <summary>
/// True if the return value is passed by reference (using a managed pointer).
/// </summary>
......
......@@ -93,8 +93,8 @@ Microsoft.CodeAnalysis.IDiscardSymbol.Type.get -> Microsoft.CodeAnalysis.ITypeSy
Microsoft.CodeAnalysis.IFieldSymbol.CorrespondingTupleField.get -> Microsoft.CodeAnalysis.IFieldSymbol
Microsoft.CodeAnalysis.ILocalSymbol.IsRef.get -> bool
Microsoft.CodeAnalysis.IMethodSymbol.RefCustomModifiers.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.CustomModifier>
Microsoft.CodeAnalysis.IMethodSymbol.ReturnsByRefReadonly.get -> bool
Microsoft.CodeAnalysis.IMethodSymbol.ReturnsByRef.get -> bool
Microsoft.CodeAnalysis.IMethodSymbol.ReturnsByRefReadonly.get -> bool
Microsoft.CodeAnalysis.INamedTypeSymbol.GetTypeArgumentCustomModifiers(int ordinal) -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.CustomModifier>
Microsoft.CodeAnalysis.INamedTypeSymbol.IsComImport.get -> bool
Microsoft.CodeAnalysis.INamedTypeSymbol.TupleElements.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.IFieldSymbol>
......@@ -110,6 +110,7 @@ Microsoft.CodeAnalysis.IOperation.Type.get -> Microsoft.CodeAnalysis.ITypeSymbol
Microsoft.CodeAnalysis.IParameterSymbol.RefCustomModifiers.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.CustomModifier>
Microsoft.CodeAnalysis.IPropertySymbol.RefCustomModifiers.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.CustomModifier>
Microsoft.CodeAnalysis.IPropertySymbol.ReturnsByRef.get -> bool
Microsoft.CodeAnalysis.IPropertySymbol.ReturnsByRefReadonly.get -> bool
Microsoft.CodeAnalysis.ITypeSymbol.IsTupleType.get -> bool
Microsoft.CodeAnalysis.MethodKind.LocalFunction = 17 -> Microsoft.CodeAnalysis.MethodKind
Microsoft.CodeAnalysis.OperationKind
......
......@@ -67,7 +67,7 @@ public enum SymbolDisplayMemberOptions
IncludeConstantValue = 1 << 6,
/// <summary>
/// Includes the <c>ref</c>, <c>ByRef</c> keyword for ref-returning methods and properties/indexers.
/// Includes the <c>ref</c>, <c>ref readonly</c>, <c>ByRef</c> keywords for ref-returning methods and properties/indexers.
/// </summary>
IncludeRef = 1 << 7,
}
......
......@@ -29,7 +29,7 @@ public enum SymbolDisplayParameterOptions
IncludeExtensionThis = 1 << 0,
/// <summary>
/// Includes the <c>params</c>, <c>ref</c>, <c>out</c>, <c>ByRef</c>, <c>ByVal</c> keywords before parameters.
/// Includes the <c>params</c>, <c>ref</c>, <c>ref readonly</c>, <c>out</c>, <c>ByRef</c>, <c>ByVal</c> keywords before parameters.
/// </summary>
IncludeParamsRefOut = 1 << 1,
......
......@@ -75,7 +75,11 @@ public interface IMethodSymbol : ISymbol
/// </summary>
bool ReturnsByRef { get; }
// PROTOTYPE(readonlyRefs): this is very preliminary. We need to have _some_ API for now.
// PROTOTYPE(readonlyRefs): this is very preliminary.
// We may actually need 3 APIs here:
// 1) Does it return an ordinary writeable ref?
// 2) Does it return a readonly ref?
// 3) Does it return any kind of ref?
/// <summary>
/// Returns true if this method returns by ref readonly.
/// </summary>
......
......@@ -40,6 +40,16 @@ public interface IPropertySymbol : ISymbol
/// </summary>
bool ReturnsByRef { get; }
// PROTOTYPE(readonlyRefs): this is very preliminary.
// We may actually need 3 APIs here:
// 1) Does it return an ordinary writeable ref?
// 2) Does it return a readonly ref?
// 3) Does it return any kind of ref?
/// <summary>
/// Returns true if this property returns by reference a readonly variable.
/// </summary>
bool ReturnsByRefReadonly { get; }
/// <summary>
/// The type of the property.
/// </summary>
......
......@@ -949,7 +949,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Get
End Property
Private ReadOnly Property IMethodSymbol_ReturnsByRefReadonly As Boolean Implements IMethodSymbol.ReturnsByRefReadonly
Private ReadOnly Property IMethodSymbol_ReturnsByReadonlyRef As Boolean Implements IMethodSymbol.ReturnsByRefReadonly
Get
' PROTOTYPE(readonlyRefs): NYI
Return False
......
......@@ -506,6 +506,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Get
End Property
Private ReadOnly Property IPropertySymbol_ByRefReturnIsReadonly As Boolean Implements IPropertySymbol.ReturnsByRefReadonly
Get
' PROTOTYPE(readonlyRef): NYI
Return False
End Get
End Property
Private ReadOnly Property IPropertySymbol_Type As ITypeSymbol Implements IPropertySymbol.Type
Get
Return Me.Type
......
......@@ -75,6 +75,14 @@ public bool ReturnsByRef
}
}
public bool ReturnsByRefReadonly
{
get
{
return _symbol.ReturnsByRefReadonly;
}
}
public IPropertySymbol OverriddenProperty
{
get
......
......@@ -99,6 +99,14 @@ public bool ReturnsByRef
}
}
public bool ReturnsByRefReadonly
{
get
{
return this.GetMethod != null && this.GetMethod.ReturnsByRefReadonly;
}
}
public new IPropertySymbol OriginalDefinition
{
get
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册