Skip to content

Conversation

@smarter
Copy link
Member

@smarter smarter commented Jun 26, 2019

When we do overloading resolution, we first replace alternatives that
could not possibly match the expected type by their apply members if
they exist, however the existing logic failed to select apply members
from the result of a polymorphic parameterless def. We fix this by
simply replacing the PolyType by its result type without making up any
type variable, the resulting behavior matches the existing behavior of
Scala 2 on the added test file.

When we do overloading resolution, we first replace alternatives that
could not possibly match the expected type by their `apply` members if
they exist, however the existing logic failed to select `apply` members
from the result of a polymorphic parameterless def. We fix this by
simply replacing the PolyType by its result type without making up any
type variable, the resulting behavior matches the existing behavior of
Scala 2 on the added test file.
@smarter smarter requested a review from odersky June 26, 2019 16:24
case _ =>
alt
}
qual.member(nme.apply).alternatives.map(TermRef(alt, nme.apply, _))
Copy link
Contributor

Choose a reason for hiding this comment

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

I find this extremely dicey. alt.apply is not even a well formed term and its type refers an unbound param ref. So this does not look right to me. Scala 2's behavior is no excuse, since it has many situations where bound variables escape. So I do not think this is the right fix, and I am not sure we need a fix at all, since it seems impossible to describe the fix in terms that are simple and sound.

Copy link
Member Author

Choose a reason for hiding this comment

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

alt.apply is not even a well formed term

But this is also true for the case where alt is a monomorphic method since it's not a stable prefix, and yet the existing code will happily make up a TermRef for it. If we wanted to be stricter we could use .narrow instead.

its type refers an unbound param ref.

True, since this is only used for overloading resolution, it seemed OK to me. If we want to avoid that, an alternative would be to make the resulting types polymorphic, e.g. if we start with:

def foo2[T]: T => String

Then we could pretend that it really has type:

[T](x: T): String

This would mean that switching between having a polymorphic method with a parameter list and a polymorphic method that returns an object with the same parameter list would not affect which overload gets chosen, this is a nice property to have and it matches what happens with monomorphic methods. The only downside I see is that it doesn't match Scala 2 behavior, but I don't think that's a big deal here (and the current behavior of dotty master can also select a different overload than Scala 2, so we wouldn't be regressing).

Copy link
Contributor

Choose a reason for hiding this comment

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

You'd certainly get into problems if the polytype is already in use in the current constraint. Yes, we can move the PolyType around, onto the apply method, but these are complicated acrobatics which make the code base harder to understand. Do we have a hard reason for doing this? Being compatible with scalac is not reason enough by itself, I think.

@odersky odersky removed their assignment Jun 26, 2019
Instead of doing overload selection directly on the result of the
PolyType which contains unbounded paramrefs, we now first call
`wildApprox` to get rid of the paramrefs. The resulting behavior is
different from what Scala 2 does, but it makes polymorphic overloads
with apply members behave more like polymorphic overloads with a
parameter list, e.g given:

    def a(x: Any): Any
    def a[T <: Int]: T => T
    a(1)

    def b(x: Any): Any
    def b[T <: Int](x: T): T
    b(1)

in both cases the second overload will be selected.
@smarter
Copy link
Member Author

smarter commented Jun 27, 2019

Updated to use wildApprox to avoid having unbounded variables.

@odersky odersky merged commit 67c9abb into scala:master Jun 27, 2019
@allanrenucci allanrenucci deleted the poly-apply branch June 27, 2019 17:53
smarter added a commit to smarter/zio that referenced this pull request Sep 6, 2019
The recent Dotty upgrade includes
scala/scala3#6756 which fixes overload
selection for `bracket_`.
smarter added a commit to smarter/zio that referenced this pull request Sep 6, 2019
The recent Dotty upgrade includes
scala/scala3#6756 which fixes overload
selection for `bracket_`.
smarter added a commit to smarter/zio that referenced this pull request Sep 6, 2019
The recent Dotty upgrade includes
scala/scala3#6756 which fixes overload
selection for `bracket_`.
ghostdogpr pushed a commit to zio/zio that referenced this pull request Sep 6, 2019
The recent Dotty upgrade includes
scala/scala3#6756 which fixes overload
selection for `bracket_`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants