From a00788d735f13b08f0aa8c98f003b0eec3da87d7 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 6 Jul 2020 13:43:24 +0200 Subject: [PATCH] Fix #9295: Avoid recursive Dynamics conversion Avoid trying to apply `Dynamic` transformation on `apply` with a qualifier that already has a been handled by the `Dynamic` transformation. --- .../src/dotty/tools/dotc/typer/TypeAssigner.scala | 12 +++++++++++- tests/neg/i9295a.scala | 9 +++++++++ tests/neg/i9295b.scala | 14 ++++++++++++++ tests/neg/i9295c.scala | 12 ++++++++++++ tests/neg/i9295d.scala | 12 ++++++++++++ tests/pos/i9295.scala | 12 ++++++++++++ tests/pos/i9295b.scala | 12 ++++++++++++ tests/pos/i9295c.scala | 12 ++++++++++++ tests/pos/i9295d.scala | 12 ++++++++++++ 9 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i9295a.scala create mode 100644 tests/neg/i9295b.scala create mode 100644 tests/neg/i9295c.scala create mode 100644 tests/neg/i9295d.scala create mode 100644 tests/pos/i9295.scala create mode 100644 tests/pos/i9295b.scala create mode 100644 tests/pos/i9295c.scala create mode 100644 tests/pos/i9295d.scala diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 1ce0f6376b95..be6a43de3976 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -140,9 +140,19 @@ trait TypeAssigner { val name = tree.name val pre = maybeSkolemizePrefix(qualType, name) val mbr = qualType.findMember(name, pre) + def isDynamicExpansion(tree: untpd.RefTree): Boolean = { + Dynamic.isDynamicMethod(name) || ( + tree match + case Select(Apply(fun: untpd.RefTree, _), nme.apply) if defn.isContextFunctionClass(fun.symbol.owner) => + isDynamicExpansion(fun) + case Select(qual, nme.apply) => + Dynamic.isDynamicMethod(qual.symbol.name) && tree.span.isSynthetic + case _ => false + ) + } if (reallyExists(mbr)) qualType.select(name, mbr) - else if (qualType.derivesFrom(defn.DynamicClass) && name.isTermName && !Dynamic.isDynamicMethod(name)) + else if (qualType.derivesFrom(defn.DynamicClass) && name.isTermName && !isDynamicExpansion(tree)) TryDynamicCallType else if (qualType.isErroneous || name.toTermName == nme.ERROR) UnspecifiedErrorType diff --git a/tests/neg/i9295a.scala b/tests/neg/i9295a.scala new file mode 100644 index 000000000000..86acc959f931 --- /dev/null +++ b/tests/neg/i9295a.scala @@ -0,0 +1,9 @@ +import scala.language.dynamics + +class Foo extends Dynamic { + def applyDynamic(arg: Any): Foo = ??? +} +object F { + val foo = new Foo + def baz = foo.blah(43) // error: method applyDynamic in class Foo does not take more parameters +} diff --git a/tests/neg/i9295b.scala b/tests/neg/i9295b.scala new file mode 100644 index 000000000000..24a5c81eaede --- /dev/null +++ b/tests/neg/i9295b.scala @@ -0,0 +1,14 @@ +import scala.language.dynamics + +class Foo extends Dynamic { + def applyDynamic(arg: Any): Bar = ??? +} +class Bar extends Dynamic { + def applyDynamic(arg: Any)(x: Int): Int = ??? +} +object F { + val foo = new Foo + def baz = foo.blah(43) // error: method applyDynamic in class Foo does not take more parameters + def qux = foo.blah.blah(43) // error: value selectDynamic is not a member of Foo + def quxx = foo.blah().blah(43) // error: method applyDynamic in class Foo does not take more parameters +} diff --git a/tests/neg/i9295c.scala b/tests/neg/i9295c.scala new file mode 100644 index 000000000000..701b84fa4bcc --- /dev/null +++ b/tests/neg/i9295c.scala @@ -0,0 +1,12 @@ +import scala.language.dynamics + +class Foo extends Dynamic { + def selectDynamic(name: String)(using DummyImplicit): Bar = ??? +} + +class Bar extends Dynamic { + def applyDynamic(name: String)(x: Int) = ??? +} + +val foo = new Foo +def baz = foo.blah(42) // error diff --git a/tests/neg/i9295d.scala b/tests/neg/i9295d.scala new file mode 100644 index 000000000000..28c64d8fb77a --- /dev/null +++ b/tests/neg/i9295d.scala @@ -0,0 +1,12 @@ +import scala.language.dynamics + +class Foo extends Dynamic { + def applyDynamic(name: String)(): DummyImplicit ?=> Bar = ??? +} + +class Bar extends Dynamic { + def applyDynamic(name: String)(x: Int) = ??? +} + +val foo = new Foo +def baz = foo.blah()(42) // error diff --git a/tests/pos/i9295.scala b/tests/pos/i9295.scala new file mode 100644 index 000000000000..654ff1dc00d5 --- /dev/null +++ b/tests/pos/i9295.scala @@ -0,0 +1,12 @@ +import scala.language.dynamics + +class Foo extends Dynamic { + def applyDynamic(name: String)(): Bar = ??? +} + +class Bar extends Dynamic { + def applyDynamic(name: String)(x: Int) = ??? +} + +val foo = new Foo +def baz = foo.blah().apply(42) diff --git a/tests/pos/i9295b.scala b/tests/pos/i9295b.scala new file mode 100644 index 000000000000..071875b7fa24 --- /dev/null +++ b/tests/pos/i9295b.scala @@ -0,0 +1,12 @@ +import scala.language.dynamics + +class Foo extends Dynamic { + def applyDynamic(name: String)()(using DummyImplicit): Bar = ??? +} + +class Bar extends Dynamic { + def applyDynamic(name: String)(x: Int) = ??? +} + +val foo = new Foo +def baz = foo.blah().apply(42) diff --git a/tests/pos/i9295c.scala b/tests/pos/i9295c.scala new file mode 100644 index 000000000000..f0e86339bf4c --- /dev/null +++ b/tests/pos/i9295c.scala @@ -0,0 +1,12 @@ +import scala.language.dynamics + +class Foo extends Dynamic { + def selectDynamic(name: String)(using DummyImplicit): Bar = ??? +} + +class Bar extends Dynamic { + def applyDynamic(name: String)(x: Int) = ??? +} + +val foo = new Foo +def baz = foo.blah.apply(42) diff --git a/tests/pos/i9295d.scala b/tests/pos/i9295d.scala new file mode 100644 index 000000000000..8488d71cc067 --- /dev/null +++ b/tests/pos/i9295d.scala @@ -0,0 +1,12 @@ +import scala.language.dynamics + +class Foo extends Dynamic { + def applyDynamic(name: String)(): DummyImplicit ?=> DummyImplicit ?=> Bar = ??? +} + +class Bar extends Dynamic { + def applyDynamic(name: String)(x: Int) = ??? +} + +val foo = new Foo +def baz = foo.blah().apply(42)