diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index 859648a47c6a..48d8530751eb 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -76,9 +76,23 @@ object Inlines: case _ => false tree.symbol.name.isUnapplyName && rec(tree) - isInlineable(tree.symbol) + val sym = tree.symbol + sym.is(Inline) && sym.hasAnnotation(defn.BodyAnnot) && !tree.tpe.widenTermRefExpr.isInstanceOf[MethodOrPoly] && StagingLevel.level == 0 + && ( + // Outside of inline method bodies, any inline call may be inlined. + !inInlineMethod + // Inside inline method bodies, a transparent inline given must still be + // expanded at typer so that dependent type members of its result + // (e.g. `tc.Out` from `fromVal[Int, Int]`) are known when typing the + // enclosing body; otherwise the implicit-argument reference is + // non-stable and gets skolemized, making `tc.Out` opaque. See #15798. + // Macro-based givens are excluded: eager expansion of their bodies + // would run a macro at the def site with abstract types, typically + // causing cyclic-macro-dependency errors (see tests/neg-macros/i18695). + || (sym.is(Given) && !sym.is(Macro) && needsTransparentInlining(tree)) + ) && ( ctx.phase == Phases.inliningPhase || (ctx.phase == Phases.typerPhase && needsTransparentInlining(tree)) diff --git a/tests/pos/i15798.scala b/tests/pos/i15798.scala new file mode 100644 index 000000000000..1020832b55e6 --- /dev/null +++ b/tests/pos/i15798.scala @@ -0,0 +1,25 @@ +import compiletime.ops.* + +class Inlined[T](val value : T) +object Inlined: + trait TC[UB, R]: + type Out <: UB + def apply(arg: R): Inlined[Out] + object TC: + transparent inline given fromVal[UB, R <: UB]: TC[UB, R] = new TC[UB, R]: + type Out = R + def apply(arg: R): Inlined[R] = forced[R](arg) + transparent inline given fromInline[UB, R <: UB, I <: Inlined[R]]: TC[UB, I] = + new TC[UB, I]: + type Out = R + def apply(arg: I): Inlined[R] = arg + + protected inline def forced[T](_value: Any): Inlined[T] = Inlined[T](_value.asInstanceOf[T]) + + def add[T <: Int, R](lhs: Inlined[T], rhs: R)(using tc: TC[Int, R]) = + forced[int.+[T, tc.Out]](lhs.value + tc(rhs).value) + def get[T <: Int](inlined: Inlined[T]) : T = inlined.value + +object Test: + inline def check[UB <: Int](ub: Inlined[UB]): Unit = + val y = Inlined.get(Inlined.add(ub, 1))