-
Notifications
You must be signed in to change notification settings - Fork 64
defer blocks discarding unit effects #903
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
Comments
Workaround: annotating |
/bounty 100 |
I took a look at this and couldn't find a way to fix it. It seems the compiler just bypasses the check. cc/ @rssh |
I may have found something similar //> using scala 3.7.0-RC3
//> using option -Wvalue-discard
//> using option -Wnonunit-statement
//> using option -Wconf:msg=(unused.*value|discarded.*value|pure.*statement):error
//> using option -language:strictEquality
//> using dep io.getkyo::kyo-prelude::0.18.0
//> using dep io.getkyo::kyo-core::0.18.0
//> using dep io.getkyo::kyo-direct::0.18.0
//> using dep io.getkyo::kyo-combinators::0.18.0
import kyo.*
object KyoAppTest extends KyoApp {
val print: Unit < IO = Console.printLine("YO")
val fail: Unit < Abort[Exception] = Abort.fail(new Exception("fail"))
val prg = print *> fail
val prgWithDefer = defer {
print.now
fail.now
}
val oups: Unit < (IO & Abort[Exception]) = defer {
Console.printLine("YO").now
Abort.fail(new Exception("fail")).now
}
val fixOups: Unit < (IO & Abort[Exception]) = defer {
Console.printLine("YO").now
Abort.fail(new Exception("fail")).now
{}
}
val prgs= Chunk(prg, prgWithDefer, oups, fixOups).zipWithIndex
val all = Kyo.foreach(prgs)((prg, i) => Console.printLine(i) *> Abort.run(prg))
run(all.unit)
}
so it doesn't execute properly "oups" val oups: Unit < (IO & Abort[Exception]) = defer {
Console.printLine("YO").now
Abort.fail(new Exception("fail")).now
} but it works for val fixOups: Unit < (IO & Abort[Exception]) = defer {
Console.printLine("YO").now
Abort.fail(new Exception("fail")).now
{}
} and other versions, such as val oups: Unit < (IO & Abort[Exception]) = defer {
Console.printLine("YO").now
Abort.fail(new Exception("fail")).unit.now
} There is a discard of the block for |
def runInner: Unit < Async = defer:
Console.printLine("test").now
object Kyo903 extends KyoApp {
run(runInner)
} produce
don't produce a compile error, and don't produce a result |
So, what is happening. With this code def runInnerOK: Unit < IO = defer:
Console.printLine("test").now
def runInnerNOK: Unit < Any = defer:
Console.printLine("test").now we have (decompiled) public Object runInnerOK() {
LazyRef var1 = new LazyRef();
Async.InferAsyncArg InferAsyncArg_this = new Async.InferAsyncArg(this.given_KyoCpsMonad_s$5(var1));
return InferAsyncArg_this.am().apply(RunInner$::runInnerOK$$anonfun$1);
}
public Object runInnerNOK() {
Pending.package var1 = .MODULE$;
LazyRef var4 = new LazyRef();
Async.InferAsyncArg InferAsyncArg_this = new Async.InferAsyncArg(this.given_KyoCpsMonad_s$6(var4));
InferAsyncArg_this.am().apply(RunInner$::$anonfun$1);
BoxedUnit v$proxy7 = BoxedUnit.UNIT;
return v$proxy7;
} Which show that the compiler is inserting a BoxedUnit.UNIT, and returns it, and doesn't warn on def anyCallToUnit: Unit < Any =
runInnerOK
The problem can be reproduced with transparent inline def toto: Unit < IO = Console.printLine("test")
def tata: Unit < Any =
toto public Object tata() {
Pending.package var1 = .MODULE$;
Frame.package.Frame var4 = kyo.Frame.package.Frame..MODULE$;
Frame.package var5 = kyo.Frame.package..MODULE$;
kyo.Console..MODULE$.printLine("test", "0dependent.scala:111:5|dependant.RunInner$|tata|def tata: Unit < Any =\n toto\ud83d\udccd");
BoxedUnit v$proxy8 = BoxedUnit.UNIT;
return v$proxy8;
} It is an issue with |
Done, it's here : scala/scala3#23018 Maybe it would be nice to have some Scalafix rules to detect those cases, opaque type Unit <: scala.Unit = scala.Unit solutions for now val x = defer { ... } .unit
val x:Any < ... = defer {...} |
created a Scalafix rule to help with it: https://github.com/ahoy-jon/kyo-scalafix-rules |
val runLayer: Unit < Any = {
Env.runLayer(Layer.empty)(Console.printLine("test"))
}
val provide: Unit < Any = {
Console.printLine("test").provide(Layer.empty)
} and probably |
#1202 solves the issue, by making the compiler report errors for those cases. |
Nice work! |
Pretty cool! Thank you @ahoy-jon |
Thank you! To make it clear, it fixes problems with:
transparent inline def toto: Unit < IO = Console.printLine("test")
def tata: Unit < Any =
toto |
Minimized example
scalac options in build.sbt:
Expected result
Should cause compiler error:
discarded non-Unit value of type Unit < (kyo.IO & kyo.Abort[java.io.IOException])
(If thedefer
block inrunInner
is replaced with a direct call toConsole.println
, this is what happens)Actual result
No compiler error or warnings, and the application runs without displaying anything message
The text was updated successfully, but these errors were encountered: