CpsMonad for type alias broke from 0.3.5 to 0.4.0
rcano opened this issue · 12 comments
In 0.3.5 I could have a CpsMonad for an alias type:
type MyMonad[T] = MyActualType
given cps.CpsMonad[MyMonad] with {...}
and this worked just fine. In 0.4.0 this broke, and now I get
java.lang.RuntimeException: Can't find async monad for [T >: scala.Nothing <: scala.Any] => MyActualType (transformImpl)
| => sat cps.Async$.transformImpl(Async.scala:56)
Not sure how to work around this. I am aware that this is in some ways stretching the functionality, but it worked just fine in the previous version so perhaps there's hope :)
Will look. Can you attach a small self-contained test case? (file or small sbt project without extra dependencies is ok)
(it can be a reincarnation of scala/scala3#11479 , but need to look at the example to say something definitely)
Will do, in a couple of hours
Here's a way to reproduce it, note that I did find a work around by turning my type opaque
object BugRepro {
object UsedToCompile {
object MyType
type PseudoMonad[T] = MyType.type
given myCpsMonad: cps.CpsMonad[PseudoMonad] with {
def flatMap[A, B](fa: PseudoMonad[A])(f: A => PseudoMonad[B]): PseudoMonad[B] = MyType
def map[A, B](fa: PseudoMonad[A])(f: A => B): PseudoMonad[B] = MyType
def pure[T](t: T): PseudoMonad[T] = MyType
}
cps.async(using myCpsMonad) {
cps.await(MyType)
}
}
object StillCompiles {
object MyType
object opaques {
opaque type PseudoMonad[T] = MyType.type
}
type PseudoMonad[T] = opaques.PseudoMonad[T]
given [T]: Conversion[PseudoMonad[T], MyType.type] = _.asInstanceOf[MyType.type]
given [T]: Conversion[MyType.type, PseudoMonad[T]] = _.asInstanceOf[PseudoMonad[T]]
given myCpsMonad: cps.CpsMonad[PseudoMonad] with {
def flatMap[A, B](fa: PseudoMonad[A])(f: A => PseudoMonad[B]): PseudoMonad[B] = MyType
def map[A, B](fa: PseudoMonad[A])(f: A => B): PseudoMonad[B] = MyType
def pure[T](t: T): PseudoMonad[T] = MyType
}
cps.async(using myCpsMonad) {
cps.await(MyType)
}
}
}
Actually, hold on, I don't think the above accurately captures my problem, because in the above example, if I do cps.await[PseudoMonad, Any(MyType)
] then it still compiles. I think there's another layer that I'm doing that's causing the issue.
Ok, thanks.
(During waiting the problem example, let's look on current test-case:
[error] -- [E007] Type Mismatch Error: /Users/rssh/work/oss/dotty-cps/dotty-cps/shared/src/test/scala/cps/TestIssue32.scala:13:16
[error] 13 | cps.await(MyType)
[error] | ^^^^^^
[error] |Found: BugRepro.UsedToCompile.MyType.type
[error] |Required: ([_$1] =>> Any)[T]
[error] |
[error] |where: T is a type variable with constraint
[error] |
[error] |Note that implicit conversions cannot be applied because they are ambiguous;
[error] |both method ArrowAssoc in object Predef and method Ensuring in object Predef convert from BugRepro.UsedToCompile.MyType.type to ([_$1] =>> Any)[T]
[error] -- Error: /Users/rssh/work/oss/dotty-cps/dotty-cps/shared/src/test/scala/cps/TestIssue32.scala:13:23
[error] 13 | cps.await(MyType)
[error] | ^
[error] |no implicit argument of type cps.CpsMonad[([_$1] =>> Any)] was found for parameter am of method await in package cps
And looks like this is before macro.
I was able to minimize this to a small program without dptty-cps-async:
trait CpsMonad[F[_]]
def await1[F[_],T](f:F[T])(using am:CpsMonad[F]):T = ???
object MyType
type PseudoMonad[T] = MyType.type
given myCpsMonad: CpsMonad[PseudoMonad] with { }
object UsedToCompile {
await1(MyType)
}
Which, I guess, illustrates the dotty bug.
Hmm, maybe not a bug: it can't transform
MyType
to PseudoMonad[T]
, but what this T should be ?.
Any ?, Nothing ?
Hmm, maybe not a bug: it can't transform
MyType
toPseudoMonad[T]
, but what this T should be ?.
Any ?, Nothing ?
I'd say anything the compiler want's to infer, which I bet is Nothing.
Neverhtless I think I found the source of my bug here, the method requests an implicit CpsMonad[F], but it doesn't handle it over to the macro, which then proceeds to do Expr.summon[CpsMonad[F]]
to find it.
My problem arises because I'm hiding the cps.async/await calls behind my own inlined calls (that make sense with my DSL), and even though I explicitly typed and pass the implicits manually, that summon still trips up.
As soon as I'm done with work I'll try to reproduce it
I copied pasted the code from my library onto a clean package and it's not happening 😩. Nevertheless the original code in the original location triggers it everytime. Don't know what to do here, in any case, please take a look at the implicit CpsMonad not being forwarded to the macro because maybe that is doable and fixes it for me.
Sorry for the noise.
Yes, minimization can be difficult. Check - are you use top-level given in other source file ? (this will exclude scala/scala3#11479 )
Yet one changes which come to mind, -- starting with 3.0.0-RC1, evaluation of non-transparent macroses moved from Typer to later phase, and now if you macro include await -- it should be transparent).
btw, submitted test-case about not looking into alias to dotty scala/scala3#11607
And close one, because the compiler error is correct: we pass an instance of MyType, the compiler can't deduce PseudoMonad[X]. from MyType, because it's see MyType as an argument, not PseudoMonad.
looks dormant, so can be closed. Free to reopen if find a way to reproduce with the newest version.