Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow use of PolyFunction in user code #18920

Merged
merged 1 commit into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/transform/PostTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ 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(
Expand Down
8 changes: 8 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,14 @@ object Checking {
def reportNoRefinements(pos: SrcPos) =
report.error("PolyFunction subtypes must refine the apply method", pos)
}.traverse(tree)

/** 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 {
Expand Down
2 changes: 1 addition & 1 deletion tests/run/erased-15.scala → tests/neg/erased-15.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object Test {
}
}

class Foo extends PolyFunction {
class Foo extends PolyFunction { // error
def apply(erased x: Int): Int = {
println("Foo.apply")
42
Expand Down
32 changes: 32 additions & 0 deletions tests/neg/i10075.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
-- Error: tests/neg/i10075.scala:8:24 ----------------------------------------------------------------------------------
8 |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
| ^^^^^^^^^^^^
| `PolyFunction` marker trait is reserved for compiler generated refinements
-- 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
-- Error: tests/neg/i10075.scala:4:14 ----------------------------------------------------------------------------------
4 |val baz = new PolyFunction { def apply = 23 } // error
| ^^^^^^^^^^^^
| `PolyFunction` marker trait is reserved for compiler generated refinements
-- Error: tests/neg/i10075.scala:5:14 ----------------------------------------------------------------------------------
5 |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
| ^^^^^^^^^^^^
| `PolyFunction` marker trait is reserved for compiler generated refinements
14 changes: 14 additions & 0 deletions tests/neg/i10075.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
val poly = [T] => (x: T) => x
val foo = new 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
val quxx = new PolyFunction { def apply[T](x: T): T = x } // error

trait PolyTrait extends PolyFunction // error

class PolyClass extends PolyTrait { // error
def apply[T](x: T): T = x
}

object PolyObject extends PolyFunction // error
10 changes: 10 additions & 0 deletions tests/neg/i10369.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
type Upgrade[T] = T match
case Int => Double
case Char => String
case Boolean => Boolean

val upgrade: [t] => t => Upgrade[t] = new PolyFunction: // error
def apply[T](x: T): Upgrade[T] = x match
case x: Int => x.toDouble
case x: Char => x.toString
case x: Boolean => !x
2 changes: 1 addition & 1 deletion tests/pos/i18302a.scala → tests/neg/i18302a.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def test = polyFun(1)

def polyFun: PolyFunction { def apply(x: Int): Int } =
new PolyFunction { def apply(x: Int): Int = x + 1 }
new PolyFunction { def apply(x: Int): Int = x + 1 } // error
4 changes: 4 additions & 0 deletions tests/neg/i18302b.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
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.
-- Error: tests/neg/i18302b.scala:4:6 ----------------------------------------------------------------------------------
4 | new PolyFunction: // error
| ^^^^^^^^^^^^
| `PolyFunction` marker trait is reserved for compiler generated refinements
2 changes: 1 addition & 1 deletion tests/neg/i18302b.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
def test = polyFun(1)(2)

def polyFun: PolyFunction { def apply(x: Int)(y: Int): Int } = // error
new PolyFunction:
new PolyFunction: // error
def apply(x: Int)(y: Int): Int = x + y
4 changes: 4 additions & 0 deletions tests/neg/i18302c.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
4 |def polyFun: PolyFunction { def foo(x: Int): Int } = // error
| ^^^^^^^^^^^^^^^^^^^^
| PolyFunction only supports apply method refinements
-- 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
2 changes: 1 addition & 1 deletion tests/neg/i18302c.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import scala.reflect.Selectable.reflectiveSelectable

def test = polyFun.foo(1)
def polyFun: PolyFunction { def foo(x: Int): Int } = // error
new PolyFunction { def foo(x: Int): Int = x + 1 }
new PolyFunction { def foo(x: Int): Int = x + 1 } // error
4 changes: 4 additions & 0 deletions tests/neg/i18302d.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
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.
-- Error: tests/neg/i18302d.scala:2:6 ----------------------------------------------------------------------------------
2 | new PolyFunction { def apply: Int = 1 } // error
| ^^^^^^^^^^^^
| `PolyFunction` marker trait is reserved for compiler generated refinements
2 changes: 1 addition & 1 deletion tests/neg/i18302d.scala
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
def polyFun: PolyFunction { def apply: Int } = // error
new PolyFunction { def apply: Int = 1 }
new PolyFunction { def apply: Int = 1 } // error
4 changes: 4 additions & 0 deletions tests/neg/i18302e.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
1 |def polyFun: PolyFunction { } = // error
| ^^^^^^^^^^^^^^^^^
| PolyFunction subtypes must refine the apply method
-- Error: tests/neg/i18302e.scala:2:6 ----------------------------------------------------------------------------------
2 | new PolyFunction { } // error
| ^^^^^^^^^^^^
| `PolyFunction` marker trait is reserved for compiler generated refinements
-- Error: tests/neg/i18302e.scala:4:15 ---------------------------------------------------------------------------------
4 |def polyFun(f: PolyFunction { }) = () // error
| ^^^^^^^^^^^^^^^^^
Expand Down
2 changes: 1 addition & 1 deletion tests/neg/i18302e.scala
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def polyFun: PolyFunction { } = // error
new PolyFunction { }
new PolyFunction { } // error

def polyFun(f: PolyFunction { }) = () // error
8 changes: 8 additions & 0 deletions tests/neg/i18302f.check
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
1 |def polyFun: PolyFunction = // error
| ^^^^^^^^^^^^
| PolyFunction subtypes must refine the apply method
-- Error: tests/neg/i18302f.scala:2:6 ----------------------------------------------------------------------------------
2 | new PolyFunction { } // error
| ^^^^^^^^^^^^
| `PolyFunction` marker trait is reserved for compiler generated refinements
-- Error: tests/neg/i18302f.scala:4:16 ---------------------------------------------------------------------------------
4 |def polyFun2(a: PolyFunction) = () // error
| ^^^^^^^^^^^^
Expand All @@ -10,3 +14,7 @@
6 |val polyFun3: PolyFunction = // error
| ^^^^^^^^^^^^
| PolyFunction subtypes must refine the apply method
-- Error: tests/neg/i18302f.scala:7:6 ----------------------------------------------------------------------------------
7 | new PolyFunction { } // error
| ^^^^^^^^^^^^
| `PolyFunction` marker trait is reserved for compiler generated refinements
4 changes: 2 additions & 2 deletions tests/neg/i18302f.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
def polyFun: PolyFunction = // error
new PolyFunction { }
new PolyFunction { } // error

def polyFun2(a: PolyFunction) = () // error

val polyFun3: PolyFunction = // error
new PolyFunction { }
new PolyFunction { } // error
4 changes: 2 additions & 2 deletions tests/neg/i18302j.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
def polyFunByName: PolyFunction { def apply(thunk: => Int): Int } = // error
new PolyFunction { def apply(thunk: => Int): Int = 1 }
new PolyFunction { def apply(thunk: => Int): Int = 1 } // error

def polyFunVarArgs: PolyFunction { def apply(args: Int*): Int } = // error
new PolyFunction { def apply(thunk: Int*): Int = 1 }
new PolyFunction { def apply(thunk: Int*): Int = 1 } // error
6 changes: 0 additions & 6 deletions tests/pos/i10369.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ type Upgrade[T] = T match
case Char => String
case Boolean => Boolean

val upgrade: [t] => t => Upgrade[t] = new PolyFunction:
def apply[T](x: T): Upgrade[T] = x match
case x: Int => x.toDouble
case x: Char => x.toString
case x: Boolean => !x

val upgrade2: [t] => t => Upgrade[t] = [t] => (x: t) => x match
case x: Int => x.toDouble
case x: Char => x.toString
Expand Down
1 change: 0 additions & 1 deletion tests/run/erased-15.check

This file was deleted.

Loading