bug icon indicating copy to clipboard operation
bug copied to clipboard

Compiler stack overflow when using Manifest with recursive existential types

Open scabug opened this issue 13 years ago • 6 comments

class C[T <: C[T]]

class UseManifest[T : Manifest]

new UseManifest[C[T] forSome{ type T <: C[T] }]

Note: I'm calling it "recursive existential type" but I'm really not sure about the terminology... maybe there's a better term.

scabug avatar Aug 18 '12 14:08 scabug

Imported From: https://issues.scala-lang.org/browse/SI-6255?orig=1 Reporter: Bruno Bieth (mustaghattack) See #6528

scabug avatar Aug 18 '12 14:08 scabug

@retronym said: It's not the same bug, but is in the same food group as #6528.

scabug avatar Jan 08 '13 18:01 scabug

Damir Vandic (damirv) said: Any updates on this? (or a possible/recommended workaround)

For the interested reader: I encountered this issue with trying to use 'recursive existential types' to call the following Java method (Titan Graph database v0.5.0):

public TitanGraphQuery<? extends TitanGraphQuery> query();

with TitanGraphQuery being

public interface TitanGraphQuery<Q extends TitanGraphQuery<Q>> {
    public Q has(String key, Object value);
}

Example Scala code (without explicit types):

val attrs: Map[String, Any]
val attrQ = attrs.foldLeft(g.query())({
  case (q, (name, value)) => q.has(name, value)
})

Does this bug mean I cannot use this method in Scala?

scabug avatar Aug 15 '14 12:08 scabug

Related but perhaps slightly different: we hit this in our codebase during an upgrade of apache thrift due to TBase being typed in this way and scalac failing to infer a manifest for its erased type. The minimal repro in our case being:

repl_test ➤ echo "public interface Test<T extends Test<T>> {}" > Test.java
repl_test ➤ javac Test.java
repl_test ➤ scala -cp .
Welcome to Scala 2.13.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_161).
Type in expressions for evaluation. Or try :help.

scala> manifest[Test[_]]
java.lang.StackOverflowError
  at scala.reflect.internal.Symbols$Symbol.isPrimaryConstructor(Symbols.scala:955)
  at scala.tools.nsc.typechecker.Contexts$Context.withOuter$1(Contexts.scala:1123)
  at scala.tools.nsc.typechecker.Contexts$Context.implicitssImpl(Contexts.scala:1146)
  at scala.tools.nsc.typechecker.Contexts$Context.withOuter$1(Contexts.scala:1125)
...

That entry seems to have slain the compiler.  Shall I replay
your session? I can re-run each line except the last one.
[y/n]

Interestingly, the same type can be inferred without issue if declared as a scala trait instead of the java interface.

Repro'ed with both java 8 & 11 on latest versions of 2.11, 2.12, and 2.13.

jvandew avatar Sep 08 '22 21:09 jvandew

Consider using ClassTag if you don't need full type information, and TypeTag if you do. As the Manifest documentation states:

it is advisable to migrate any Manifest-based APIs to use Tags

SethTisue avatar Sep 08 '22 22:09 SethTisue

We did indeed switch to using a mix of tags (ClassTag where possible, TypeTag where required) which gets around this problem. I expect we'll have to revisit this when we eventually upgrade to Scala 3 as TypeTag seems to have been removed, but it's probably a few years yet before we cross that bridge.

jvandew avatar Sep 09 '22 03:09 jvandew