Skip to content
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

#4143: Pseudo-union type inference with type aliases and js.undefined #4145

Open
wants to merge 1 commit into
base: master
from

Conversation

@frobinet
Copy link

frobinet commented Jul 30, 2020

This PR fixes #4143, an issue with type inference for pseudo-union types scala.scalajs.js.| when Nothing is the first type parameter. This is especially useful when infering for js.undefined (see #4143).

Since Scala 3 will include proper union types, I've limited the changes to the strict minimum to allow js.undefined to work with type aliases like it did in Scala.js 0.6.x.

This is my first contribution to Scala.js, so there are probably issues with this PR. Feel free to point them out!

@frobinet frobinet force-pushed the frobinet:pseudo-union-nothing-inference branch from 60f37ba to b7de868 Jul 31, 2020
@frobinet
Copy link
Author

frobinet commented Jul 31, 2020

This passes my tests but causes issues with diverging implicit expansion in some other projects where I've tried it. I'll take a closer look this week-end.

@frobinet frobinet force-pushed the frobinet:pseudo-union-nothing-inference branch from b7de868 to a756c7f Jul 31, 2020
@frobinet frobinet force-pushed the frobinet:pseudo-union-nothing-inference branch from a756c7f to 7b4b0e9 Jul 31, 2020
@frobinet
Copy link
Author

frobinet commented Jul 31, 2020

I added a second implicit conversion and some other tests to cover more complex type aliases. I think this is ready for review.

@sjrd
Copy link
Member

sjrd commented Aug 5, 2020

I really don't like the left-right asymmetry of the new rules. Previously, all rules where symmetric in the sense that if there was a rule for X | Y, there was the same rule for Y | X. Now this is not the case anymore: there is a rule for Nothing | Y for not for Y | Nothing, and there is a rule for X | Unit but none for Unit | X.

I am also wary about the fact that you had to add addUnit to compensate for bad effects introduced by fromNothing. This is very worrying, because it means that fromNothing can have other unanticipated effects.

For those two reasons, I don't think this is the best way to go to mitigate the type inference issue.

@frobinet
Copy link
Author

frobinet commented Aug 5, 2020

addUnit was not needed because of fromNothing, but more in addition to it to make things work in some even harder test cases.

I agree that not having the symmetry is not elegant, I used this more as a direct solution to the specific problem that occured with type aliases and js.undefined, so I tried to restrict the addition of rules to the bare minimum.

I understand your concerns about these additions breaking some other things downstream. Do you have some kind of community build for Scala.js that might help us assess this? Otherwise, it is probably wiser to close this and try to fix the inference issue in the Scala compiler itself. That will probably be above my pay-grade though! 😄

@sjrd
Copy link
Member

sjrd commented Aug 7, 2020

Do you have some kind of community build for Scala.js that might help us assess this?

No, we don't. We rely on an extensive test suite instead, which is usually good enough. But for cases of tricky type inference like this, a test suite can never be enough because of many unknown unknowns about interactions with surrounding code. That's why we have to be extra careful.

I'm also particularly wary here, compared to other changes we've done in the past to Union.scala, because the new rules are, in theory, completely redundant:

  • addUnit[A] is the same as left[A, A, Unit](base[A])

  • fromNothing[A2, B1, B2](a)(ev_A2_B2) is the same as

    from[Nothing | A2, B1, B2](a)(
      allSubtypes[Nothing, A2, B1 | B2](
        base[Nothing], // an Evidence[Nothing, Nothing] which, by covariance, is also an Evidence[Nothing, B1 | B2]
        right[A2, B1, B2](ev_A2_B2) // an Evidence[A2, B1 | B2]
      )
    )
    

and redundant implicit definitions can easily cause divergences or ambiguities.

Otherwise, it is probably wiser to close this and try to fix the inference issue in the Scala compiler itself. That will probably be above my pay-grade though!

Maybe fixing the type inference is above you pay-grade (I don't know your background nor your time availabilities), but if you got this far, I'm sure you could create a reproduction to post as an issue on scala/bug 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

2 participants
You can’t perform that action at this time.