Skip to content

Singleton type of varargs #18119

Open
Open
@prolativ

Description

@prolativ

Compiler version

3.3.2-RC1-bin-20230630-c629090-NIGHTLY and before

Minimized code

The following snippet contains multiple cases obtained by uncommenting one of the commented lines at a time.

object Test {
  def foo(xs: Int*)(ys: xs.type) = ys
  def bar(xs: Int*)(ys: xs.type*) = ys
  val ints = Seq(1)

  // val f1 = foo()()
  // val f2 = foo(1)(1)
  // val f3 = foo(1)(1, 1)
  // val f4 = foo(1, 1)(1, 1)
  // val f5 = foo(1, 2)(1, 2)
  // val f6 = foo(1, 2)(Seq(1, 2): _*)
  // val f7 = foo(ints: _*)(ints)
  // val f8 = foo(ints: _*)(ints: _*)

  // val b1 = bar()()
  // val b2 = bar(1)(1)
  // val b3 = bar(1)(1, 1)
  // val b4 = bar(1, 1)(1, 1)
  // val b5 = bar(1, 2)(1, 2)
  // val b6 = bar(1, 2)(Seq(1, 2): _*)
  // val b7 = bar(ints: _*)(ints)
  // val b8 = bar(ints: _*)(ints: _*)
}

Output

case scala 3.nightly scala 2.13.11
f1 crash error
f2 crash success
f3 crash error
f4 crash error
f5 crash error
f6 error error
f7 crash error
f8 error error
b1 success crash
b2 error success
b3 error success
b4 error crash
b5 error crash
b6 error crash
b7 error error
b8 error error

Stack trace for a crash in 3.3.2-RC1-bin-20230630-c629090-NIGHTLY (taking f2 as example):

Exception in thread "main" java.util.NoSuchElementException: head of empty list
        at scala.collection.immutable.Nil$.head(List.scala:662)
        at scala.collection.immutable.Nil$.head(List.scala:661)
        at dotty.tools.dotc.typer.Applications$Application.matchArgs(Applications.scala:638)
        at dotty.tools.dotc.typer.Applications$Application.init(Applications.scala:492)
        at dotty.tools.dotc.typer.Applications$TypedApply.<init>(Applications.scala:777)
        at dotty.tools.dotc.typer.Applications$ApplyToUntyped.<init>(Applications.scala:894)
        at dotty.tools.dotc.typer.Applications.ApplyTo(Applications.scala:1124)
        at dotty.tools.dotc.typer.Applications.ApplyTo$(Applications.scala:352)
        at dotty.tools.dotc.typer.Typer.ApplyTo(Typer.scala:116)
        at dotty.tools.dotc.typer.Applications.simpleApply$1(Applications.scala:967)
        at dotty.tools.dotc.typer.Applications.realApply$1$$anonfun$2(Applications.scala:1050)
        at dotty.tools.dotc.typer.Typer.tryEither(Typer.scala:3392)
        at dotty.tools.dotc.typer.Applications.realApply$1(Applications.scala:1061)
        at dotty.tools.dotc.typer.Applications.typedApply(Applications.scala:1099)
        at dotty.tools.dotc.typer.Applications.typedApply$(Applications.scala:352)
        at dotty.tools.dotc.typer.Typer.typedApply(Typer.scala:116)
        at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3109)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3176)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3252)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3256)
        at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3368)
        at dotty.tools.dotc.typer.Namer.typedAheadExpr$$anonfun$1(Namer.scala:1656)
        at dotty.tools.dotc.typer.Namer.typedAhead(Namer.scala:1646)
        at dotty.tools.dotc.typer.Namer.typedAheadExpr(Namer.scala:1656)
        at dotty.tools.dotc.typer.Namer.typedAheadRhs$1$$anonfun$1(Namer.scala:1915)
        at dotty.tools.dotc.inlines.PrepareInlineable$.dropInlineIfError(PrepareInlineable.scala:243)
        at dotty.tools.dotc.typer.Namer.typedAheadRhs$1(Namer.scala:1915)
        at dotty.tools.dotc.typer.Namer.rhsType$1(Namer.scala:1923)
        at dotty.tools.dotc.typer.Namer.cookedRhsType$1(Namer.scala:1941)
        at dotty.tools.dotc.typer.Namer.lhsType$1(Namer.scala:1942)
        at dotty.tools.dotc.typer.Namer.inferredResultType(Namer.scala:1953)
        at dotty.tools.dotc.typer.Namer.inferredType$1(Namer.scala:1694)
        at dotty.tools.dotc.typer.Namer.valOrDefDefSig(Namer.scala:1700)
        at dotty.tools.dotc.typer.Namer$Completer.typeSig(Namer.scala:787)
        at dotty.tools.dotc.typer.Namer$Completer.completeInCreationContext(Namer.scala:934)
        at dotty.tools.dotc.typer.Namer$Completer.complete(Namer.scala:814)
        at dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:174)
        at dotty.tools.dotc.core.Denotations$Denotation.completeInfo$1(Denotations.scala:187)
        at dotty.tools.dotc.core.Denotations$Denotation.info(Denotations.scala:189)
        at dotty.tools.dotc.core.SymDenotations$SymDenotation.ensureCompleted(SymDenotations.scala:393)
        at dotty.tools.dotc.typer.Typer.retrieveSym(Typer.scala:3050)
        at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3075)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3175)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3252)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3256)
        at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3278)
        at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3324)
        at dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:2742)
        at dotty.tools.dotc.typer.Typer.typedTypeOrClassDef$1(Typer.scala:3097)
        at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:3101)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3175)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3252)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3256)
        at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3278)
        at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3324)
        at dotty.tools.dotc.typer.Typer.typedPackageDef(Typer.scala:2873)
        at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:3143)
        at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:3176)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3252)
        at dotty.tools.dotc.typer.Typer.typed(Typer.scala:3256)
        at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3368)
        at dotty.tools.dotc.typer.TyperPhase.typeCheck$$anonfun$1(TyperPhase.scala:44)
        at dotty.tools.dotc.typer.TyperPhase.typeCheck$$anonfun$adapted$1(TyperPhase.scala:50)
        at scala.Function0.apply$mcV$sp(Function0.scala:42)
        at dotty.tools.dotc.core.Phases$Phase.monitor(Phases.scala:440)
        at dotty.tools.dotc.typer.TyperPhase.typeCheck(TyperPhase.scala:50)
        at dotty.tools.dotc.typer.TyperPhase.runOn$$anonfun$3(TyperPhase.scala:84)
        at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
        at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
        at scala.collection.immutable.List.foreach(List.scala:333)
        at dotty.tools.dotc.typer.TyperPhase.runOn(TyperPhase.scala:84)
        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)

Expectation

For sure the compiler should not crash but I'm not really sure which of the cases (if any) should compile successfully.
The semantics of singleton vararg types in general are quite unclear. E.g. they cannot be used as declared return types. Successfully compiling b3 in scala 2.13 seems to suggest that xs.type is a subtype of Int rather than Int* or Seq[Int].
@odersky should we disallow singleton vararg types at all to prevent such strange corner cases? Alternatively which of the cases should compile?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions