dotty-cps-async icon indicating copy to clipboard operation
dotty-cps-async copied to clipboard

Help: Is there a support for AsyncShift for extension on opaque types?

Open ahoy-jon opened this issue 7 months ago • 5 comments

I am currently working on https://github.com/getkyo/kyo/issues/1209, and I struggle to have AsyncShift working on Result[?, ?] or Maybe[?].

For this code:

opaque type Maybe[+A] >: (Absent | Present[A]) = Absent | Present[A]

object Maybe:
  extension [A](self: Maybe[A])
    inline def map[B](inline f: A => B): Maybe[B] =
            if isEmpty then Absent else f(get)  
val x: Maybe[Int] = Maybe(1)
def f(i: Int): Int < Any = i + 1
"map" in {
    val d = defer:
        x.map(i => f(i).now)
    assert(d.eval == Maybe(1))
}

I get this error (simplified):

Can't shift caller kyo.Maybe$package.Maybe.map[Int](x)[Int] (
tree TypeApply(Apply(
            TypeApply(Select(Ident(Maybe),map), List(TypeTree[Int])),
            List(Ident(x))
          ),
          List(TypeTree[Int])))

while there is this definition for the AsyncShift

object MaybeAsyncShift extends AsyncShift[Maybe.type]:
    def map[F[_], A, B](obj: Maybe.type, monad: CpsMonad[F])(c: Maybe[A])(f: A => F[B]): F[Maybe[B]] =
        c.fold(monad.pure(Maybe.empty))(a => monad.map(f(a))(b => Maybe(b)))

transparent inline given shiftedMaybe: MaybeAsyncShift.type = MaybeAsyncShift

Changing the signature to:

        def map[F[_], A](obj: Maybe.type, monad: CpsMonad[F])(c: Maybe[A])[B](f: A => F[B]): F[Maybe[B]] =
            c.fold(monad.pure(Maybe.empty))(a => monad.map(f(a))(b => Maybe(b)))

Doesn't change anything. Do you think there is a way to implement AsyncShift on Maybe currently?

ahoy-jon avatar May 26 '25 17:05 ahoy-jon

Hmm, can you define in scope implicit value cps.macros.flags.PrintCode and look on expression, which dotty-cps-async try to reduce.

implicit val printCode = cps.macroFlags.PrintCode
<code-which-not-compiled>

In such a way we will see the actual expression which should be reduced. Also, a small self-contained example would be helpful.

rssh avatar May 27 '25 06:05 rssh

I have reproduced something similar: https://github.com/dotty-cps-async/dotty-cps-async/commit/a1c8baf796d4a002aa17eef53c3d9a8e65f04f48

Don;'t work now, will think, how to include this functionality in the next minor release.

rssh avatar May 27 '25 06:05 rssh

Thank you so much @rssh! Definitely will work with cps.macros.flags.PrintCode.

ahoy-jon avatar May 27 '25 09:05 ahoy-jon

Hi, I have implemented preliminary support for shifting extension methods. Example is in https://github.com/dotty-cps-async/dotty-cps-async/blob/master/shared/src/test/scala/cpstest/TestOpaqueAsyncShift.scala. (omitt commented-output variants for now).

This is preliminary and has not been published (for release, we need to write the documentation and implement the same functionality for the compiler plugin). However, you may want to experiment with the locally built master branch.

rssh avatar Jun 01 '25 15:06 rssh

Thanks a lot, it works like the tests: https://github.com/ahoy-jon/kyo/commit/4db4d029f7c805a98c84bc778c64a9d4e288d92a

ahoy-jon avatar Jun 02 '25 14:06 ahoy-jon

published 1.1.0

rssh avatar Jun 14 '25 09:06 rssh

@rssh it's working, thank you (cf. https://github.com/getkyo/kyo/pull/1263)

ahoy-jon avatar Jun 14 '25 15:06 ahoy-jon