Skip to content

Commit a8ee53c

Browse files
authored
Avoid cyclic references due to experimental check when inlining (#16195)
2 parents 17776df + e75d7c5 commit a8ee53c

File tree

5 files changed

+53
-2
lines changed

5 files changed

+53
-2
lines changed

compiler/src/dotty/tools/dotc/inlines/Inlines.scala

+4-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ object Inlines:
8585
if (tree.symbol == defn.CompiletimeTesting_typeChecks) return Intrinsics.typeChecks(tree)
8686
if (tree.symbol == defn.CompiletimeTesting_typeCheckErrors) return Intrinsics.typeCheckErrors(tree)
8787

88-
CrossVersionChecks.checkExperimentalRef(tree.symbol, tree.srcPos)
88+
if ctx.isAfterTyper then
89+
// During typer we wait with cross version checks until PostTyper, in order
90+
// not to provoke cyclic references. See i16116 for a test case.
91+
CrossVersionChecks.checkExperimentalRef(tree.symbol, tree.srcPos)
8992

9093
if tree.symbol.isConstructor then return tree // error already reported for the inline constructor definition
9194

compiler/src/dotty/tools/dotc/transform/PostTyper.scala

+1
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
360360
}
361361
case Inlined(call, bindings, expansion) if !call.isEmpty =>
362362
val pos = call.sourcePos
363+
CrossVersionChecks.checkExperimentalRef(call.symbol, pos)
363364
val callTrace = Inlines.inlineCallTrace(call.symbol, pos)(using ctx.withSource(pos.source))
364365
cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(call)))
365366
case templ: Template =>

tests/neg-custom-args/no-experimental/experimentalInline.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ import scala.annotation.experimental
44
inline def g() = ()
55

66
def test: Unit =
7-
g() // errors
7+
g() // error
88
()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import scala.annotation.experimental
2+
3+
@experimental
4+
transparent inline def g() = ()
5+
6+
def test: Unit =
7+
g() // error
8+
()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package x
2+
3+
import scala.annotation.*
4+
import scala.concurrent.*
5+
6+
trait CpsMonad[F[_]] {
7+
type Context
8+
}
9+
10+
object CpsMonad {
11+
type Aux[F[_],C] = CpsMonad[F] { type Context = C }
12+
given CpsMonad[Future] with {}
13+
}
14+
15+
@experimental
16+
object Test {
17+
18+
@capability
19+
class CpsTransform[F[_]] {
20+
def await[T](ft: F[T]): { this } T = ???
21+
}
22+
23+
transparent inline def cpsAsync[F[_]](using m:CpsMonad[F]) =
24+
new Test.InfernAsyncArg
25+
26+
class InfernAsyncArg[F[_],C](using am:CpsMonad.Aux[F,C]) {
27+
def apply[A](expr: (CpsTransform[F], C) ?=> A): F[A] = ???
28+
}
29+
30+
def asyncPlus[F[_]](a:Int, b:F[Int])(using cps: CpsTransform[F]): { cps } Int =
31+
a + (cps.await(b).asInstanceOf[Int])
32+
33+
def testExample1Future(): Unit =
34+
val fr = cpsAsync[Future] {
35+
val y = asyncPlus(1,Future successful 2).asInstanceOf[Int]
36+
y+1
37+
}
38+
39+
}

0 commit comments

Comments
 (0)