From b96a235536579829b0e30a7daeba038ae4a71c33 Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Wed, 3 Jul 2024 18:21:36 +0200 Subject: [PATCH] Add structural classes of dynamicApply before inlining [Cherry-picked 716304263bc6f21362c7c19877e0f0995d2c0886][modified] --- 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 88b5308c058d..3a5758427a25 100644 --- a/compiler/src/dotty/tools/dotc/core/Mode.scala +++ b/compiler/src/dotty/tools/dotc/core/Mode.scala @@ -147,6 +147,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 61e2a58a0176..cf6af25df036 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -63,6 +63,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 6dde9e10c833..df4aa9f4de40 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -361,7 +361,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { 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 = Inlines.inlineCallTrace(call.symbol, pos)(using ctx.withSource(pos.source)) cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(tree))) case templ: Template => @@ -512,7 +512,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { 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 db87ece77eb7..14cc7bf963a6 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.* @@ -17,6 +19,7 @@ import core.Symbols.* import transform.ValueClasses import ErrorReporting.* import reporting.* +import inlines.Inlines object Dynamic { private def isDynamicMethod(name: Name): Boolean = @@ -209,7 +212,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