-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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 regression #17245: Overloaded methods with ClassTags #18286
Conversation
@@ -1118,7 +1118,7 @@ class Definitions { | |||
case ErasedFunctionOf(mt) => | |||
Some(mt.paramInfos, mt.resType, mt.isContextualMethod) | |||
case _ => | |||
val tsym = ft.dealias.typeSymbol | |||
val tsym = ft.typeSymbol |
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.
What was the type of the ft
that caused the issue and what was the dealiased type?
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.
It was OnChannel
, which when dealiased became Channel => Any
, which I suppose made sense to match as a FunctionOf. I will admit after a certain point I mostly focused on obtaining previous behavior, without much consideration on what is the most correct (I saw the dealias change in the PR introducing the regression). Ideally I imagine we would keep the dealiased unapply and try to fix the issue directly inside resolveOverloaded
methods?
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.
Maybe we should figure out what this has in common with #18276. I'm currently suspecting a change in Typer in https://github.com/lampepfl/dotty/pull/16507/files#diff-8c9ece1772bd78160fc1c31e988664586c9df566a1d22ff99ef99dd6d5627a90 could have broken this.
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.
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.
Indeed, they are unrelated. It fixed the other one (waiting for CI confirmation) in #18288.
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.
Now I am wondering if you need #18288 to fix the new issue you are having.
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 tested now and it does not seem to affect it, but keeping the dealiasing in FunctionOf unapply and instead changing the resolveOverloaded1
method here seems to work for all of the now-failing tests, even if changing only one line very naively, so we can skip that case which previously would not be accessed, like this:
- case defn.FunctionOf(args, resultType, _) =>
+ case defn.FunctionOf(args, resultType, _) if pt.dealias.typeSymbol == pt.typeSymbol =>
But I want to read up on this method some more today in case there is a cleaner solution, and then I will update this PR by tomorrow morning
Hmm, some tests are failing |
The failing tests might be related to #18276. |
I think this means that the added dealias in FunctionOf unapply was what ended up fixing #12663 |
Sorry, this wasn't a reply! I was just thinking out loud about the failing tests. I tested just now the minimization from #18276 on the changes introduced here and it does not fix anything there |
In my last commit here I decided to just remove the separate case for FunctionOf, as I could not find a use case for it, all the tests still passed, and that fixed an additional similar issue for overloaded methods returning non-aliased Function types. This made the tests pass, but just now I found that for: def f(s: Int): Unit = println("a")
def f: Int => Unit = _ => println("b")
@main def Test =
val test: String => Unit = f
test(0) Before my last last commit "a" would be printed out, and after it "b" (ideally I imagine here an exception should be thrown, but that is a topic for a separate issue). So this is still work in progress despite the tests clearing, but I have a few more ideas left. |
Before the regression, FunctionOf unapply would not try dealiasing, meaning that an aliased function type would be handled by a general case. To fix that, instead of handling Function types separately when filtering overloaded methods in `resolveOverloaded1`, we allow to fallback to the general case if the previous one returns nothing. Along with fixing the regression, this also improves other cases, one of which was added to the test. Readd a separate FunctionOf case, but with a fallback
Passes all the tests now. I reopened the PR and updated the original comment to better reflect the changes introduced |
This fix appears to have broken ScalaTest's Here's the signature with a dummy implementation to illustrate the issue: inline def assertThrows[T <: AnyRef](f: => Any)(implicit classTag: scala.reflect.ClassTag[T]) = f
assertThrows(1)
|
Hmm, the above minimization fails regardless of the Scala 3 version used (which seems like the correct behavior to me, as the type inference does not get any information about what T could even resolve to). Moreover I don't think assertThrows is being overloaded anywhere in ScalaTest, so the above changes should not affect have any effect on that method, I think. |
Ok, this was the only change I could find that would explain why upgrading to RC6 (from RC1) prevents tests from running (i.e. due to aforementioned compilation failure). Only sbt (1.9.0 to 1.9.4) and scala were updated. Interestingly vscode doesn't mark EDIT @jchyb ☝️ p.s. sorry if this has nothing to do with the merged PR here |
…19654) Fixes #19641 How we got here: Originally, overloading resolution for types that were not applied was handled like this: ```scala case defn.FunctionOf(args, resultType, _) => narrowByTypes(alts, args, resultType) case pt => val compat = alts.filterConserve(normalizedCompatible(_, pt, keepConstraint = false)) if (compat.isEmpty) /* * the case should not be moved to the enclosing match * since SAM type must be considered only if there are no candidates * For example, the second f should be chosen for the following code: * def f(x: String): Unit = ??? * def f: java.io.OutputStream = ??? * new java.io.ObjectOutputStream(f) */ pt match { case SAMType(mtp, _) => narrowByTypes(alts, mtp.paramInfos, mtp.resultType) case _ => // pick any alternatives that are not methods since these might be convertible // to the expected type, or be used as extension method arguments. val convertible = alts.filterNot(alt => normalize(alt, IgnoredProto(pt)).widenSingleton.isInstanceOf[MethodType]) if convertible.length == 1 then convertible else compat } else compat ``` Note the warning comment that the case for SAM types should not be moved out, yet we do exactly the same thing for plain function types. I believe this was simply wrong, but it was not discovered in a test. Then in #16507 we changed the `defn.FunctionOf` extractor so that aliases of function types were matched by it. This triggered test failures since we now hit the wrong case with aliases of function types. In #18286, we moved the extractor test around, but that was not enough, as #19641 shows. Instead the test for `FunctionOf` should be aligned with the test for SAM case. But it turns out that's not even necessary since the preceding `val compat = ...` handles function prototypes correctly by simulating an eta expansion. So in the end we could simply delete the problematic case.
The problem lied with slightly adjusted unapply of FunctionOf in a previous PR, which caused different behavior in
resolveOverloaded
, where due to a pattern match into a FunctionOf (here),resolveOverloaded1
would return no candidates, causing more issues later on.To keep the new behavior of FunctionOf unapply (which as a side-effect ended up fixing few issues represented with tests), with the previous behavior of overloaded functions, we allow the method candidate filtering to fallback from the FunctionOf candidate filtering, into the previous behavior, in case no candidates are kept. This also fixes and additional case, which is not part of a #17245 regression, but produces an incorrect error in similar manner.
Fixes #17245