shapeless
shapeless copied to clipboard
scalac GC error with LocalDateTime, Generic and Selector
I have a strange error with Generic
and Select
on a case class containing LocalDateTime
. I haven't been able to pinpoint the issue exactly, but having both in my case class causes very high compilation times in my project. Example code:
case class WAT(
ld: java.time.LocalDate,
a: String,
b: String,
ldt: java.time.LocalDateTime
)
def x[H <: HList, T](
implicit
gen: Generic.Aux[WAT, H],
at: Selector[H, LocalDateTime]
): Nothing = ???
x
This is the minimal failing example I could come up with. This causes scalac to go on for what seems to be forever (haven't finished in ~1 hour), with a lot of GC activity and 1GB of heap space. If I increase the number of fields it will eventually fail with the below error. If I remove a: String
or b: String
from the case class, the compilation still takes a bit longer than usual (ie, if I do Selector[H, String]
the compilation time is noticeably quicker), but it still compiles. Is this an issue with shapeless or am I doing something else wrong that I don't quite see?
Error:scalac: Error: GC overhead limit exceeded
java.lang.OutOfMemoryError: GC overhead limit exceeded
at scala.reflect.internal.Types$Type.scala$reflect$internal$Types$Type$$findMemberInternal$1(Types.scala:1019)
at scala.reflect.internal.Types$Type.findMember(Types.scala:1021)
at scala.reflect.internal.Types$Type.memberBasedOnName(Types.scala:636)
at scala.reflect.internal.Types$Type.nonPrivateMember(Types.scala:612)
at scala.reflect.internal.Types$class.rebind(Types.scala:3422)
at scala.reflect.internal.Types$class.typeRef(Types.scala:3497)
at scala.reflect.internal.SymbolTable.typeRef(SymbolTable.scala:16)
at scala.reflect.internal.Symbols$TypeSymbol.newTypeRef(Symbols.scala:3081)
at scala.reflect.internal.Symbols$TypeSymbol.typeConstructor(Symbols.scala:3103)
at scala.reflect.internal.Symbols$TypeSymbol.tpeHK(Symbols.scala:3106)
at scala.reflect.internal.Types$TypeVar$.createTypeVar(Types.scala:2833)
at scala.reflect.internal.Types$TypeVar$.apply(Types.scala:2806)
at scala.reflect.internal.Types$ExistentialType$$anonfun$23.apply(Types.scala:2701)
at scala.reflect.internal.Types$ExistentialType$$anonfun$23.apply(Types.scala:2701)
at scala.collection.immutable.List.map(List.scala:284)
Scala version: 2.11.11 Shapeless version: 2.3.2
Please note that these are the latest versions I'm able to use due to some restrictions on the project.
F-bounded types strike again?
scala> List("", LocalDate.now(), LocalDateTime.now())
res1: List[Comparable[_ >: java.time.chrono.ChronoLocalDateTime[?0] with java.time.chrono.ChronoLocalDate with String forSome { type ?0 } <: Comparable[_ >: java.time.chrono.ChronoLocalDateTime[?0] with java.time.chrono.ChronoLocalDate with String forSome { type ?0 } <: Comparable[_ >: java.time.chrono.ChronoLocalDateTime[?0] with java.time.chrono.ChronoLocalDate with String forSome { type ?0 } <: Object] forSome { type ?0 }] forSome { type ?0 }] with java.io.Serializable] = List("", 2018-03-19, 2018-03-19T22:25:44.370)
I'm not familiar enough with the internals of shapeless to know why this would cause an issue in a case class. The only workaround I found so far is to wrap each such type individually like so:
case class LocalDateWrapper(value: LocalDate)
case class LocalDateTimeWrapper(value: LocalDateTime)
I'm not 100% sure myself, so take with a grain of salt, but my reasoning goes like this
The issue is not with shapeless itself, but with subtyping tests taking forever on F-bounded types to a large depth. The depth depends on the complexity of the type and HList
s are obviously complex types. The subtyping tests involved are just part of the standard implicit resolution in Scala, no macro magic involved here (take a look at the definition of Selector
).