Skip to content

Dotty typer crashes with scalajs Lambda SAM error #15785

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

Closed
evbo opened this issue Jul 29, 2022 · 2 comments · Fixed by #19461
Closed

Dotty typer crashes with scalajs Lambda SAM error #15785

evbo opened this issue Jul 29, 2022 · 2 comments · Fixed by #19461

Comments

@evbo
Copy link

evbo commented Jul 29, 2022

Compiler version

Scala 3.2.0 RC-2 and RC-1

Minimized code

https://scastie.scala-lang.org/W2mz3ejSTOOIOkuUzHC6Tg

//> using scala "3.2.0-RC2"
//> using platform "scala-js"

import scala.scalajs.js

sealed trait Foo[T]

given Foo[Int] with {}

class Bar[T: Foo](val getValue: () => T)

class FooWorks[T: Foo](val foo: Bar[T] => T = (f: Bar[T]) => f.getValue())

class FooSAM[T: Foo](val foo: js.Function1[Bar[T],T] = (f: Bar[T]) => f.getValue())

(note that scala3 types compile but scalajs type does not)

Output (click arrow to expand)

[error] ./test.scala:14:83: result type of lambda is an underspecified SAM type scalajs.js.Function1[Bar[<?>], <?>]
[error] class FooSAM[T: Foo](val foo: js.Function1[Bar[T],T] = (f: Bar[T]) => f.getValue())
[error]                                                                                   ^
exception occurred while typechecking /tmp/i15785/test.scala
exception occurred while compiling /tmp/i15785/test.scala
Error compiling project (Scala 3.2.0-RC2, Scala.js)
java.lang.Error: internal error: type of right-hand side scalajs.js.Function1[Bar[<?>], <?>] is not fully defined, pos = <260..329>
	at dotty.tools.dotc.typer.Inferencing$.fullyDefinedType(Inferencing.scala:54)
	at dotty.tools.dotc.typer.Namer.lhsType$1(Namer.scala:1893)
	at dotty.tools.dotc.typer.Namer.inferredResultType(Namer.scala:1904)
	at dotty.tools.dotc.typer.Namer.inferredType$1(Namer.scala:1657)
	at dotty.tools.dotc.typer.Namer.valOrDefDefSig(Namer.scala:1664)
	at dotty.tools.dotc.typer.Namer.defDefSig(Namer.scala:1749)
	at dotty.tools.dotc.typer.Namer$Completer.typeSig(Namer.scala:786)
	at dotty.tools.dotc.typer.Namer$Completer.completeInCreationContext(Namer.scala:921)
	at dotty.tools.dotc.typer.Namer$Completer.complete(Namer.scala:809)
	at dotty.tools.dotc.core.SymDenotations$SymDenotation.completeFrom(SymDenotations.scala:171)
	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:373)
	at dotty.tools.dotc.typer.Typer.retrieveSym(Typer.scala:2800)
	at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2825)
	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2921)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2987)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2991)
	at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3013)
	at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3063)
	at dotty.tools.dotc.typer.Typer.typedClassDef(Typer.scala:2500)
	at dotty.tools.dotc.typer.Typer.typedTypeOrClassDef$1(Typer.scala:2847)
	at dotty.tools.dotc.typer.Typer.typedNamed$1(Typer.scala:2851)
	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2921)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2987)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2991)
	at dotty.tools.dotc.typer.Typer.traverse$1(Typer.scala:3013)
	at dotty.tools.dotc.typer.Typer.typedStats(Typer.scala:3063)
	at dotty.tools.dotc.typer.Typer.typedPackageDef(Typer.scala:2629)
	at dotty.tools.dotc.typer.Typer.typedUnnamed$1(Typer.scala:2892)
	at dotty.tools.dotc.typer.Typer.typedUnadapted(Typer.scala:2922)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2987)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:2991)
	at dotty.tools.dotc.typer.Typer.typedExpr(Typer.scala:3107)
	at dotty.tools.dotc.typer.TyperPhase.typeCheck$$anonfun$1(TyperPhase.scala:43)
	at dotty.tools.dotc.typer.TyperPhase.typeCheck$$anonfun$adapted$1(TyperPhase.scala:50)
	at scala.Function0.apply$mcV$sp(Function0.scala:39)
	at dotty.tools.dotc.core.Phases$Phase.monitor(Phases.scala:417)
	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:234)
	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:1328)
	at dotty.tools.dotc.Run.runPhases$1(Run.scala:245)
	at dotty.tools.dotc.Run.compileUnits$$anonfun$1(Run.scala:253)
	at dotty.tools.dotc.Run.compileUnits$$anonfun$adapted$1(Run.scala:262)
	at dotty.tools.dotc.util.Stats$.maybeMonitored(Stats.scala:68)
	at dotty.tools.dotc.Run.compileUnits(Run.scala:262)
	at dotty.tools.dotc.Run.compileSources(Run.scala:186)
	at dotty.tools.dotc.Run.compile(Run.scala:170)
	at dotty.tools.dotc.Driver.doCompile(Driver.scala:35)
	at dotty.tools.xsbt.CompilerBridgeDriver.run(CompilerBridgeDriver.java:88)
	at dotty.tools.xsbt.CompilerBridge.run(CompilerBridge.java:22)
	at sbt.internal.inc.AnalyzingCompiler.compile(AnalyzingCompiler.scala:91)
	at sbt.internal.inc.bloop.internal.BloopHighLevelCompiler.compileSources$1(BloopHighLevelCompiler.scala:133)
	at sbt.internal.inc.bloop.internal.BloopHighLevelCompiler.$anonfun$compile$7(BloopHighLevelCompiler.scala:151)
	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
	at sbt.internal.inc.bloop.internal.BloopHighLevelCompiler.$anonfun$compile$1(BloopHighLevelCompiler.scala:71)
	at bloop.tracing.BraveTracer.traceInternal(BraveTracer.scala:65)
	at bloop.tracing.BraveTracer.trace(BraveTracer.scala:39)
	at sbt.internal.inc.bloop.internal.BloopHighLevelCompiler.timed$1(BloopHighLevelCompiler.scala:70)
	at sbt.internal.inc.bloop.internal.BloopHighLevelCompiler.$anonfun$compile$6(BloopHighLevelCompiler.scala:151)
	at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
	at monix.eval.internal.TaskRunLoop$.monix$eval$internal$TaskRunLoop$$loop$1(TaskRunLoop.scala:187)
	at monix.eval.internal.TaskRunLoop$RestartCallback$1.onSuccess(TaskRunLoop.scala:119)
	at monix.eval.Task$.$anonfun$forkedUnit$2(Task.scala:1463)
	at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1395)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Error: Unexpected error when compiling project_87a0305fea_87a0305fea-a20649ef27: 'internal error: type of right-hand side scalajs.js.Function1[Bar[<?>], <?>] is not fully defined, pos = <260..329>'

Additional discussion on discord:
https://discord.com/channels/632150470000902164/635668814956068864/1002302314889084928

@evbo evbo added itype:bug itype:crash stat:needs triage Every issue needs to have an "area" and "itype" label labels Jul 29, 2022
@Florian3k Florian3k added area:typer area:scala.js and removed stat:needs triage Every issue needs to have an "area" and "itype" label labels Jul 29, 2022
@sjrd
Copy link
Member

sjrd commented Jul 29, 2022

I can reproduce this without Scala.js, by defining a SAM type as follows:

trait SAMFunction1[-T1, +R] {:
  def apply(x1: T1): R

and using it instead of js.Function1. So this is not Scala.js-related.

In fact, I can minimize it all the way to

trait SAMFunction1[-T1, +R]:
  def apply(x1: T1): R

def fooSAM[T](foo: SAMFunction1[T, T] = (f: T) => f): Unit = ()

No need for context bounds or givens, or for a class constructor. Just a parameter of a generic SAM type with a default value which is a lambda. (Replacing SAMFunction1[T, T] by SAMFunction1[Int, Int] fixes the crash, so the genericity of the SAM is relevant to the issue.)

@Kordyjan Kordyjan added this to the Future versions milestone Dec 12, 2022
@odersky odersky self-assigned this Dec 14, 2022
@smarter
Copy link
Member

smarter commented Mar 15, 2023

The default argument is typed with an expected type of SAMFunction1[WildcardType, WildcardType], we can give it a more precise type manually with an explicit ascription:

trait SAMFunction1[-T1, +R]:
  def apply(x1: T1): R

def fooSAM[T](foo: SAMFunction1[T, T] = ((f: T) => f): SAMFunction1[T, T]): Unit = ()

Since SAM types with wildcards are hard to handle, it'd be simpler to always type them with the more precise expected type SAMFunction1[T, T]. I believe this is achievable by generalizing the check in https://github.com/lampepfl/dotty/blob/6e5be23c6baaa8b3b904bf32ad4b7712d89cedfc/compiler/src/dotty/tools/dotc/typer/Namer.scala#L1860-L1882
to also match on case SAMType(_) if !defn.isFunctionType(approxTp) (Function types are also matched by SAM types, but we do want to type them with wildcards so that def fooFun[T](foo: Function1[T, T] = (f: Int) => f): Unit = () can compile).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants