From 716304263bc6f21362c7c19877e0f0995d2c0886 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 26 Oct 2023 16:43:06 +0200 Subject: [PATCH] Add structural classes of dynamicApply before inlining --- compiler/src/dotty/tools/dotc/core/Mode.scala | 4 +-- .../dotty/tools/dotc/inlines/Inlines.scala | 1 + .../tools/dotc/transform/PostTyper.scala | 4 +-- .../src/dotty/tools/dotc/typer/Dynamic.scala | 10 +++++- tests/run/i17761.check | 8 +++++ tests/run/i17761.scala | 33 +++++++++++++++++++ 6 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 tests/run/i17761.check create mode 100644 tests/run/i17761.scala diff --git a/compiler/src/dotty/tools/dotc/core/Mode.scala b/compiler/src/dotty/tools/dotc/core/Mode.scala index 133d110cabda..71b49394ae14 100644 --- a/compiler/src/dotty/tools/dotc/core/Mode.scala +++ b/compiler/src/dotty/tools/dotc/core/Mode.scala @@ -163,6 +163,6 @@ object Mode { */ val RelaxedOverriding: Mode = newMode(30, "RelaxedOverriding") - /** We are checking the original call of an Inlined node */ - val InlinedCall: Mode = newMode(31, "InlinedCall") + /** Skip inlining of methods. */ + val NoInline: Mode = newMode(31, "NoInline") } diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index 6b41f65e2fdd..5bdd0bb98495 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -64,6 +64,7 @@ object Inlines: ) && !ctx.typer.hasInliningErrors && !ctx.base.stopInlining + && !ctx.mode.is(Mode.NoInline) } private def needsTransparentInlining(tree: Tree)(using Context): Boolean = diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 79470addd03d..e59f5e1c40ab 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -366,7 +366,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => case tree @ Inlined(call, bindings, expansion) if !tree.inlinedFromOuterScope => val pos = call.sourcePos CrossVersionChecks.checkExperimentalRef(call.symbol, pos) - withMode(Mode.InlinedCall)(transform(call)) + withMode(Mode.NoInline)(transform(call)) val callTrace = ref(call.symbol)(using ctx.withSource(pos.source)).withSpan(pos.span) cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(tree))) case templ: Template => @@ -520,7 +520,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => if (sym.isEffectivelyErased) dropInlines.transform(rhs) else rhs private def registerNeedsInlining(tree: Tree)(using Context): Unit = - if tree.symbol.is(Inline) && !Inlines.inInlineMethod && !ctx.mode.is(Mode.InlinedCall) then + if tree.symbol.is(Inline) && !Inlines.inInlineMethod && !ctx.mode.is(Mode.NoInline) then ctx.compilationUnit.needsInlining = true /** Check if the definition has macro annotation and sets `compilationUnit.hasMacroAnnotations` if needed. */ diff --git a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala index 71b32b639997..91f863eacfd3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala +++ b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala @@ -7,6 +7,8 @@ import dotty.tools.dotc.ast.tpd import dotty.tools.dotc.ast.untpd import dotty.tools.dotc.core.Constants.Constant import dotty.tools.dotc.core.Contexts.* +import dotty.tools.dotc.core.Flags.* +import dotty.tools.dotc.core.Mode import dotty.tools.dotc.core.Names.{Name, TermName} import dotty.tools.dotc.core.StdNames.* import dotty.tools.dotc.core.Types.* @@ -18,6 +20,7 @@ import ErrorReporting.* import dotty.tools.dotc.transform.ValueClasses import dotty.tools.dotc.transform.TypeUtils.isPrimitiveValueType import reporting.* +import inlines.Inlines object Dynamic { private def isDynamicMethod(name: Name): Boolean = @@ -210,7 +213,12 @@ trait Dynamic { case _ => tree case other => tree case _ => tree - addClassOfs(typed(scall)) + + // We type the application of `applyDynamic` without inlining (arguments are already typed and inlined), + // to be able to add the add the Class arguments before we inline the method. + val call = addClassOfs(withMode(Mode.NoInline)(typed(scall))) + if Inlines.needsInlining(call) then Inlines.inlineCall(call) + else call } def fail(reason: String): Tree = diff --git a/tests/run/i17761.check b/tests/run/i17761.check new file mode 100644 index 000000000000..6e31f05b09df --- /dev/null +++ b/tests/run/i17761.check @@ -0,0 +1,8 @@ +Normal +test +ArraySeq(class java.lang.String, int) +ArraySeq(test, 42) +Transparent +test +ArraySeq(class java.lang.String, int) +ArraySeq(test, 42) diff --git a/tests/run/i17761.scala b/tests/run/i17761.scala new file mode 100644 index 000000000000..258773aef940 --- /dev/null +++ b/tests/run/i17761.scala @@ -0,0 +1,33 @@ +class MyRecord extends Selectable: + def applyDynamic(name: String, paramClasses: Class[_]*)(args: Any*): Any = { + println(name) + println(paramClasses) + println(args) + () + } + +class MyRecordTransparent extends Selectable: + inline transparent def applyDynamic(name: String, paramClasses: Class[_]*)(args: Any*): Any = { + println(name) + println(paramClasses) + println(args) + () + } + +type Person = MyRecord { + def test(a: String, b: Int): Unit +} + + +type PersonTransparent = MyRecordTransparent { + def test(a: String, b: Int): Unit +} + +val person = MyRecord().asInstanceOf[Person] +val personTransparent = MyRecordTransparent().asInstanceOf[PersonTransparent] + +@main def Test: Unit = + println("Normal") + person.test("test", 42) + println("Transparent") + personTransparent.test("test", 42) \ No newline at end of file