diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 7aa770a25bb2..79ac75432da9 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -287,6 +287,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => super.transform(tree)(using gadtCtx) case tree: Ident => if tree.isType then + Checking.checkPolyFunctionType(tree) checkNotPackage(tree) else checkNoConstructorProxy(tree) @@ -299,6 +300,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => registerNeedsInlining(tree) if name.isTypeName then Checking.checkRealizable(qual.tpe, qual.srcPos) + Checking.checkPolyFunctionType(tree) withMode(Mode.Type)(super.transform(checkNotPackage(tree))) else checkNoConstructorProxy(tree) @@ -370,7 +372,6 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => 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 => - Checking.checkPolyFunctionExtension(templ) withNoCheckNews(templ.parents.flatMap(newPart)) { forwardParamAccessors(templ) synthMbr.addSyntheticMembers( @@ -382,7 +383,6 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => case tree: ValDef => registerIfHasMacroAnnotations(tree) checkErasedDef(tree) - Checking.checkPolyFunctionType(tree.tpt) val tree1 = cpy.ValDef(tree)(rhs = normalizeErasedRhs(tree.rhs, tree.symbol)) if tree1.removeAttachment(desugar.UntupledParam).isDefined then checkStableSelection(tree.rhs) @@ -390,7 +390,6 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => case tree: DefDef => registerIfHasMacroAnnotations(tree) checkErasedDef(tree) - Checking.checkPolyFunctionType(tree.tpt) annotateContextResults(tree) val tree1 = cpy.DefDef(tree)(rhs = normalizeErasedRhs(tree.rhs, tree.symbol)) processValOrDefDef(superAcc.wrapDefDef(tree1)(super.transform(tree1).asInstanceOf[DefDef])) @@ -495,9 +494,6 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => ) case Block(_, Closure(_, _, tpt)) if ExpandSAMs.needsWrapperClass(tpt.tpe) => superAcc.withInvalidCurrentClass(super.transform(tree)) - case tree: RefinedTypeTree => - Checking.checkPolyFunctionType(tree) - super.transform(tree) case _: Quote | _: QuotePattern => ctx.compilationUnit.needsStaging = true super.transform(tree) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index e7d25c797c34..ac71fabe36fa 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -825,38 +825,11 @@ object Checking { case _ => end checkExperimentalImports - /** Checks that PolyFunction only have valid refinements. - * - * It only supports `apply` methods with one parameter list and optional type arguments. - */ - def checkPolyFunctionType(tree: Tree)(using Context): Unit = new TreeTraverser { - def traverse(tree: Tree)(using Context): Unit = tree match - case tree: RefinedTypeTree if tree.tpe.derivesFrom(defn.PolyFunctionClass) => - if tree.refinements.isEmpty then - reportNoRefinements(tree.srcPos) - tree.refinements.foreach { - case refinement: DefDef if refinement.name != nme.apply => - report.error("PolyFunction only supports apply method refinements", refinement.srcPos) - case refinement: DefDef if !defn.PolyFunctionOf.isValidPolyFunctionInfo(refinement.tpe.widen) => - report.error("Implementation restriction: PolyFunction apply must have exactly one parameter list and optionally type arguments. No by-name nor varags are allowed.", refinement.srcPos) - case _ => - } - case _: RefTree if tree.symbol == defn.PolyFunctionClass => - reportNoRefinements(tree.srcPos) - case _ => - traverseChildren(tree) - - def reportNoRefinements(pos: SrcPos) = - report.error("PolyFunction subtypes must refine the apply method", pos) - }.traverse(tree) + /** Checks that PolyFunction is not used directly */ + def checkPolyFunctionType(tree: RefTree)(using Context): Unit = + if tree.symbol == defn.PolyFunctionClass then + report.error(s"Direct use of `PolyFunction` is not allowed. Use lambda instead.", tree.srcPos) - /** Check that users do not extend the `PolyFunction` trait. - * We only allow compiler generated `PolyFunction`s. - */ - def checkPolyFunctionExtension(templ: Template)(using Context): Unit = - templ.parents.find(_.tpe.derivesFrom(defn.PolyFunctionClass)) match - case Some(parent) => report.error(s"`PolyFunction` marker trait is reserved for compiler generated refinements", parent.srcPos) - case None => } trait Checking { diff --git a/tests/neg/i10075.check b/tests/neg/i10075.check index 6f3e9ab4334a..bffcb9c155f3 100644 --- a/tests/neg/i10075.check +++ b/tests/neg/i10075.check @@ -1,32 +1,36 @@ --- Error: tests/neg/i10075.scala:8:24 ---------------------------------------------------------------------------------- -8 |trait PolyTrait extends PolyFunction // error +-- Error: tests/neg/i10075.scala:9:24 ---------------------------------------------------------------------------------- +9 |trait PolyTrait extends PolyFunction // error | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements --- Error: tests/neg/i10075.scala:10:24 --------------------------------------------------------------------------------- -10 |class PolyClass extends PolyTrait { // error - | ^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements --- Error: tests/neg/i10075.scala:14:26 --------------------------------------------------------------------------------- -14 |object PolyObject extends PolyFunction // error + | Direct use of `PolyFunction` is not allowed. Use lambda instead. +-- Error: tests/neg/i10075.scala:11:24 --------------------------------------------------------------------------------- +11 |class PolyClass extends PolyFunction { // error + | ^^^^^^^^^^^^ + | Direct use of `PolyFunction` is not allowed. Use lambda instead. +-- Error: tests/neg/i10075.scala:15:26 --------------------------------------------------------------------------------- +15 |object PolyObject extends PolyFunction // error | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements + | Direct use of `PolyFunction` is not allowed. Use lambda instead. -- Error: tests/neg/i10075.scala:2:14 ---------------------------------------------------------------------------------- 2 |val foo = new PolyFunction { } // error | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements --- Error: tests/neg/i10075.scala:3:14 ---------------------------------------------------------------------------------- -3 |val bar = new PolyFunction { def bar = 23 } // error - | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements + | Direct use of `PolyFunction` is not allowed. Use lambda instead. +-- Error: tests/neg/i10075.scala:3:21 ---------------------------------------------------------------------------------- +3 |val foo2 = new scala.PolyFunction { } // error + | ^^^^^^^^^^^^^^^^^^ + | Direct use of `PolyFunction` is not allowed. Use lambda instead. -- Error: tests/neg/i10075.scala:4:14 ---------------------------------------------------------------------------------- -4 |val baz = new PolyFunction { def apply = 23 } // error +4 |val bar = new PolyFunction { def bar = 23 } // error | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements + | Direct use of `PolyFunction` is not allowed. Use lambda instead. -- Error: tests/neg/i10075.scala:5:14 ---------------------------------------------------------------------------------- -5 |val qux = new PolyFunction { def apply[T] = 47 } // error +5 |val baz = new PolyFunction { def apply = 23 } // error + | ^^^^^^^^^^^^ + | Direct use of `PolyFunction` is not allowed. Use lambda instead. +-- Error: tests/neg/i10075.scala:6:14 ---------------------------------------------------------------------------------- +6 |val qux = new PolyFunction { def apply[T] = 47 } // error | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements --- Error: tests/neg/i10075.scala:6:15 ---------------------------------------------------------------------------------- -6 |val quxx = new PolyFunction { def apply[T](x: T): T = x } // error + | Direct use of `PolyFunction` is not allowed. Use lambda instead. +-- Error: tests/neg/i10075.scala:7:15 ---------------------------------------------------------------------------------- +7 |val quxx = new PolyFunction { def apply[T](x: T): T = x } // error | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements + | Direct use of `PolyFunction` is not allowed. Use lambda instead. diff --git a/tests/neg/i10075.scala b/tests/neg/i10075.scala index e1a255ec8b54..073af0b55613 100644 --- a/tests/neg/i10075.scala +++ b/tests/neg/i10075.scala @@ -1,5 +1,6 @@ val poly = [T] => (x: T) => x val foo = new PolyFunction { } // error +val foo2 = new scala.PolyFunction { } // error val bar = new PolyFunction { def bar = 23 } // error val baz = new PolyFunction { def apply = 23 } // error val qux = new PolyFunction { def apply[T] = 47 } // error @@ -7,7 +8,7 @@ val quxx = new PolyFunction { def apply[T](x: T): T = x } // error trait PolyTrait extends PolyFunction // error -class PolyClass extends PolyTrait { // error +class PolyClass extends PolyFunction { // error def apply[T](x: T): T = x } diff --git a/tests/neg/i18302a.scala b/tests/neg/i18302a.scala index dc4bc703c404..76e40441e86e 100644 --- a/tests/neg/i18302a.scala +++ b/tests/neg/i18302a.scala @@ -1,4 +1,4 @@ def test = polyFun(1) -def polyFun: PolyFunction { def apply(x: Int): Int } = +def polyFun: PolyFunction { def apply(x: Int): Int } = // error new PolyFunction { def apply(x: Int): Int = x + 1 } // error diff --git a/tests/neg/i18302b.check b/tests/neg/i18302b.check index 624c0cc0e415..b55859b800cf 100644 --- a/tests/neg/i18302b.check +++ b/tests/neg/i18302b.check @@ -1,8 +1,8 @@ --- Error: tests/neg/i18302b.scala:3:32 --------------------------------------------------------------------------------- +-- Error: tests/neg/i18302b.scala:3:13 --------------------------------------------------------------------------------- 3 |def polyFun: PolyFunction { def apply(x: Int)(y: Int): Int } = // error - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - |Implementation restriction: PolyFunction apply must have exactly one parameter list and optionally type arguments. No by-name nor varags are allowed. + | ^^^^^^^^^^^^ + | Direct use of `PolyFunction` is not allowed. Use lambda instead. -- Error: tests/neg/i18302b.scala:4:6 ---------------------------------------------------------------------------------- 4 | new PolyFunction: // error | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements + | Direct use of `PolyFunction` is not allowed. Use lambda instead. diff --git a/tests/neg/i18302c.check b/tests/neg/i18302c.check index 67dffcfae98c..1b8d7ceda9b6 100644 --- a/tests/neg/i18302c.check +++ b/tests/neg/i18302c.check @@ -1,8 +1,8 @@ --- Error: tests/neg/i18302c.scala:4:32 --------------------------------------------------------------------------------- +-- Error: tests/neg/i18302c.scala:4:13 --------------------------------------------------------------------------------- 4 |def polyFun: PolyFunction { def foo(x: Int): Int } = // error - | ^^^^^^^^^^^^^^^^^^^^ - | PolyFunction only supports apply method refinements + | ^^^^^^^^^^^^ + | Direct use of `PolyFunction` is not allowed. Use lambda instead. -- Error: tests/neg/i18302c.scala:5:6 ---------------------------------------------------------------------------------- 5 | new PolyFunction { def foo(x: Int): Int = x + 1 } // error | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements + | Direct use of `PolyFunction` is not allowed. Use lambda instead. diff --git a/tests/neg/i18302d.check b/tests/neg/i18302d.check index f052735a4db2..e7c3c6845f28 100644 --- a/tests/neg/i18302d.check +++ b/tests/neg/i18302d.check @@ -1,8 +1,8 @@ --- Error: tests/neg/i18302d.scala:1:32 --------------------------------------------------------------------------------- +-- Error: tests/neg/i18302d.scala:1:13 --------------------------------------------------------------------------------- 1 |def polyFun: PolyFunction { def apply: Int } = // error - | ^^^^^^^^^^^^^^ - |Implementation restriction: PolyFunction apply must have exactly one parameter list and optionally type arguments. No by-name nor varags are allowed. + | ^^^^^^^^^^^^ + | Direct use of `PolyFunction` is not allowed. Use lambda instead. -- Error: tests/neg/i18302d.scala:2:6 ---------------------------------------------------------------------------------- 2 | new PolyFunction { def apply: Int = 1 } // error | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements + | Direct use of `PolyFunction` is not allowed. Use lambda instead. diff --git a/tests/neg/i18302e.check b/tests/neg/i18302e.check index 7fbe19e8213d..1fc23d30aeb9 100644 --- a/tests/neg/i18302e.check +++ b/tests/neg/i18302e.check @@ -1,12 +1,12 @@ -- Error: tests/neg/i18302e.scala:1:13 --------------------------------------------------------------------------------- 1 |def polyFun: PolyFunction { } = // error - | ^^^^^^^^^^^^^^^^^ - | PolyFunction subtypes must refine the apply method + | ^^^^^^^^^^^^ + | Direct use of `PolyFunction` is not allowed. Use lambda instead. -- Error: tests/neg/i18302e.scala:2:6 ---------------------------------------------------------------------------------- 2 | new PolyFunction { } // error | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements + | Direct use of `PolyFunction` is not allowed. Use lambda instead. -- Error: tests/neg/i18302e.scala:4:15 --------------------------------------------------------------------------------- 4 |def polyFun(f: PolyFunction { }) = () // error - | ^^^^^^^^^^^^^^^^^ - | PolyFunction subtypes must refine the apply method + | ^^^^^^^^^^^^ + | Direct use of `PolyFunction` is not allowed. Use lambda instead. diff --git a/tests/neg/i18302f.check b/tests/neg/i18302f.check index 5231e894fabb..0208d5afb342 100644 --- a/tests/neg/i18302f.check +++ b/tests/neg/i18302f.check @@ -1,20 +1,20 @@ -- Error: tests/neg/i18302f.scala:1:13 --------------------------------------------------------------------------------- 1 |def polyFun: PolyFunction = // error | ^^^^^^^^^^^^ - | PolyFunction subtypes must refine the apply method + | Direct use of `PolyFunction` is not allowed. Use lambda instead. -- Error: tests/neg/i18302f.scala:2:6 ---------------------------------------------------------------------------------- 2 | new PolyFunction { } // error | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements + | Direct use of `PolyFunction` is not allowed. Use lambda instead. -- Error: tests/neg/i18302f.scala:4:16 --------------------------------------------------------------------------------- 4 |def polyFun2(a: PolyFunction) = () // error | ^^^^^^^^^^^^ - | PolyFunction subtypes must refine the apply method + | Direct use of `PolyFunction` is not allowed. Use lambda instead. -- Error: tests/neg/i18302f.scala:6:14 --------------------------------------------------------------------------------- 6 |val polyFun3: PolyFunction = // error | ^^^^^^^^^^^^ - | PolyFunction subtypes must refine the apply method + | Direct use of `PolyFunction` is not allowed. Use lambda instead. -- Error: tests/neg/i18302f.scala:7:6 ---------------------------------------------------------------------------------- 7 | new PolyFunction { } // error | ^^^^^^^^^^^^ - | `PolyFunction` marker trait is reserved for compiler generated refinements + | Direct use of `PolyFunction` is not allowed. Use lambda instead.