diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs index 092fbebdfbf82..138a7cce7d05c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs @@ -353,8 +353,15 @@ private PEParameterSymbol( bool hasNameInMetadata = !string.IsNullOrEmpty(_name); if (!hasNameInMetadata) { - // As was done historically, if the parameter doesn't have a name, we give it the name "value". - _name = "value"; + if (isExtensionMarkerParameter(containingSymbol, ordinal)) + { + _name = ""; + } + else + { + // As was done historically, if the parameter doesn't have a name, we give it the name "value". + _name = "value"; + } } _packedFlags = new PackedFlags(refKind, attributesAreComplete: handle.IsNil, hasNameInMetadata: hasNameInMetadata, scope, hasUnscopedRefAttribute); @@ -362,6 +369,17 @@ private PEParameterSymbol( Debug.Assert(refKind == this.RefKind); Debug.Assert(hasNameInMetadata == this.HasNameInMetadata); Debug.Assert(_name is not null); + + static bool isExtensionMarkerParameter(Symbol containingSymbol, int ordinal) + { + if (containingSymbol.MetadataName != WellKnownMemberNames.ExtensionMarkerMethodName) + { + return false; + } + + var markerMethod = ((PENamedTypeSymbol)containingSymbol.ContainingType).GetMarkerMethodSymbol(); + return object.ReferenceEquals(markerMethod, containingSymbol) && ordinal == 0; + } } private bool HasNameInMetadata diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs index 9c0dd360ae364..4a7c2b59b7cf1 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs @@ -4575,6 +4575,50 @@ private class C { } Diagnostic(ErrorCode.ERR_BadVisIndexerParam, "P").WithArguments("Extensions.extension(Extensions.C).P", "Extensions.C").WithLocation(6, 27)); } + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/81251")] + public void ReceiverParameter_Name() + { + // Unnamed extension parameter should not default to "value" as its name when round-tripped + var libSrc = """ +using System; + +public static class ArrayEx +{ + extension(Array) + { + public static T[] Init(T value) + => throw null; + } +} +"""; + var libComp = CreateCompilation(libSrc); + libComp.VerifyDiagnostics(); + + var src = """ +using System; + +Array.Init(value: 10); +"""; + var comp = CreateCompilation([src, libSrc]); + comp.VerifyEmitDiagnostics(); + validate(comp); + + comp = CreateCompilation(src, references: [libComp.EmitToImageReference()]); + comp.VerifyEmitDiagnostics(); + validate(comp); + + comp = CreateCompilation(src, references: [libComp.ToMetadataReference()]); + comp.VerifyEmitDiagnostics(); + validate(comp); + + void validate(CSharpCompilation comp) + { + var extension = comp.GlobalNamespace.GetTypeMember("ArrayEx").GetTypeMembers("").Single(); + Assert.True(extension.IsExtension); + Assert.Equal("", extension.ExtensionParameter.Name); + } + } + [Fact] public void InconsistentTypeAccessibility_01() { @@ -9085,7 +9129,7 @@ public static string M(object o, string s, int x) AssertEx.Equal("Extensions.extension(object).M(object, string)", m1.ToDisplayString()); AssertEx.Equal([], m1.GetAttributes()); - AssertEx.Equal("System.Object value", extensions[1].ExtensionParameter.ToTestDisplayString()); + AssertEx.Equal("System.Object", extensions[1].ExtensionParameter.ToTestDisplayString()); AssertEx.Equal("$C43E2675C7BBF9284AF22FB8A9BF0280", extensions[1].MetadataName); Symbol m2 = extensions[1].GetMembers().Single(); AssertEx.Equal("Extensions.extension(object).M(object, string, int)", m2.ToDisplayString()); @@ -29798,7 +29842,7 @@ public static partial class C var container = m.GlobalNamespace.GetTypeMember("C"); var extension = container.GetTypeMembers().Single(); - AssertEx.Equal("System.Object value", extension.ExtensionParameter.ToTestDisplayString()); + AssertEx.Equal("System.Object", extension.ExtensionParameter.ToTestDisplayString()); AssertEx.Equal("$C43E2675C7BBF9284AF22FB8A9BF0280", extension.MetadataName); var methods = extension.GetMembers(); diff --git a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests2.cs b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests2.cs index 57774ccb56d43..6806ef04b8675 100644 --- a/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests2.cs +++ b/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests2.cs @@ -24749,7 +24749,7 @@ static void validate(ModuleSymbol module) var extension = module.GlobalNamespace.GetMember("E").GetTypeMembers().Single(); Assert.Equal(["AAttribute", "BAttribute"], extension.TypeParameters[0].GetAttributes().Select(a => a.ToString())); Assert.Equal(["AAttribute", "BAttribute"], extension.ExtensionParameter.GetAttributes().Select(a => a.ToString())); - Assert.Equal(module is SourceModuleSymbol ? "" : "value", extension.ExtensionParameter.Name); + Assert.Equal("", extension.ExtensionParameter.Name); } }