-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Should we allow polymorphic overloads with the same number of type parameters? #9109
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
Comments
I agree, it seems to be more useful and also more consistent to support them. |
should a new issue for this be made in feature requests or here? |
We should keep this open since the current situation is inconsistent (adding an overload can break overriding) |
Thinking about this more, I'm not so sure anymore if we should allow this or not. I think it comes down to what we want to do with #8929: class A {
def foo[T <: Serializable](x: T): Unit = {}
}
class B extends A {
override def foo[T](x: T): Unit = {}
} These are valid overrides for scalac but not for dotty, that is: scalac allows not only covariant result type overriding but contravariant type parameter bounds overriding, dotty refuses them because their signatures are different. If we were to support this, then it would make sense to ban overloads with the same number of type parameters, because overriding relationships would become very confusing to figure out, both for the compiler and for users, who cannot rely on just counting the number of type parameters to see what overrides what. |
Use Denotation#matches instead of Types#matches, the former takes signatures into account, in the testcase this is needed to ensure that RefChecks does not emit an error about `def foo[T <: Serializable](x: T): Unit` being an invalid override of `def foo[T <: Cloneable](x: T): Unit`. Note that our treatment of polymorphic methods is different Scala 2 which seems to consider that two polymorphic methods with the same number of type and term parameters always match and cannot be overloads (see scala#8929), but it's closer to what Java does and allows us to override some Java methods which scalac can't.
Use Denotation#matches instead of Types#matches, the former takes signatures into account, in the testcase this is needed to ensure that RefChecks does not emit an error about `def foo[T <: Serializable](x: T): Unit` being an invalid override of `def foo[T <: Cloneable](x: T): Unit`. Note that our treatment of polymorphic methods differs from Scala 2 which seems to consider that two polymorphic methods with the same number of type and term parameters always match and cannot be overloads (see scala#8929), but it's closer to what Java does and allows us to override some Java methods which scalac can't.
Use Denotation#matches instead of Types#matches, the former takes signatures into account, in the testcase this is needed to ensure that RefChecks does not emit an error about `def foo[T <: Serializable](x: T): Unit` being an invalid override of `def foo[T <: Cloneable](x: T): Unit`. Note that our treatment of polymorphic methods differs from Scala 2 which seems to consider that two polymorphic methods with the same number of type and term parameters always match and cannot be overloads (see scala#8929), but it's closer to what Java does and allows us to override some Java methods which scalac can't.
Use Denotation#matches instead of Types#matches, the former takes signatures into account, in the testcase this is needed to ensure that RefChecks does not emit an error about `def foo[T <: Serializable](x: T): Unit` being an invalid override of `def foo[T <: Cloneable](x: T): Unit`. Note that our treatment of polymorphic methods differs from Scala 2 which seems to consider that two polymorphic methods with the same number of type and term parameters always match and cannot be overloads (see scala#8929), but it's closer to what Java does and allows us to override some Java methods which scalac can't.
Fix #9109: More precise override check
What happens if we mix |
It doesn't change anything, why would it? overrides must have matching uses of |
These two overloads are considered valid by Dotty, because their signatures are different:
... but trying to override one of them fails, because refchecks uses
Types#matches
to find overrides which does not take signatures into account (it callsTypeComparer#matchesType
which in turns doesmatchesType(tp1.resultType, tp2.resultType.subst(tp2, tp1))
, therefore comparing(x: T): Unit
to(x: T): Unit
):So the question is: should we disallow these overloads, or should we strive to support them? The answer is not clear cut to me because Scala 2 never supported them:
... but Java does support them, so if we don't support them we're still in trouble when trying to override them (and in fact scala 2 cannot override them):
I would be in favor of supporting them for better interoperability and because it doesn't seem too hard (require matching param signatures for Types#matches to bring it in line with Denotation#matches)
WDYT @odersky ?
The text was updated successfully, but these errors were encountered: