Skip to content

Invalid PolyFunction refinements  #18302

Closed
@nicolasstucki

Description

@nicolasstucki

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)

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions