Skip to content

Commit 459ce89

Browse files
stbau04Stephan Bauer
andauthored
Remove warning from 'in enum' extension methods (#80708)
Fixes #73746 --------- Co-authored-by: Stephan Bauer <[email protected]>
1 parent e7d28d8 commit 459ce89

File tree

11 files changed

+840
-54
lines changed

11 files changed

+840
-54
lines changed

src/Compilers/CSharp/Portable/Symbols/Extensions/SynthesizedExtensionMarker.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ protected override (TypeWithAnnotations ReturnType, ImmutableArray<ParameterSymb
101101
{
102102
diagnostics.Add(ErrorCode.ERR_RefExtensionParameterMustBeValueTypeOrConstrainedToOne, parameterTypeSyntax);
103103
}
104-
else if (parameterRefKind is RefKind.In or RefKind.RefReadOnlyParameter && parameterType.TypeKind != TypeKind.Struct)
104+
else if (parameterRefKind is RefKind.In or RefKind.RefReadOnlyParameter
105+
&& !parameterType.IsValidInOrRefReadonlyExtensionParameterType())
105106
{
106107
diagnostics.Add(ErrorCode.ERR_InExtensionParameterMustBeValueType, parameterTypeSyntax);
107108
}

src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,13 +389,19 @@ private static bool IsValidExtensionReceiverParameter(ParameterSymbol thisParam)
389389
{
390390
Debug.Assert(thisParam is not null);
391391

392+
if (!thisParam.Type.IsValidExtensionParameterType())
393+
{
394+
return false;
395+
}
396+
392397
// For ref and ref-readonly extension members and classic extension methods, receivers need to be of the correct types to be considered in lookup
393398
if (thisParam.RefKind == RefKind.Ref && !thisParam.Type.IsValueType)
394399
{
395400
return false;
396401
}
397402

398-
if (thisParam.RefKind is RefKind.In or RefKind.RefReadOnlyParameter && thisParam.Type.TypeKind != TypeKind.Struct)
403+
if (thisParam.RefKind is RefKind.In or RefKind.RefReadOnlyParameter
404+
&& !thisParam.Type.IsValidInOrRefReadonlyExtensionParameterType())
399405
{
400406
return false;
401407
}

src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,8 @@ protected sealed override void ExtensionMethodChecks(BindingDiagnosticBag diagno
222222
{
223223
diagnostics.Add(ErrorCode.ERR_RefExtensionMustBeValueTypeOrConstrainedToOne, _location, Name);
224224
}
225-
else if (parameter0RefKind is RefKind.In or RefKind.RefReadOnlyParameter && parameter0Type.TypeKind != TypeKind.Struct)
225+
else if (parameter0RefKind is RefKind.In or RefKind.RefReadOnlyParameter
226+
&& !parameter0Type.Type.IsValidInOrRefReadonlyExtensionParameterType())
226227
{
227228
diagnostics.Add(ErrorCode.ERR_InExtensionMustBeValueType, _location, Name);
228229
}

src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,11 @@ public static bool IsValidExtensionParameterType(this TypeSymbol type)
324324
}
325325
}
326326

327+
public static bool IsValidInOrRefReadonlyExtensionParameterType(this TypeSymbol type)
328+
{
329+
return type is { IsValueType: true, TypeKind: not TypeKind.TypeParameter };
330+
}
331+
327332
public static bool IsInterfaceType(this TypeSymbol type)
328333
{
329334
RoslynDebug.Assert((object)type != null);

src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenInParametersTests.cs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#nullable disable
66

7+
using System.Linq;
8+
using Microsoft.CodeAnalysis.CSharp.Symbols;
79
using Microsoft.CodeAnalysis.CSharp.Syntax;
810
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
911
using Microsoft.CodeAnalysis.Test.Utilities;
@@ -4909,5 +4911,184 @@ .maxstack 1
49094911
var comp = CreateCompilation(src, references: new[] { libChanged.EmitToImageReference(), libUser.EmitToImageReference() });
49104912
CompileAndVerify(comp, expectedOutput: "Report1 11");
49114913
}
4914+
4915+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73746")]
4916+
public void TestExtensionMethodInModifierWithEnumType()
4917+
{
4918+
var source = """
4919+
int i = 0;
4920+
i.M1();
4921+
4922+
E e = (E)0;
4923+
e.M2();
4924+
4925+
enum E;
4926+
4927+
static class Extensions
4928+
{
4929+
public static void M1(this in int e)
4930+
{
4931+
System.Console.WriteLine("int");
4932+
}
4933+
4934+
public static void M2(this in E e)
4935+
{
4936+
System.Console.WriteLine("enum");
4937+
}
4938+
}
4939+
""";
4940+
4941+
var comp = CompileAndVerify(source, symbolValidator: validate, expectedOutput: """
4942+
int
4943+
enum
4944+
""");
4945+
4946+
static void validate(ModuleSymbol m)
4947+
{
4948+
AssertEx.Equal(
4949+
RefKind.In,
4950+
m.GlobalNamespace.GetMember<MethodSymbol>("Extensions.M1").Parameters.Single().RefKind);
4951+
4952+
AssertEx.Equal(
4953+
RefKind.In,
4954+
m.GlobalNamespace.GetMember<MethodSymbol>("Extensions.M2").Parameters.Single().RefKind);
4955+
}
4956+
}
4957+
4958+
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73746")]
4959+
public void TestExtensionBlockInModifierWithEnumType()
4960+
{
4961+
var source = """
4962+
int i = 0;
4963+
i.M1();
4964+
_ = i.P1;
4965+
i.P1 = 0;
4966+
_ = i + new object();
4967+
4968+
E e = (E)0;
4969+
e.M1();
4970+
_ = e.P1;
4971+
e.P1 = 0;
4972+
_ = e + new object();
4973+
4974+
enum E;
4975+
4976+
static class IntExtensions
4977+
{
4978+
extension(in int i)
4979+
{
4980+
public void M1()
4981+
{
4982+
System.Console.WriteLine("method_int");
4983+
}
4984+
4985+
public int P1
4986+
{
4987+
get
4988+
{
4989+
System.Console.WriteLine("property_get_int");
4990+
return 0;
4991+
}
4992+
4993+
set
4994+
{
4995+
System.Console.WriteLine("property_set_int");
4996+
}
4997+
}
4998+
4999+
public static int operator +(in int a, object b)
5000+
{
5001+
System.Console.WriteLine("operator_int");
5002+
return 0;
5003+
}
5004+
}
5005+
}
5006+
5007+
static class EnumExtensions
5008+
{
5009+
extension(in E e)
5010+
{
5011+
public void M1()
5012+
{
5013+
System.Console.WriteLine("method_enum");
5014+
}
5015+
5016+
public int P1
5017+
{
5018+
get
5019+
{
5020+
System.Console.WriteLine("property_get_enum");
5021+
return 0;
5022+
}
5023+
5024+
set
5025+
{
5026+
System.Console.WriteLine("property_set_enum");
5027+
}
5028+
}
5029+
5030+
public static int operator +(in E a, object b)
5031+
{
5032+
System.Console.WriteLine("operator_enum");
5033+
return 0;
5034+
}
5035+
}
5036+
}
5037+
""";
5038+
5039+
var comp = CompileAndVerify(source, symbolValidator: validate, expectedOutput: """
5040+
method_int
5041+
property_get_int
5042+
property_set_int
5043+
operator_int
5044+
method_enum
5045+
property_get_enum
5046+
property_set_enum
5047+
operator_enum
5048+
""");
5049+
5050+
static void validate(ModuleSymbol m)
5051+
{
5052+
AssertEx.Equal(
5053+
RefKind.In,
5054+
m.GlobalNamespace.GetTypeMember("IntExtensions").GetTypeMembers().Single().ExtensionParameter.RefKind);
5055+
5056+
AssertEx.Equal(
5057+
RefKind.In,
5058+
m.GlobalNamespace.GetMember<MethodSymbol>("IntExtensions.M1").Parameters.Single().RefKind);
5059+
5060+
AssertEx.Equal(
5061+
RefKind.In,
5062+
m.GlobalNamespace.GetMember<MethodSymbol>("IntExtensions.get_P1").Parameters.Single().RefKind);
5063+
5064+
AssertEx.Equal(
5065+
RefKind.In,
5066+
m.GlobalNamespace.GetMember<MethodSymbol>("IntExtensions.set_P1").Parameters.First().RefKind);
5067+
5068+
AssertEx.Equal(
5069+
RefKind.In,
5070+
m.GlobalNamespace.GetMember<MethodSymbol>("IntExtensions.op_Addition").Parameters.First().RefKind);
5071+
5072+
AssertEx.Equal(
5073+
RefKind.In,
5074+
m.GlobalNamespace.GetTypeMember("EnumExtensions").GetTypeMembers().Single().ExtensionParameter.RefKind);
5075+
5076+
AssertEx.Equal(
5077+
RefKind.In,
5078+
m.GlobalNamespace.GetMember<MethodSymbol>("EnumExtensions.M1").Parameters.Single().RefKind);
5079+
5080+
AssertEx.Equal(
5081+
RefKind.In,
5082+
m.GlobalNamespace.GetMember<MethodSymbol>("EnumExtensions.get_P1").Parameters.Single().RefKind);
5083+
5084+
AssertEx.Equal(
5085+
RefKind.In,
5086+
m.GlobalNamespace.GetMember<MethodSymbol>("EnumExtensions.set_P1").Parameters.First().RefKind);
5087+
5088+
AssertEx.Equal(
5089+
RefKind.In,
5090+
m.GlobalNamespace.GetMember<MethodSymbol>("EnumExtensions.op_Addition").Parameters.First().RefKind);
5091+
}
5092+
}
49125093
}
49135094
}

0 commit comments

Comments
 (0)