Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow dynamic calls on ref struct receivers #72674

Merged
merged 8 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
7 changes: 7 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,13 @@ private BoundExpression BindDynamicInvocation(
methodGroup.ResultKind);
break;
}

if (receiver.Type.IsRefLikeType)
333fred marked this conversation as resolved.
Show resolved Hide resolved
333fred marked this conversation as resolved.
Show resolved Hide resolved
{
// Cannot perform a dynamic call on a ref struct '{0}'.
Error(diagnostics, ErrorCode.ERR_CannotDynamicInvokeOnRefStruct, receiver.Syntax, receiver.Type);
hasErrors = true;
}
}
}
else
Expand Down
5 changes: 4 additions & 1 deletion src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -7905,4 +7905,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_NoModifiersOnUsing" xml:space="preserve">
<value>Modifiers cannot be placed on using declarations</value>
</data>
</root>
<data name="ERR_CannotDynamicInvokeOnRefStruct" xml:space="preserve">
<value>Cannot perform a dynamic call on a ref struct '{0}'.</value>
</data>
</root>
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2301,10 +2301,15 @@ internal enum ErrorCode
ERR_ParamsCollectionMissingConstructor = 9228,

ERR_NoModifiersOnUsing = 9229,
ERR_CannotDynamicInvokeOnRefStruct = 9230,

#endregion

// Note: you will need to do the following after adding errors:
// 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs)
333fred marked this conversation as resolved.
Show resolved Hide resolved

// Note: you will need to do the following after adding warnings:
// 1) Re-generate compiler code (eng\generate-compiler-code.cmd).
// 2) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs)
}
}
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2431,6 +2431,7 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
case ErrorCode.ERR_ParamsCollectionExtensionAddMethod:
case ErrorCode.ERR_ParamsCollectionMissingConstructor:
case ErrorCode.ERR_NoModifiersOnUsing:
case ErrorCode.ERR_CannotDynamicInvokeOnRefStruct:
return false;
default:
// NOTE: All error codes must be explicitly handled in this switch statement
Expand Down
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

178 changes: 178 additions & 0 deletions src/Compilers/CSharp/Test/Semantic/Semantics/DynamicTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4545,5 +4545,183 @@ class C2 : C1

CompileAndVerify(comp, expectedOutput: "int").VerifyDiagnostics();
}

[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/72606")]
public void RefStructReceiver01()
{
var code = """
var s = new S();
dynamic d = null;

s.M(d);

ref struct S
{
public void M<T>(T t) { }
}
""";

CreateCompilation(code).VerifyDiagnostics(
// (4,1): error CS9230: Cannot perform a dynamic call on a ref struct 'S'.
// s.M(d);
Diagnostic(ErrorCode.ERR_CannotDynamicInvokeOnRefStruct, "s").WithArguments("S").WithLocation(4, 1)
);
}

[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/72606")]
[InlineData("object")]
[InlineData("dynamic")]
public void RefStructReceiver02(string argType)
{
var code = $$"""
var s = new S();
dynamic d = "Hello world";

s.M(d);

ref struct S
{
public void M({{argType}} o) => System.Console.WriteLine(o);
}
""";

var verifier = CompileAndVerify(code, expectedOutput: "Hello world", targetFramework: TargetFramework.StandardAndCSharp);
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", $$"""
{
// Code size 23 (0x17)
.maxstack 2
.locals init (S V_0, //s
object V_1) //d
IL_0000: ldloca.s V_0
IL_0002: initobj "S"
IL_0008: ldstr "Hello world"
IL_000d: stloc.1
IL_000e: ldloca.s V_0
IL_0010: ldloc.1
IL_0011: call "void S.M({{argType}})"
IL_0016: ret
}
""");
}

[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/72606")]
[InlineData("string")]
[InlineData("int")]
public void RefStructReceiver03(string argType)
{
var code = $$"""
var s = new S();
dynamic d = "Hello world";

try
{
s.M(d);
}
catch
{
System.Console.WriteLine("Caught exception");
}

ref struct S
{
public void M({{argType}} o) => System.Console.WriteLine(o);
}
""";

var verifier = CompileAndVerify(code, expectedOutput: argType == "string" ? "Hello world" : "Caught exception", targetFramework: TargetFramework.StandardAndCSharp);
verifier.VerifyDiagnostics();
verifier.VerifyIL("<top-level-statements-entry-point>", $$"""
{
// Code size 101 (0x65)
.maxstack 4
.locals init (S V_0, //s
object V_1) //d
IL_0000: ldloca.s V_0
IL_0002: initobj "S"
IL_0008: ldstr "Hello world"
IL_000d: stloc.1
.try
{
IL_000e: ldloca.s V_0
IL_0010: ldsfld "System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, {{argType}}>> Program.<>o__0.<>p__0"
IL_0015: brtrue.s IL_003b
IL_0017: ldc.i4.0
IL_0018: ldtoken "{{argType}}"
IL_001d: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"
IL_0022: ldtoken "Program"
IL_0027: call "System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)"
IL_002c: call "System.Runtime.CompilerServices.CallSiteBinder Microsoft.CSharp.RuntimeBinder.Binder.Convert(Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, System.Type, System.Type)"
IL_0031: call "System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, {{argType}}>> System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, {{argType}}>>.Create(System.Runtime.CompilerServices.CallSiteBinder)"
IL_0036: stsfld "System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, {{argType}}>> Program.<>o__0.<>p__0"
IL_003b: ldsfld "System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, {{argType}}>> Program.<>o__0.<>p__0"
IL_0040: ldfld "System.Func<System.Runtime.CompilerServices.CallSite, dynamic, {{argType}}> System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, {{argType}}>>.Target"
IL_0045: ldsfld "System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, dynamic, {{argType}}>> Program.<>o__0.<>p__0"
IL_004a: ldloc.1
IL_004b: callvirt "{{argType}} System.Func<System.Runtime.CompilerServices.CallSite, dynamic, {{argType}}>.Invoke(System.Runtime.CompilerServices.CallSite, dynamic)"
IL_0050: call "void S.M({{argType}})"
IL_0055: leave.s IL_0064
}
catch object
{
IL_0057: pop
IL_0058: ldstr "Caught exception"
IL_005d: call "void System.Console.WriteLine(string)"
IL_0062: leave.s IL_0064
}
IL_0064: ret
}
""");
}

[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/72606")]
[InlineData("object")]
[InlineData("dynamic")]
public void RefStructReceiver04(string argType)
{
var code = $$"""
var s = new S();
dynamic d = "Hello world";

s.M(d);

ref struct S
{
public void M({{argType}} o) => System.Console.WriteLine(o);
public void M(string s) => System.Console.WriteLine(s);
}
""";

CreateCompilation(code).VerifyDiagnostics(
// (4,1): error CS9230: Cannot perform a dynamic call on a ref struct 'S'.
// s.M(d);
Diagnostic(ErrorCode.ERR_CannotDynamicInvokeOnRefStruct, "s").WithArguments("S").WithLocation(4, 1)
);
}

[Theory, WorkItem("https://github.com/dotnet/roslyn/issues/72606")]
[InlineData("object")]
[InlineData("dynamic")]
public void RefStructReceiver05(string argType)
{
var code = $$"""
var s = new S();
dynamic d = "Hello world";

s.M(d);

ref struct S
{
public void M({{argType}} o) => System.Console.WriteLine(o);
public void M<T>(T t) => System.Console.WriteLine(t);
}
""";

CreateCompilation(code).VerifyDiagnostics(
// (4,1): error CS9230: Cannot perform a dynamic call on a ref struct 'S'.
// s.M(d);
Diagnostic(ErrorCode.ERR_CannotDynamicInvokeOnRefStruct, "s").WithArguments("S").WithLocation(4, 1)
);
}
}
}
Loading
Loading