Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d91b8db
Add friendlier error message
Sep 12, 2025
7982b7f
Merge branch 'main' into feature/60742-friendlier-error-message
stbau04 Sep 12, 2025
d7e1891
Resolve pr conflicts
Sep 12, 2025
1f2ff2f
Remove unused usings
Sep 12, 2025
e3b4125
Fix wrong refactor
Sep 12, 2025
2337acb
PR fix: Rename SloppyExplicitImplementationComparer
Sep 12, 2025
9bbf39e
PR fix: Add error message for properties and events
Sep 15, 2025
3f95508
PR fix: Perform signature comparison as done for overrides
Sep 15, 2025
916c468
Fix failing unit tests
Sep 19, 2025
2db8326
Resolve pr conflicts
Sep 19, 2025
98c3ece
Fix changes done to resolve pr conflict
Sep 19, 2025
da6a11d
Fix tests, Add additional tests
Sep 19, 2025
ec53477
Add missing semicolon
Sep 20, 2025
bb9f40b
Fix actions
Sep 20, 2025
275169c
Fix more tests
Sep 20, 2025
d7cf7ac
Merge branch 'feature/60742-friendlier-error-message' into utility
Sep 20, 2025
aa56971
Revert changes
Sep 20, 2025
467b984
Merge branch 'utility' into feature/60742-friendlier-error-message
Sep 20, 2025
8b8eead
Revert tests
Sep 20, 2025
8da786b
Merge branch 'utility' into feature/60742-friendlier-error-message
Sep 20, 2025
3d5799f
Revert more changes
Sep 20, 2025
9949468
Move tests
Sep 20, 2025
f3130b2
Fix unit tests
Sep 20, 2025
443da33
Fix indentation
Sep 20, 2025
c10e253
Fix comment
Sep 20, 2025
faa048d
Rename test
Sep 20, 2025
d23f94c
Update src/Compilers/CSharp/Portable/Symbols/Source/ExplicitInterface…
stbau04 Sep 23, 2025
8b9d010
Add test
Sep 23, 2025
de75b5d
Merge branch 'main' into feature/60742-friendlier-error-message
Sep 23, 2025
21ad1f0
Update error comments
Sep 23, 2025
69659d8
Fix more error codes
Sep 23, 2025
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
6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -8196,4 +8196,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_AttributeCannotBeAppliedManually" xml:space="preserve">
<value>'{0}' cannot be applied manually.</value>
</data>
<data name="ERR_ExplicitInterfaceMemberTypeMismatch" xml:space="preserve">
<value>'{0}': type must be '{1}' to match implemented member '{2}'</value>
</data>
<data name="ERR_ExplicitInterfaceMemberReturnTypeMismatch" xml:space="preserve">
<value>'{0}': return type must be '{1}' to match implemented member '{2}'</value>
</data>
</root>
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2427,6 +2427,8 @@ internal enum ErrorCode
ERR_MethodImplAttributeAsyncCannotBeUsed = 9330,
ERR_AttributeCannotBeAppliedManually = 9331,
ERR_BadSpreadInCatchFilter = 9332,
ERR_ExplicitInterfaceMemberTypeMismatch = 9333,
ERR_ExplicitInterfaceMemberReturnTypeMismatch = 9334,

// Note: you will need to do the following after adding errors:
// 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs)
Expand Down
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2536,6 +2536,8 @@ or ErrorCode.ERR_ExtensionBlockCollision
or ErrorCode.ERR_MethodImplAttributeAsyncCannotBeUsed
or ErrorCode.ERR_AttributeCannotBeAppliedManually
or ErrorCode.ERR_BadSpreadInCatchFilter
or ErrorCode.ERR_ExplicitInterfaceMemberTypeMismatch
or ErrorCode.ERR_ExplicitInterfaceMemberReturnTypeMismatch
=> false,
};
#pragma warning restore CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ internal sealed class MemberSignatureComparer : IEqualityComparer<Symbol>
considerCallingConvention: true,
typeComparison: TypeCompareKind.AllIgnoreOptions);

/// <summary>
/// If this returns false, then the real explicit implementation comparer will also return false.
/// Skips checking whether the return type is equal.
/// </summary>
public static readonly MemberSignatureComparer ExplicitImplementationWithoutReturnTypeComparer = new MemberSignatureComparer(
considerName: false,
considerExplicitlyImplementedInterfaces: false,
considerReturnType: false,
refKindCompareMode: RefKindCompareMode.ConsiderDifferences | RefKindCompareMode.AllowRefReadonlyVsInMismatch,
considerCallingConvention: true,
typeComparison: TypeCompareKind.AllIgnoreOptions);

/// <summary>
/// This instance is used when trying to determine if one member implicitly implements another,
/// according to the C# definition.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,13 @@ private static Symbol FindExplicitlyImplementedMember(
//do a lookup anyway
}

// Found a matching member without checking the return type.
var foundMatchingMemberWithoutReturnTypeComparer = false;
// Setting this flag to true does not imply that an interface member has been successfully implemented.
// It just indicates that a corresponding interface member has been found (there may still be errors).
var foundMatchingMember = false;

Symbol matchingMemberWithoutReturnTypeComparer = null;
Symbol implementedMember = null;

// Do not look in itself
Expand Down Expand Up @@ -265,7 +268,19 @@ private static Symbol FindExplicitlyImplementedMember(
continue;
}

if (MemberSignatureComparer.ExplicitImplementationComparer.Equals(implementingMember, interfaceMember))
if (!MemberSignatureComparer.ExplicitImplementationWithoutReturnTypeComparer.Equals(implementingMember, interfaceMember))
{
continue;
}

var implementingMemberTypeMap = MemberSignatureComparer.GetTypeMap(implementingMember);
var interfaceMemberTypeMap = MemberSignatureComparer.GetTypeMap(interfaceMember);
if (MemberSignatureComparer.HaveSameReturnTypes(
implementingMember,
implementingMemberTypeMap,
interfaceMember,
interfaceMemberTypeMap,
TypeCompareKind.AllIgnoreOptions))
{
foundMatchingMember = true;
// Cannot implement accessor directly unless
Expand All @@ -291,13 +306,30 @@ private static Symbol FindExplicitlyImplementedMember(
break;
}
}
else
{
foundMatchingMemberWithoutReturnTypeComparer = true;
matchingMemberWithoutReturnTypeComparer = interfaceMember;
}
}

if (!foundMatchingMember)
{
// CONSIDER: we may wish to suppress this error in the event that another error
// CONSIDER: we may wish to suppress these errors in the event that another error
// has been reported about the signature.
diagnostics.Add(ErrorCode.ERR_InterfaceMemberNotFound, memberLocation, implementingMember);

if (foundMatchingMemberWithoutReturnTypeComparer)
{
var errorType = implementingMember.Kind is SymbolKind.Method
? ErrorCode.ERR_ExplicitInterfaceMemberReturnTypeMismatch
: ErrorCode.ERR_ExplicitInterfaceMemberTypeMismatch;
var returnType = matchingMemberWithoutReturnTypeComparer.GetTypeOrReturnType();
diagnostics.Add(errorType, memberLocation, implementingMember, returnType, matchingMemberWithoutReturnTypeComparer);
}
else
{
diagnostics.Add(ErrorCode.ERR_InterfaceMemberNotFound, memberLocation, implementingMember);
}
}

// Make sure implemented member is accessible
Expand Down
10 changes: 10 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.

10 changes: 10 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.

10 changes: 10 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.

10 changes: 10 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.

10 changes: 10 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.

10 changes: 10 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.

10 changes: 10 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.

10 changes: 10 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.

10 changes: 10 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.

10 changes: 10 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.

10 changes: 10 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.

10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf

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

Loading