-
Notifications
You must be signed in to change notification settings - Fork 748
Fix kwarg func resolution #1136
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
Fix kwarg func resolution #1136
Conversation
Just to note that we have been using this fix for some time and it does appear to work. It is a welcome change from needing to specify long list of args you don't care about. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just FYI, there's a much better way to do method resolution (which I hope we will adopt at some point) but it requires lots of rework: C# Binder. I did a simple experiment here: losttech@605c576
We can still take this change in meanwhile.
src/runtime/methodbinder.cs
Outdated
// Order by the number of defaults required and find the smallest | ||
var fewestDefaultsRequired = bestKwargMatches.OrderBy((x) => x.Item2).ToArray()[0].Item2; | ||
|
||
List<Tuple<int, int, object[], int, MethodBase>> bestDefaultsMatches = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make named structs from the tuples? It's hard to read with Item1
-like references.
Yes this wasn't supposed to change the world, simply just to get something that worked 😄 |
ce07727
to
2b98872
Compare
if (testMatch.DefaultsNeeded == fewestDefaultsRequired) | ||
{ | ||
bestCount++; | ||
if (bestMatchIndex == -1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not having this check will cause tests to fail because a different overload is picked- e.g. MethodTest.TestOverloadedObjectTwo(5, 5) will get the (Object, Object) overload rather than the (Int, Int) overload
src/runtime/methodbinder.cs
Outdated
var matchedMethod = new MatchedMethod(kwargsMatched, defaultsNeeded, margs, outs, mi); | ||
argMatchedMethods.Add(matchedMethod); | ||
} | ||
if (argMatchedMethods.Count() > 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use Count
property. Count()
method might require a run through the entire collection.
if (bestCount > 1 && fewestDefaultsRequired > 0) | ||
{ | ||
// Best effort for determining method to match on gives multiple possible | ||
// matches and we need at least one default argument - bail from this point | ||
return null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this makes the change breaking for Python.NET 2.x branch. Currently the first match is returned irrespective if there are other matches. No need to fix it, just means might have to be merged later.
643f7bc
to
1dd8725
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved, but should wait for post 2.x branch due to the breaking change in behavior around overload resolution ordering.
@jmlidbetter we have released 2.5 and |
Sure. I assume just rebasing on top of master is sufficient or is there something else you'd want? |
@jmlidbetter it should be. I'll re-review just in case. |
7caa7ed
to
d453159
Compare
@lostmsu Ok I have rebased, feel free to check and merge (as appropriate) |
@jmlidbetter related tests seem to be failing. |
Hmm that is strange - when I ran the tests on my machine they all passed.... I will have a look tomorrow. |
Seems like the Linux tests have passed ok but are broken on Windows - perhaps there is some slight difference in behaviour on windows. I have limited ability test on windows but I'll see what I can do. |
@lostmsu I have not been able to reproduce the test failures. Building on Windows I get the following output: Are you able to repro this issue on windows? |
I am not sure what causes the discrepancy, but judging by the code, it seems like the CI build messes up with named parameters. I will try to see if that is correct. However, this also uncovers a bug: if Python passed a named parameter not defined in C#, the overload resolution behavior is incorrect. I suggest to handle that and add a test too. void NoOverloads(int a = 0) {} NoOverloads(c=1) # should fail, because c does not match a |
I believe I had originally implemented that behaviour (not submitted onto this branch) but it broke some other tests. I may be misremembering though, I will check tomorrow. |
@lostmsu here is the breaking test if you fail when a kwarg is supplied that doesn't appear in the method signature:
I haven't done any further investigation into this. I guess there are two ways to proceed: Its up to you, but personally I'm in favour of (1) because (a) having working kwargs (except in the case where you supply extra ones ;) ) is quite a big improvement and (b) python is fairly loose anyway with ducktyping etc etc, in a way all C# methods would have an implicit **kwargs in their signature - it might be possible to throw a warning when extraneous kwargs are given, I don't know. |
Are we good to merge this change once the tests have passed? |
This looks good to me, @lostmsu are you also fine with merging this? |
Codecov Report
@@ Coverage Diff @@
## master #1136 +/- ##
=======================================
Coverage 87.97% 87.97%
=======================================
Files 1 1
Lines 291 291
=======================================
Hits 256 256
Misses 35 35
Flags with carried forward coverage won't be shown. Click here to find out more. Continue to review full report at Codecov.
|
What does this implement/fix? Explain your changes.
A first run at fixing issue #1097. Currently, the method for selecting which method to use is quite simple and just takes the first function it finds to match. The problem is that the current picking algorithm has no knowledge of kwargs and how many have been supplied or used, i.e. MatchesArgumentCount will return true even if we've supplied some kwargs but the current overload does not require them. Ultimately, this means the first matched method might not be the best.
This small patch aims to rectify this issue by collecting together all the methods for which MatchesArgumentCount returns true and then from these selecting the best match based on the following criteria
It also has some logic to abort in the case where
This stops users in python making ambiguous function calls - see the tests for an example.
Does this close any currently open issues?
#1097
Any other comments?
Feedback please!
Checklist
Check all those that are applicable and complete.
AUTHORS
CHANGELOG