-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix comparison of dependent function types #12214
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
Conversation
Note that even with the current restriction in places, structural selection via reflection is unsound in both Scala 2 and 3: import scala.language.reflectiveCalls
class Sink[A] { def put(x: A): Unit = {} }
object Test {
def main(args: Array[String]): Unit = {
val a = new Sink[String]
val b: { def put(x: String): Unit } = a
b.put("") // NoSuchMethodException: Sink.put(java.lang.String)
}
} So I would be in favor of allowing variance in structural types by default and phasing out reflectiveCalls in some way since it's broken beyond repair anyway, except that it's apparenty a big deal for Scala.js and I don't know what to do there /cc @sjrd. |
Can we fix reflexive dispatch to deal with the problem? We do have the restriction that refinements may not be overloaded. That should help. |
Only sort of, even if there's no overloading in |
If we assume the no-overload restriction, we could fix I.e if there is only one method, pick that. If there are several, pick the one that is defined in the parent class, or that overrides a method defined in the parent class. |
I don't follow, by the time we're typing |
@smarter You are right. So there would always be cases where a reflexive dispatch will be ambiguous. |
The other alternative would be to be stricter, disallowing val b: { def put(x: String): Unit } = a |
We now have a deluxe version of refinement subtyping, where the signature check can be disabled by inheriting from |
library/src/scala/Selectable.scala
Outdated
* the additional restriction that the signatures of the refinement and | ||
* the definition that implements the refinment must match. | ||
*/ | ||
trait WithoutPreciseParameterTypes extends Selectable |
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.
This needs to be @experimental
or commented out until 3.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.
I moved that part to a separate PR #12268 with a 3.1 milestone.
Dependent function types are expressed as refinements over regular function types. These refinements need to be compared with the standard arrow rule for function subtyping. But comparison of method refinements so far demanded equal parameter types. The solution is tricky since refined types lead to selections via reflection still cannot tolerate differing parameter types since reflexive method dispatch uses precise parameter types. That's why we apply standard arrow rule only for refinements where the refined method exists in the underlying class. Fixes scala#12211
Needed to compile pos/i11481.scala
@smarter Ready to merge? |
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.
LGTM, I'd like to extend this to allow polymorphic functions to vary but I can try that in a separate PR.
Dependent function types are expressed as refinements over regular function types.
These refinements need to be compared with the standard arrow rule for function
subtyping. But comparison of method refinements so far demanded equal parameter
types.
The solution is tricky since refined types lead to selections via reflection.
These still cannot tolerate differring parameter types since reflexive method dispatch
uses precise parameter types. That's why we apply the standard arrow rule only
for refinements where the refined method exists in the underlying class.
Fixes #12211