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

Add message details for AmbiguousMatchException #84512

Merged
merged 1 commit into from
May 31, 2023

Conversation

IDisposable
Copy link
Contributor

@IDisposable IDisposable commented Apr 8, 2023

Add information to what is ambiguously matched when an AmbiguousMatchException or an AmbiguousInvovationException is thrown as we know what we found multiple matching items for.

Fixes #18255

Basic idea is to use the known-first match as a source for the declaring type name and member name to format into the Exception message value.

There's a bunch of similar/common/duplicated code all over, so not sure where (which subset) to apply so this PR attempts most of the uses of AmbigousMatchException and AmbiguousInvocationException (which has similar issues).

Need to know before this gets final which of the libraries/builds this needs to be done in:

  • src/coreclr/nativeaot/System.Private.CoreLib
  • src/libraries/System.Private.CoreLib
  • src/libraries/System.Reflection.MetadataLoadContext
  • src/mono/System.Private.CoreLib

I also noted that the same localizable string ends up in several assemblies the way things are now (e.g. there's a Strings.resx and matching ThrowHelper.cs for each of the target libraries above, with some overlapped strings). I am not sure there is anything to be done about that, but worth calling out in this PR

@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Apr 8, 2023
@ghost
Copy link

ghost commented Apr 8, 2023

Tagging subscribers to this area: @dotnet/area-system-reflection
See info in area-owners.md if you want to be subscribed.

Issue Details

Add information to what is ambiguously matched when an AmbiguousMatchException is thrown as we know what we found multiple matching items for.

This is a draft PR to fix #18255

Basic idea is to use the known-first match as a source for the declaring type name and member name to format into the Exception message value.

There's a bunch of similar/common/duplicated code all over, so not sure where (which subset) to apply so this PR attempts most of the uses of AmbigousMatchException and AmbiguousInvocationException (which has similar issues).

Need to know before this gets final which of the libraries/builds this needs to be done in:

  • src/coreclr/nativeaot/System.Private.CoreLib
  • src/libraries/System.Private.CoreLib
  • src/libraries/System.Reflection.MetadataLoadContext
  • src/mono/System.Prive.CoreLib

I also noted that the same localizable string ends up in several assemblies the way things are now (e.g. there's a Strings.resx and matching ThrowHelper.cs for each of the targes above, with some overlapped strings)... not sure there is anything to be done about that, but worth calling out in this Draft

Author: IDisposable
Assignees: -
Labels:

area-System.Reflection

Milestone: -

@@ -2891,7 +2889,7 @@ public override InterfaceMapping GetInterfaceMap([DynamicallyAccessedMembers(Dyn
{
if (returnType is null)
// if we are here we have no args or property type to select over and we have more than one property with that name
throw new AmbiguousMatchException();
ThrowHelper.ThrowAmbiguousMatchException(firstCandidate);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As this is the first use of the helper in this PR, I thought I would mention the strategy. To resolve the original issue and add more information to figure out what was ambiguous, we need to know the name of the member that has ambiguity.

Since PropertyInfo et al all descend from MemberInfo, we can make a helper that formats messages from calling .ToString() on the info and it's DeclaringType. This yields, for example from String.Length the values System.String and Int32 Length as the insertions. See ThrowHelper.cs


if (!_policies.OkToIgnoreAmbiguity(match, challenger))
throw new AmbiguousMatchException();
// If they're not the same method, we throw if the policy doesn't allow ambiguity.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Merged the two if statements as they are logically doing the full check, and in either case throwing with the same info.

@IDisposable
Copy link
Contributor Author

If this seems like a reasonable approach, I will build out tests for all the paths

@steveharter, @marek-safar, @MichalStrehovsky I am not sure I actually need to handle the case of a null DeclaringType... is that really a possibility, because much of the code I did a surface scan of seems to think that never happens, in which case I can simplify a bit and eliminate the _Simple strings.

@IDisposable IDisposable changed the title Add message for AmbiguousMatchException Add detailed message for AmbiguousMatchException and AmbiguousInvocationException Apr 8, 2023
@IDisposable
Copy link
Contributor Author

IDisposable commented Apr 8, 2023

Check failures do not look to be related to anything I did.

@IDisposable IDisposable changed the title Add detailed message for AmbiguousMatchException and AmbiguousInvocationException Add message details for AmbiguousMatchException Apr 9, 2023
@IDisposable
Copy link
Contributor Author

IDisposable commented Apr 9, 2023

Fleshed out the rest of the AmbiguousMatchExeception uses (and removed talk about doing the same for AmbiguousImplementationExceptio as there's no details available)

@IDisposable IDisposable force-pushed the better-ambiguity-messages branch 3 times, most recently from 011f8d2 to 7fcafef Compare April 9, 2023 06:47
Copy link
Contributor Author

@IDisposable IDisposable left a comment

Choose a reason for hiding this comment

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

Cleanup and fleshed things out a bit more. Seems to build.

@IDisposable
Copy link
Contributor Author

Thanks TONS for the review @buyaa-n ! I just had eye surgery so I'm face down with minimal screen time for at least a week, will integrate your changes ASAP!

@IDisposable
Copy link
Contributor Author

IDisposable commented May 10, 2023

I merged the simple ones, but this is no an unstable revision until I loop through the rest... I'll resync with main and squash this all before making it ready again Completed feedback comments and rebased and squashed

@IDisposable IDisposable marked this pull request as draft May 10, 2023 19:07
@IDisposable IDisposable force-pushed the better-ambiguity-messages branch 2 times, most recently from 040cb97 to 2887a9c Compare May 15, 2023 02:31
@IDisposable IDisposable force-pushed the better-ambiguity-messages branch 4 times, most recently from ab3b597 to be66552 Compare May 29, 2023 23:23
@IDisposable
Copy link
Contributor Author

IDisposable commented May 29, 2023

Addressed final feedback, rebased and squashed.

Clean build except:
Mono Product Build windows x64 release/Build Product has an unrelated error

D:\a_work\1\s\src\mono\mono\utils\options.c(327): fatal error C1051: program database file, 'D:\a_work\1\s\artifacts\obj\mono\windows.x64.Release\mono\utils\CMakeFiles\utils_objects.dir\vc140.pdb', has an obsolete format, delete it and recompile

Build Libraries Test Run release mono osx x64 Debug/Publish Logs has an unrelated error

ApplicationInsightsTelemetrySender correlated 2 events with X-TFS-Session ee700fc9-8f51-4fbc-9dfc-a87d4770ce7a
##[error]Artifact BuildLogs_Mono__windows_x64_release already exists for build 289357.

@IDisposable
Copy link
Contributor Author

IDisposable commented May 31, 2023

Not sure why the Detailed version isn't useful, but if we're killing off the uses, I can remove the literal. I added these originally because what I was getting back from the various .ToString() calls was different information, so it seemed valuable.

If we're absolutely sure we should never emit the type's information, I'll make one more pass to neaten the .ResX files and rebase/squash again

@buyaa-n
Copy link
Member

buyaa-n commented May 31, 2023

Not sure why the Detailed version isn't useful, but if we're killing off the uses, I can remove the literal. I added these originally because what I was getting back from the various .ToString() calls was different information, so it seemed valuable.

It is more about the extra conditional added for checking if the declaringType is not null, than it was not useful. At least throwing an exception is not a hot path that needs to be performant, so I am OK to add it if the declaringType info added is really useful, for which I am not that sure about. Let's take the example you used, for:
Ambiguous implementation found for 'System.String Int32 Length'
Ambiguous implementation found for 'Int32 Length'
How useful the System.String part for you, or is this could cause any confusion when you were actually looking for the Length property?

Also, another option could be just passing the declaring type without null check as string.Format accepts null. The message would just have and extra space when the declaring type is null Ambiguous implementation found for ' Int32 Length'. How this sound?

If you want to keep it all as is I am also OK with that

@IDisposable
Copy link
Contributor Author

Let's take the example you used, for: Ambiguous implementation found for 'System.String Int32 Length'
Ambiguous implementation found for 'Int32 Length'

How useful the System.String part for you, or is this could cause any confusion when you were actually looking for the Length property?

When we're figuring out why the exception was thrown (at post-mortem debug), knowing the exact class that had ONE of the ambiguities lets us narrow things down. We wouldn't be doing this on core classes usually, so having the type seems very helpful for opening the right source file :)

Also, another option could be just passing the declaring type without null check as string.Format accepts null. The message would just have and extra space when the declaring type is null Ambiguous implementation found for ' Int32 Length'. How this sound?

I like that idea... lemme churn that a bit and commit.

@IDisposable
Copy link
Contributor Author

Incorporated these last few discussions. Now always passes the (possibly null) DeclaringType when dumping a MemberInfo (or derived). The other ResX messages are now named according to the ambiguous thing, so we're now talking about AmbiguousMatchException_Assembly, Arg_AmbiguousMatchException_Attribute, Arg_AmbiguousMatchException_CustomAttributeData (was Simple), Arg_AmbiguousMatchException_MemberInfo (was Detailed), and Arg_AmbiguousMatchException_RoDefinitionType with matching ThrowHelper or inline versions (as needed)

@IDisposable
Copy link
Contributor Author

IDisposable commented May 31, 2023

Build errors, please hold Fixed it... helps to ^S in VS Code ;)

Add information to what is ambiguously matched when an AmbiguousMatchException is thrown as we know what we found multiple matching items for.

Addressed review feedback 
Renames of SR/RESX strings. Removal of `.ToString()` calls. Remove unused strings from RESX RESX string rewording.
Change the exception format string to "found for" style.
Cleanup of DefaultBinder.cs FindMostDerived* to use the local variable.
Remove copy-pasta ThrowHelper.cs instance.
Don't emit the CustomAtrributeData's type
All MemberInfo cases pass a (possibly null) `DeclaringType`.
Co-authored-by: Buyaa Namnan <buyankhishig.namnan@microsoft.com>
Copy link
Member

@buyaa-n buyaa-n left a comment

Choose a reason for hiding this comment

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

Thank you @IDisposable LGTM

@buyaa-n
Copy link
Member

buyaa-n commented May 31, 2023

The failures unrelated and all known issues, merging

@buyaa-n buyaa-n merged commit c75b8e0 into dotnet:main May 31, 2023
@IDisposable IDisposable deleted the better-ambiguity-messages branch May 31, 2023 17:52
@ghost ghost locked as resolved and limited conversation to collaborators Jun 30, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Reflection community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Exception message for AmbiguousMatchException should include the name
2 participants