Skip to content

Investigate problem in ZIO's promise #10808

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

Closed
odersky opened this issue Dec 15, 2020 · 6 comments
Closed

Investigate problem in ZIO's promise #10808

odersky opened this issue Dec 15, 2020 · 6 comments
Assignees

Comments

@odersky
Copy link
Contributor

odersky commented Dec 15, 2020

In Promise.scala in core/shared/src/main/scala/zio we get on error in the following line:

final class Promise[E, A] private (private val state: AtomicReference[State[E, A]], blockingOn: List[Fiber.Id])

We have to change State[E, A] to Promise.internal.State[E, A] to make it pass. This since the new scheme for
constructor proxies #10784. We should find out the cause and see whether we can address it.

@odersky
Copy link
Contributor Author

odersky commented Dec 16, 2020

Minimization:

import Promise.internal.State

class Promise(state: State)

object Promise:
  object internal:
    trait State

This gives:

-- [E046] Cyclic Error: test.scala:4:21 ----------------------------------------
4 |class Promise(state: State)
  |                     ^
  |                     Cyclic reference involving val <import>

@odersky
Copy link
Contributor Author

odersky commented Dec 16, 2020

Here's the observed completion sequence:

completing val <import>
  completing val Promise
  completed Promise in object Test
  completing type Promise$
    completing val <init>
    completed <init> in object Promise
add constr app object Promise
    completing type Promise
      completing val <init>
        completing val state
          completing val <import>
Cyclic reference involving! val <import>

So, it tries to type the import, which means it needs to complete the Promise object. That means we need to complete the Promise class since we need to know what constructor proxies to add. Completing the Promise class implies typechecking the parameters, which means we need to resolve State, which leads to completing the import. Hence the cycle.
It only happens if the import comes first, and if the type State is two levels deep in Promise.

@odersky
Copy link
Contributor Author

odersky commented Dec 16, 2020

The following variants work:

  import Promise.State

  class Promise(state: State)

  object Promise:
    trait State

and

  object Promise:
    object internal:
      trait State

  import Promise.internal.State

  class Promise(state: State)

and

class Promise(state: Promise.internal.State)

object Promise:
  object internal:
    trait State

and

object Promise:
  object internal:
    trait State

class Promise(state: Promise.internal.State)

@odersky
Copy link
Contributor Author

odersky commented Dec 16, 2020

At this point, I don't see much we can do. I tried to delay resolving the import but that caused problems in other code. So I guess we have to live with the fact that this orderings of code and imports now gives a cycle. There are of course ways in which this could have given a cycle before, for instance if object Promise had extended class Promise. This is just one more way to produce a cycle. I believe we can live with it.

@odersky odersky closed this as completed Dec 16, 2020
@som-snytt
Copy link
Contributor

FWIW, this issue feels like a recent duplicate, but I couldn't find where I saw it. The forward-reference style of import from companion is common; the idiom always feels strange to me; maybe it's worth advertising its fragility, perhaps in the error message.

@nafg
Copy link

nafg commented Dec 16, 2020 via email

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

No branches or pull requests

3 participants