Skip to content

API proposal: represent ref fields and scoped parameters and locals #61647

@cston

Description

@cston

This issue is referenced in source/test.

Background and Motivation

Represent ref modifier for fields and the related scoped modifier for parameters and locals (see language proposal).

ref fields:

readonly ref struct Ref<T>
{
    private readonly ref T _t;
    public Ref(ref T t) { _t = ref t; }
}

readonly ref struct ReadOnlyRef<T>
{
    private readonly ref readonly T _t;
    public ReadOnlyRef(ref T t) { _t = ref t; }
}

scoped parameters and locals:

static void F(scoped ref int x, ref int y)
{
    scoped Ref<int> r = new Ref<int>(ref x);
}

Proposed API

Symbols

namespace Microsoft.CodeAnalysis
{
    public interface IFieldSymbol : ISymbol
    {
+       /// <summary>
+       /// Returns the RefKind of the field.
+       /// </summary>
+       RefKind RefKind { get; }

+       /// <summary>
+       /// Custom modifiers associated with the ref modifier, or an empty array if there are none.
+       /// </summary>
+       ImmutableArray<CustomModifier> RefCustomModifiers { get; }
    }

    public interface ILocalSymbol : ISymbol
    {
+       /// <summary>
+       /// Returns true if the local ref or value is scoped to the current method.
+       /// </summary>
+       bool IsScoped { get; }
    }

    public interface IParameterSymbol : ISymbol
    {
+       /// <summary>
+       /// Returns true if the parameter ref or value is scoped to the current method.
+       /// </summary>
+       bool IsScoped { get; }
    }
}

Syntax

SyntaxKind.ScopedKeyword is added.

ScopedTypeSyntax is added that combines a scoped keyword and following type syntax.

If the type following scoped includes a ref, ref readonly, in, or out, the type is represented as a nested RefTypeSyntax.

namespace Microsoft.CodeAnalysis.CSharp
{
    public enum SyntaxKind
    {
+       /// <summary>Represents <see langword="scoped"/>.</summary>
+       ScopedKeyword = 8447,
    }

    public class SyntaxFactory
    {
+       public static ScopedTypeSyntax ScopedType(SyntaxToken scopedKeyword, TypeSyntax type);
    }
}

namespace Microsoft.CodeAnalysis.CSharp.Syntax
{
+   public sealed class ScopedTypeSyntax : TypeSyntax
+   {
+       public SyntaxToken ScopedKeyword { get; }
+       public TypeSyntax Type { get; }
+
+       public ScopedTypeSyntax Update(SyntaxToken scopedKeyword, TypeSyntax type);
+
+       public ScopedTypeSyntax WithScopedKeyword(SyntaxToken scopedKeyword);
+       public ScopedTypeSyntax WithType(TypeSyntax type);
+   }
}

Metadata encoding

ScopedRefAttribute is used by the compiler to emit scoped modifiers to metadata.

The attribute type definition is synthesized by the compiler if missing from the compilation.

namespace System.Runtime.CompilerServices
{
+   [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
+   internal sealed class ScopedRefAttribute : Attribute
+   {
+   }
}

Usage Examples

Using RefTypeSyntax is a change for ParameterSyntax which currently represents ref keywords in ParameterSyntax.Modifiers. The proposal is to use RefTypeSyntax for ref keywords in parameters within scoped types only, to avoid a breaking change for C#10 syntax.

For example, the parameters from static void M(ref int x, scoped ref int y) will be represented as:

SyntaxFactory.ParameterList(
    SyntaxFactory.Parameter(
        modifiers: SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.RefKeyword)),
        type: SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword)),
        identifier: "x"),
    SyntaxFactory.Parameter(
        modifiers: default,
        type: SyntaxFactory.ScopedType(
            SyntaxFactory.Token(SyntaxKind.ScopedKeyword),
            SyntaxFactory.RefType(
                SyntaxFactory.Token(SyntaxKind.RefKeyword),
                SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntKeyword)))),
        identifier: "y"));

Alternative Designs

Risks

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions