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

Invalid PolyFunction refinements #18302

Closed
nicolasstucki opened this issue Jul 27, 2023 · 1 comment · Fixed by #18457
Closed

Invalid PolyFunction refinements #18302

nicolasstucki opened this issue Jul 27, 2023 · 1 comment · Fixed by #18457

Comments

@nicolasstucki
Copy link
Contributor

Compiler version

3.4.0-RC1-bin-20230726-97677cc-NIGHTLY

Issue

We are not restricting the signatures of the user-written (in source or macro) refinements of PolyFunction. We should restrict and check that those refinements are valid

Example 1

def test = polyFun(1)

def polyFun: PolyFunction { def apply(x: Int): Int } =
  new PolyFunction { def apply(x: Int): Int = x + 1 }

Works but is outside of the current spec of PolyFunction. These should be supported at some point. We should probably emit an error now and allow it once we update the spec.

Example 2

def test = polyFun(1)(2)

def polyFun: PolyFunction { def apply(x: Int)(y: Int): Int } =
  new PolyFunction:
    def apply(x: Int)(y: Int): Int = x + y

This is not supported by the spec and is not intended to be supported. It currently crashes the compiler with

java.util.NoSuchElementException: head of empty list
Exception in thread "main" java.lang.AssertionError: assertion failed
        at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:11)
        at dotty.tools.dotc.core.TypeErasure$.functionType$1(TypeErasure.scala:569)
        at dotty.tools.dotc.core.TypeErasure$.eraseRefinedFunctionApply(TypeErasure.scala:572)
        at dotty.tools.dotc.core.TypeErasure.dotty$tools$dotc$core$TypeErasure$$apply(TypeErasure.scala:658)
        at dotty.tools.dotc.core.TypeErasure.eraseResult(TypeErasure.scala:881)
        at dotty.tools.dotc.core.TypeErasure.eraseInfo(TypeErasure.scala:815)
        at dotty.tools.dotc.core.TypeErasure$.transformInfo(TypeErasure.scala:275)
        at dotty.tools.dotc.transform.Erasure.transform(Erasure.scala:97)

  exception while retyping @SourceFile("tests/run-custom-args/erased/erased-15.scala") final module class 
  erased-15$package() extends Object() {
  private def writeReplace(): AnyRef =
    new scala.runtime.ModuleSerializationProxy(classOf[erased-15$package.type])
  def test: Int = polyFun.apply(1)(2)
  def polyFun: (x: Int) => (y: Int) => Int =
    {
      final class $anon() extends Object(), PolyFunction {
        def apply(x: Int)(y: Int): Int = x.+(y)
        private val $outer: erased-15$package
        final def erased-15$package$_$$anon$$$outer: erased-15$package = $outer
      }
      new Object with PolyFunction {...}():((x: Int) => (y: Int) => Int)
    }
} of class TypeDef # -1

  An unhandled exception was thrown in the compiler.
  Please file a crash report here:
  https://github.com/lampepfl/dotty/issues/new/choose

     while compiling: tests/run-custom-args/erased/erased-15.scala
        during phase: MegaPhase{elimErasedValueType, pureStats, vcElideAllocations, etaReduce, arrayApply, elimPolyFunction, tailrec, completeJavaEnums, mixin, lazyVals, memoize, nonLocalReturns, capturedVars}
                mode: Mode(ImplicitsEnabled)
     library version: version 2.13.10
    compiler version: version 3.4.0-RC1-bin-SNAPSHOT-nonbootstrapped-git-c04d2db
            settings: -classpath /Users/nicolasstucki/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.10/scala-library-2.13.10.jar:/Users/nicolasstucki/GitHub/dotty/library/../out/bootstrap/scala3-library-bootstrapped/scala-3.4.0-RC1-bin-SNAPSHOT-nonbootstrapped/scala3-library_3-3.4.0-RC1-bin-SNAPSHOT.jar -d t/out

                tree: PackageDef(object <empty>)
       tree position: tests/run-custom-args/erased/erased-15.scala:1:0
           tree type: <empty>.type
              symbol: package <empty>
   symbol definition: final lazy module object <empty>: <empty> (a Symbol)
      symbol package: <root>
       symbol owners: 
           call site: package <empty> in module class <empty>

  == Source file context for tree position ==

-- Error: tests/run-custom-args/erased/erased-15.scala:1:0 ---------------------
1 |def test = polyFun(1)(2)
  |^

2 |def polyFun: PolyFunction { def apply(x: Int)(y: Int): Int } =
3 |  new PolyFunction:
4 |    def apply(x: Int)(y: Int): Int = x + y
        at dotty.tools.dotc.core.Denotations$SingleDenotation.goForward$1(Denotations.scala:830)
        at dotty.tools.dotc.core.Denotations$SingleDenotation.current(Denotations.scala:876)
        at dotty.tools.dotc.core.Symbols$Symbol.recomputeDenot(Symbols.scala:122)
        at dotty.tools.dotc.core.Symbols$Symbol.computeDenot(Symbols.scala:116)
        at dotty.tools.dotc.core.Symbols$Symbol.denot(Symbols.scala:109)
        at dotty.tools.dotc.core.Symbols$.toDenot(Symbols.scala:496)
        at dotty.tools.dotc.core.SymDenotations$ClassDenotation.paramAccessors$$anonfun$1(SymDenotations.scala:2392)
        at dotty.tools.dotc.core.Scopes$Scope.filter(Scopes.scala:102)
        at dotty.tools.dotc.core.SymDenotations$ClassDenotation.paramAccessors(SymDenotations.scala:2392)
        at dotty.tools.dotc.core.Contexts$Context.superCallContext(Contexts.scala:408)
        at dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:2626)
        at dotty.tools.dotc.transform.Erasure$Typer.typedClassDef(Erasure.scala:1043)
        at dotty.tools.dotc.typer.Typer.typedTypeOrClassDef$1(Typer.scala:3087)
        at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3091)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3166)
        at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:174)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3243)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3247)
        at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3269)
        at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3315)
        at dotty.tools.dotc.transform.Erasure$Typer.typedStats(Erasure.scala:1054)
        at dotty.tools.dotc.typer.Typer.typedPackageDef(Typer.scala:2861)
        at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3133)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3167)
        at dotty.tools.dotc.typer.ReTyper.typedUnadapted(ReTyper.scala:174)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3243)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3247)
        at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3359)
        at dotty.tools.dotc.transform.Erasure.run(Erasure.scala:144)
        at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:327)
        at scala.collection.immutable.List.map(List.scala:246)
        at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:331)
        at dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:246)
        at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
        at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
        at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1321)
        at dotty.tools.dotc.Run.runPhases$1(Run.scala:262)
        at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:270)
        at dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:279)
        at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:67)
        at dotty.tools.dotc.Run.compileUnits(Run.scala:279)
        at dotty.tools.dotc.Run.compileSources(Run.scala:194)
        at dotty.tools.dotc.Run.compile(Run.scala:179)
        at dotty.tools.dotc.Driver.doCompile(Driver.scala:37)
        at dotty.tools.dotc.Driver.process(Driver.scala:197)
        at dotty.tools.dotc.Driver.process(Driver.scala:165)
        at dotty.tools.dotc.Driver.process(Driver.scala:177)
        at dotty.tools.dotc.Driver.main(Driver.scala:207)
        at dotty.tools.dotc.Main.main(Main.scala)

Example 3

import scala.reflect.Selectable.reflectiveSelectable

def test = polyFun.foo(1)
def polyFun: PolyFunction { def foo(x: Int): Int } =
  new PolyFunction { def foo(x: Int): Int = x + 1 }

Not in the spec. Crashes the compiler with

java.util.NoSuchElementException: head of empty list
Exception in thread "main" java.util.NoSuchElementException: head of empty list

  unhandled exception while running MegaPhase{elimErasedValueType, pureStats, vcElideAllocations, etaReduce, arrayApply, elimPolyFunction, tailrec, completeJavaEnums, mixin, lazyVals, memoize, nonLocalReturns, capturedVars} on Test.scala

  An unhandled exception was thrown in the compiler.
  Please file a crash report here:
  https://github.com/lampepfl/dotty/issues/new/choose

     while compiling: Test.scala
        during phase: MegaPhase{elimErasedValueType, pureStats, vcElideAllocations, etaReduce, arrayApply, elimPolyFunction, tailrec, completeJavaEnums, mixin, lazyVals, memoize, nonLocalReturns, capturedVars}
                mode: Mode(ImplicitsEnabled)
     library version: version 2.13.10
    compiler version: version 3.4.0-RC1-bin-SNAPSHOT-nonbootstrapped-git-c04d2db
            settings: -classpath /Users/nicolasstucki/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.10/scala-library-2.13.10.jar:/Users/nicolasstucki/GitHub/dotty/library/../out/bootstrap/scala3-library-bootstrapped/scala-3.4.0-RC1-bin-SNAPSHOT-nonbootstrapped/scala3-library_3-3.4.0-RC1-bin-SNAPSHOT.jar -d t/out

                tree: EmptyTree
       tree position: :<unknown>
           tree type: <notype>
              symbol: val <none>
           call site: package <root> in module class <root>

  == Source file context for tree position ==


        at scala.collection.immutable.Nil$.head(List.scala:662)
        at scala.collection.immutable.Nil$.head(List.scala:661)
        at dotty.tools.dotc.transform.ElimPolyFunction.functionTypeOfPoly(ElimPolyFunction.scala:50)
        at dotty.tools.dotc.transform.ElimPolyFunction.transform(ElimPolyFunction.scala:36)
        at dotty.tools.dotc.core.Denotations$SingleDenotation.goForward$1(Denotations.scala:830)
        at dotty.tools.dotc.core.Denotations$SingleDenotation.current(Denotations.scala:876)
        at dotty.tools.dotc.core.Denotations$SingleDenotation.goForward$1(Denotations.scala:847)
        at dotty.tools.dotc.core.Denotations$SingleDenotation.current(Denotations.scala:876)
        at dotty.tools.dotc.core.Denotations$SingleDenotation.goForward$1(Denotations.scala:847)
        at dotty.tools.dotc.core.Denotations$SingleDenotation.current(Denotations.scala:876)
        at dotty.tools.dotc.core.Types$NamedType.computeDenot(Types.scala:2425)
        at dotty.tools.dotc.core.Types$NamedType.denot(Types.scala:2388)
        at dotty.tools.dotc.ast.Trees$DenotingTree.denot(Trees.scala:256)
        at dotty.tools.dotc.ast.Trees$Tree.symbol(Trees.scala:145)
        at dotty.tools.dotc.ast.tpd$.localOwner(tpd.scala:609)
        at dotty.tools.dotc.ast.tpd$.localCtx(tpd.scala:613)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1745)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1791)
        at dotty.tools.dotc.transform.CapturedVars$CollectCaptured.traverse(CapturedVars.scala:74)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1790)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1790)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.fold$1(Trees.scala:1654)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.apply(Trees.scala:1656)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1687)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1791)
        at dotty.tools.dotc.transform.CapturedVars$CollectCaptured.traverse(CapturedVars.scala:74)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1790)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1790)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1742)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1791)
        at dotty.tools.dotc.transform.CapturedVars$CollectCaptured.traverse(CapturedVars.scala:74)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1790)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1790)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.fold$1(Trees.scala:1654)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.apply(Trees.scala:1656)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1749)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1791)
        at dotty.tools.dotc.transform.CapturedVars$CollectCaptured.traverse(CapturedVars.scala:74)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1790)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1790)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1746)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1791)
        at dotty.tools.dotc.transform.CapturedVars$CollectCaptured.traverse(CapturedVars.scala:74)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1790)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.apply(Trees.scala:1790)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.fold$1(Trees.scala:1654)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.apply(Trees.scala:1656)
        at dotty.tools.dotc.ast.Trees$Instance$TreeAccumulator.foldOver(Trees.scala:1755)
        at dotty.tools.dotc.ast.Trees$Instance$TreeTraverser.traverseChildren(Trees.scala:1791)
        at dotty.tools.dotc.transform.CapturedVars$CollectCaptured.traverse(CapturedVars.scala:74)
        at dotty.tools.dotc.transform.CapturedVars$CollectCaptured.runOver(CapturedVars.scala:77)
        at dotty.tools.dotc.transform.CapturedVars.prepareForUnit(CapturedVars.scala:84)
        at dotty.tools.dotc.transform.MegaPhase.prepUnit(MegaPhase.scala:1095)
        at dotty.tools.dotc.transform.MegaPhase.prepUnit(MegaPhase.scala:1095)
        at dotty.tools.dotc.transform.MegaPhase.prepUnit(MegaPhase.scala:1095)
        at dotty.tools.dotc.transform.MegaPhase.transformUnit(MegaPhase.scala:468)
        at dotty.tools.dotc.transform.MegaPhase.run(MegaPhase.scala:481)
        at dotty.tools.dotc.core.Phases$Phase.runOn$$anonfun$1(Phases.scala:327)
        at scala.collection.immutable.List.map(List.scala:246)
        at dotty.tools.dotc.core.Phases$Phase.runOn(Phases.scala:331)
        at dotty.tools.dotc.Run.runPhases$1$$anonfun$1(Run.scala:246)
        at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
        at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
        at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1321)
        at dotty.tools.dotc.Run.runPhases$1(Run.scala:262)
        at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:270)
        at dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:279)
        at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:67)
        at dotty.tools.dotc.Run.compileUnits(Run.scala:279)
        at dotty.tools.dotc.Run.compileSources(Run.scala:194)
        at dotty.tools.dotc.Run.compile(Run.scala:179)
        at dotty.tools.dotc.Driver.doCompile(Driver.scala:37)
        at dotty.tools.dotc.Driver.process(Driver.scala:197)
        at dotty.tools.dotc.Driver.process(Driver.scala:165)
        at dotty.tools.dotc.Driver.process(Driver.scala:177)
        at dotty.tools.dotc.Driver.main(Driver.scala:207)
        at dotty.tools.dotc.Main.main(Main.scala)
@nicolasstucki
Copy link
Contributor Author

Example 4

def test = polyFun.apply
def polyFun: PolyFunction { def apply: Int } =
  new PolyFunction { def apply: Int = 1 }
scala.MatchError: ExprType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),object scala),class Int)) (of class dotty.tools.dotc.core.Types$CachedExprType)

nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Aug 25, 2023
`PolyFunction` must be refined with an `apply` method that has a single
parameter list with no by-name nor varargs parameters. It may optionally
have type parameters. Some of these restrictions could be lifted later,
but for now these features are not properly handled by the compiler.

Fixes scala#18302
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Aug 25, 2023
`PolyFunction` must be refined with an `apply` method that has a single
parameter list with no by-name nor varargs parameters. It may optionally
have type parameters. Some of these restrictions could be lifted later,
but for now these features are not properly handled by the compiler.

Fixes scala#18302
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Aug 25, 2023
`PolyFunction` must be refined with an `apply` method that has a single
parameter list with no by-name nor varargs parameters. It may optionally
have type parameters. Some of these restrictions could be lifted later,
but for now these features are not properly handled by the compiler.

Fixes scala#18302
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Aug 25, 2023
`PolyFunction` must be refined with an `apply` method that has a single
parameter list with no by-name nor varargs parameters. It may optionally
have type parameters. Some of these restrictions could be lifted later,
but for now these features are not properly handled by the compiler.

Fixes scala#18302
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Sep 7, 2023
`PolyFunction` must be refined with an `apply` method that has a single
parameter list with no by-name nor varargs parameters. It may optionally
have type parameters. Some of these restrictions could be lifted later,
but for now these features are not properly handled by the compiler.

Fixes scala#8299
Fixes scala#18302

fixup
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Sep 19, 2023
`PolyFunction` must be refined with an `apply` method that has a single
parameter list with no by-name nor varargs parameters. It may optionally
have type parameters. Some of these restrictions could be lifted later,
but for now these features are not properly handled by the compiler.

Fixes scala#8299
Fixes scala#18302

fixup
nicolasstucki added a commit to dotty-staging/dotty that referenced this issue Oct 12, 2023
`PolyFunction` must be refined with an `apply` method that has a single
parameter list with no by-name nor varargs parameters. It may optionally
have type parameters. Some of these restrictions could be lifted later,
but for now these features are not properly handled by the compiler.

Fixes scala#8299
Fixes scala#18302
WojciechMazur added a commit that referenced this issue Jun 19, 2024
`PolyFunction` must be refined with an `apply` method that has a single
parameter list with no by-name nor varargs parameters. It may optionally
have type parameters. Some of these restrictions could be lifted later,
but for now these features are not properly handled by the compiler.

Fixes #8299
Fixes #18302

[Cherry-picked e5ca0c4][modified]
WojciechMazur added a commit that referenced this issue Jun 20, 2024
`PolyFunction` must be refined with an `apply` method that has a single
parameter list with no by-name nor varargs parameters. It may optionally
have type parameters. Some of these restrictions could be lifted later,
but for now these features are not properly handled by the compiler.

Fixes #8299
Fixes #18302

[Cherry-picked e5ca0c4][modified]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants