From d92e81e405187f521defc6f10c3c48ce0240e310 Mon Sep 17 00:00:00 2001 From: Arman Bilge Date: Fri, 13 Aug 2021 16:21:25 +0000 Subject: [PATCH] Backport thunk --- .../src/main/scala/cats/effect/IO.scala | 4 +-- .../src/main/scala/cats/effect/Thunk.scala | 29 +++++++++++++++++++ .../test/scala/cats/effect/ThunkSpec.scala | 27 +++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 core/shared/src/main/scala/cats/effect/Thunk.scala create mode 100644 core/shared/src/test/scala/cats/effect/ThunkSpec.scala diff --git a/core/shared/src/main/scala/cats/effect/IO.scala b/core/shared/src/main/scala/cats/effect/IO.scala index e1fa6f774f..158ba2c18b 100644 --- a/core/shared/src/main/scala/cats/effect/IO.scala +++ b/core/shared/src/main/scala/cats/effect/IO.scala @@ -1152,7 +1152,7 @@ object IO extends IOInstances { * `IO`. */ def defer[A](thunk: => IO[A]): IO[A] = { - val nextIo = Suspend(() => thunk) + val nextIo = Suspend(Thunk.asFunction0(thunk)) if (isFullStackTracing) { IOTracing.decorated(nextIo) } else { @@ -1167,7 +1167,7 @@ object IO extends IOInstances { * into the `IO`. */ def delay[A](body: => A): IO[A] = { - val nextIo = Delay(() => body) + val nextIo = Delay(Thunk.asFunction0(body)) if (isFullStackTracing) { IOTracing.decorated(nextIo) } else { diff --git a/core/shared/src/main/scala/cats/effect/Thunk.scala b/core/shared/src/main/scala/cats/effect/Thunk.scala new file mode 100644 index 0000000000..26aa85b855 --- /dev/null +++ b/core/shared/src/main/scala/cats/effect/Thunk.scala @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2017-2021 The Typelevel Cats-effect Project Developers + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cats.effect + +/** + * A utility to convert a by-name `thunk: => A` to a `Function0[A]` (its binary representation). + * Scala 2 performs this optimization automatically but on Scala 3 the thunk is wrapped inside of a new `Function0`. + * See https://github.com/typelevel/cats-effect/pull/2226 + */ +private object Thunk { + private[this] val impl = + ((x: Any) => x).asInstanceOf[(=> Any) => Function0[Any]] + + def asFunction0[A](thunk: => A): Function0[A] = impl(thunk).asInstanceOf[Function0[A]] +} diff --git a/core/shared/src/test/scala/cats/effect/ThunkSpec.scala b/core/shared/src/test/scala/cats/effect/ThunkSpec.scala new file mode 100644 index 0000000000..42c3b52c3a --- /dev/null +++ b/core/shared/src/test/scala/cats/effect/ThunkSpec.scala @@ -0,0 +1,27 @@ +/* + * Copyright 2020-2021 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cats.effect + +class ThunkSpec extends CatsEffectSuite { + + test("Thunk.asFunction0") { + var i = 0 + val f = () => i += 1 + assertEquals(Thunk.asFunction0(f()), f) + } + +}