Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4880,8 +4880,8 @@ private void ParseParameterModifiers(SyntaxListBuilder modifiers, bool isFunctio
{
modifiers.Add(scopedKeyword);

// Look if ref/out/in/readonly are next
while (this.CurrentToken.Kind is SyntaxKind.RefKeyword or SyntaxKind.OutKeyword or SyntaxKind.InKeyword or SyntaxKind.ReadOnlyKeyword)
// Look if ref/out/in/readonly/this are next
while (this.CurrentToken.Kind is SyntaxKind.RefKeyword or SyntaxKind.OutKeyword or SyntaxKind.InKeyword or SyntaxKind.ReadOnlyKeyword or SyntaxKind.ThisKeyword)
{
modifiers.Add(this.EatToken());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,66 @@ [ScopedRef] scoped R r
});
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78491")]
public void EmitAttribute_ExtensionMethodParameters_ScopedInThis()
{
var source =
@"static class Extensions
{
public static void F(scoped in this int i) { }
}";
var comp = CreateCompilation(source);
var expected =
@"void Extensions.F(this scoped in System.Int32 i)
[ScopedRef] scoped in System.Int32 i
";
CompileAndVerify(comp, symbolValidator: module =>
{
Assert.Equal("System.Runtime.CompilerServices.ScopedRefAttribute", GetScopedRefType(module).ToTestDisplayString());
AssertScopedRefAttributes(module, expected);
});
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78491")]
public void EmitAttribute_ExtensionMethodParameters_ScopedRefThis()
{
var source =
@"static class Extensions
{
public static void F(scoped ref this int i) { }
}";
var comp = CreateCompilation(source);
var expected =
@"void Extensions.F(this scoped ref System.Int32 i)
[ScopedRef] scoped ref System.Int32 i
";
CompileAndVerify(comp, symbolValidator: module =>
{
Assert.Equal("System.Runtime.CompilerServices.ScopedRefAttribute", GetScopedRefType(module).ToTestDisplayString());
AssertScopedRefAttributes(module, expected);
});
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78491")]
public void EmitAttribute_ExtensionMethodParameters_ScopedRefReadonlyThis()
{
var source =
@"static class Extensions
{
public static void F(scoped ref readonly this int i) { }
}";
var comp = CreateCompilation(source);
var expected =
@"void Extensions.F(this scoped ref readonly System.Int32 i)
[ScopedRef] scoped ref readonly System.Int32 i
";
CompileAndVerify(comp, symbolValidator: module =>
{
Assert.Equal("System.Runtime.CompilerServices.ScopedRefAttribute", GetScopedRefType(module).ToTestDisplayString());
AssertScopedRefAttributes(module, expected);
});
}

private static void AssertScopedRefAttributes(ModuleSymbol module, string expected)
{
var actual = ScopedRefAttributesVisitor.GetString((PEModuleSymbol)module);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14944,5 +14944,144 @@ public void Catch_03()
}
EOF();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78491")]
public void ScopedWithThis_01()
{
var source = "void M(scoped in this int p);";
UsingDeclaration(source);

N(SyntaxKind.MethodDeclaration);
{
N(SyntaxKind.PredefinedType);
{
N(SyntaxKind.VoidKeyword);
}
N(SyntaxKind.IdentifierToken, "M");
N(SyntaxKind.ParameterList);
{
N(SyntaxKind.OpenParenToken);
N(SyntaxKind.Parameter);
{
N(SyntaxKind.ScopedKeyword);
N(SyntaxKind.InKeyword);
N(SyntaxKind.ThisKeyword);
N(SyntaxKind.PredefinedType);
{
N(SyntaxKind.IntKeyword);
}
N(SyntaxKind.IdentifierToken, "p");
}
N(SyntaxKind.CloseParenToken);
}
N(SyntaxKind.SemicolonToken);
}
EOF();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78491")]
public void ScopedWithThis_02()
{
var source = "void M(scoped ref this int p);";
UsingDeclaration(source);

N(SyntaxKind.MethodDeclaration);
{
N(SyntaxKind.PredefinedType);
{
N(SyntaxKind.VoidKeyword);
}
N(SyntaxKind.IdentifierToken, "M");
N(SyntaxKind.ParameterList);
{
N(SyntaxKind.OpenParenToken);
N(SyntaxKind.Parameter);
{
N(SyntaxKind.ScopedKeyword);
N(SyntaxKind.RefKeyword);
N(SyntaxKind.ThisKeyword);
N(SyntaxKind.PredefinedType);
{
N(SyntaxKind.IntKeyword);
}
N(SyntaxKind.IdentifierToken, "p");
}
N(SyntaxKind.CloseParenToken);
}
N(SyntaxKind.SemicolonToken);
}
EOF();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78491")]
public void ScopedWithThis_03()
{
// Test scoped ref readonly this
var source = "void M(scoped ref readonly this int p);";
UsingDeclaration(source);

N(SyntaxKind.MethodDeclaration);
{
N(SyntaxKind.PredefinedType);
{
N(SyntaxKind.VoidKeyword);
}
N(SyntaxKind.IdentifierToken, "M");
N(SyntaxKind.ParameterList);
{
N(SyntaxKind.OpenParenToken);
N(SyntaxKind.Parameter);
{
N(SyntaxKind.ScopedKeyword);
N(SyntaxKind.RefKeyword);
N(SyntaxKind.ReadOnlyKeyword);
N(SyntaxKind.ThisKeyword);
N(SyntaxKind.PredefinedType);
{
N(SyntaxKind.IntKeyword);
}
N(SyntaxKind.IdentifierToken, "p");
}
N(SyntaxKind.CloseParenToken);
}
N(SyntaxKind.SemicolonToken);
}
EOF();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78491")]
public void ScopedWithThis_04()
{
// Test that this scoped in still works
var source = "void M(this scoped in int p);";
UsingDeclaration(source);

N(SyntaxKind.MethodDeclaration);
{
N(SyntaxKind.PredefinedType);
{
N(SyntaxKind.VoidKeyword);
}
N(SyntaxKind.IdentifierToken, "M");
N(SyntaxKind.ParameterList);
{
N(SyntaxKind.OpenParenToken);
N(SyntaxKind.Parameter);
{
N(SyntaxKind.ThisKeyword);
N(SyntaxKind.ScopedKeyword);
N(SyntaxKind.InKeyword);
N(SyntaxKind.PredefinedType);
{
N(SyntaxKind.IntKeyword);
}
N(SyntaxKind.IdentifierToken, "p");
}
N(SyntaxKind.CloseParenToken);
}
N(SyntaxKind.SemicolonToken);
}
EOF();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Remove extra empty lines below. And for the scenarios you've added above, add corresponding tests to AttributeTests_ScopedRef for the scenarios that aren't already covered.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Removed the extra empty lines and added three attribute tests for the extension method scenarios with this keyword combinations in commit af5f4ec.

}
}