Compilation hangs on Scala 2 when specifying types for fairly long twiddles
francesconero opened this issue · comments
Hello!
Thanks again @mpilquist for the 0.6.2 Skunk release. Unfortunately we found another blocker trying to complete our migration. This time there seems to be a problem when the compiler is forced to check a subtype relation for a Twiddle (in Skunk, this happens often, for example when passing data to queries or commands after inferring the Encoder type from the sql macro).
Here's a minimal example that takes about 30 seconds to compile on a fairly recent laptop:
object Debug {
import org.typelevel.twiddles._
val inferred =
1 *: 1 *: 1 *: 1 *: 1 *: 1 *: 1 *: 1 *:
1 *: 1 *: 1 *: 1 *: 1 *: 1 *: 1 *: 1 *:
1 *: 1 *: 1 *: 1 *: 1 *: 1 *: 1 *: 1 *:
1 *: 1 *: 1 *: 1 *: 1 *: 1 *:
EmptyTuple
type Expected =
Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *:
Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *:
Int *: Int *: Int *: Int *: Int *: Int *: Int *: Int *:
Int *: Int *: Int *: Int *: Int *: Int *:
EmptyTuple
inferred: Expected
}
Removing the line inferred: Expected
reduces the compile time to under a second, indicating that the issue isn't with the construction of the Twiddle or the Expected type per se.
Anything more than 30 elements in a twiddle, and the compilation times explode.
Here is the compilation profile for the snippet:
*** Cumulative timers for phases
#total compile time : 1 spans, ()35254.291ms
parser : 1 spans, ()2.018ms (0.0%)
bm4-parser : 1 spans, ()11.805ms (0.0%)
bm4-parser2 : 1 spans, ()2.683ms (0.0%)
kind-projector : 1 spans, ()3.806ms (0.0%)
namer : 1 spans, ()213.77ms (0.6%)
packageobjects : 1 spans, ()14.133ms (0.0%)
typer : 1 spans, ()34539.101ms (98.0%) <------ typechecking is the problem
bm4-typer : 1 spans, ()4.953ms (0.0%)
superaccessors : 1 spans, ()0.93ms (0.0%)
extmethods : 1 spans, ()0.186ms (0.0%)
pickler : 1 spans, ()0.299ms (0.0%)
xsbt-api : 1 spans, ()3.484ms (0.0%)
xsbt-dependency : 1 spans, ()15.01ms (0.0%)
refchecks : 1 spans, ()12.612ms (0.0%)
patmat : 1 spans, ()0.202ms (0.0%)
uncurry : 1 spans, ()1.76ms (0.0%)
fields : 1 spans, ()0.377ms (0.0%)
tailcalls : 1 spans, ()0.192ms (0.0%)
specialize : 1 spans, ()33.64ms (0.1%)
explicitouter : 1 spans, ()0.511ms (0.0%)
erasure : 1 spans, ()4.071ms (0.0%)
posterasure : 1 spans, ()0.405ms (0.0%)
lambdalift : 1 spans, ()0.598ms (0.0%)
constructors : 1 spans, ()1.067ms (0.0%)
flatten : 1 spans, ()0.182ms (0.0%)
mixin : 1 spans, ()0.431ms (0.0%)
cleanup : 1 spans, ()0.862ms (0.0%)
delambdafy : 1 spans, ()0.332ms (0.0%)
jvm : 1 spans, ()27.799ms (0.1%)
scalacenter-profiling : 1 spans, ()267.273ms (0.8%)
xsbt-analyzer : 1 spans, ()7.995ms (0.0%)
and details for the typer phase:
*** Cumulative statistics at phase typer
#plausibly compatible : 30 (100.0%)
#typed : 30 (100.0%)
#class symbols : 10294
#typechecked selections : 159
#created tree nodes : 1996
#created scopes : 750
#implicit inscope hits : 30 (100.0%)
#implicit searches : 30
#plausibly compatible : 30 (100.0%)
#matching : 30 (100.0%)
#typed : 30 (100.0%)
#found : 30 (100.0%)
#implicit inscope hits : 30 (100.0%)
time spent in scope population: 122 spans, ()0.012ms
#findMember ops : 2181
of which not found : 631 (28.9%)
of which multiple overloaded: 2 (0.1%)
of which in implicit : 1069 (49.0%)
#subtype ops : 1236
of which in implicit : 510 (41.3%)
#base type seqs : 204
avg base type seq length : 4.2
of which for compound types : 30 (14.7%)
of which for typerefs : 173 (84.8%)
#type symbols : 19269
#unique types : 3221
#typechecked identifiers : 189
#found : 30 (100.0%)
#symbols : 32117
time spent typechecking : 1 spans, ()34539.089ms
time spent in lubs : 0 spans, ()0.0ms (0.0%) aggregate, 0.0ms (0.0%) specific
time spent in <:< : 1236 spans, ()34447.786ms (99.7%) aggregate, 34447.678ms (99.7%) specific <----- subtyping check (?)
time spent in findmember : 2181 spans, ()0.935ms (0.0%) aggregate, 0.935ms (0.0%) specific
time spent in findmembers : 0 spans, ()0.0ms (0.0%) aggregate, 0.0ms (0.0%) specific
time spent in asSeenFrom : 4797 spans, ()25.053ms (0.1%) aggregate, 24.847ms (0.1%) specific
time spent in baseTypeSeq : 203 spans, ()1.032ms (0.0%) aggregate, 0.714ms (0.0%) specific
time spent in baseClasses : 93 spans, ()2.786ms (0.0%) aggregate, 2.393ms (0.0%) specific
time classfilereading : 114 spans, ()55.341ms (0.2%)
time spent in failed : 0 spans, ()0.0ms (0.0%)
failed apply : 0 spans, ()0.0ms (0.0%)
failed op= : 0 spans, ()0.0ms (0.0%)
time spent ref scanning : 0 spans, ()0.0ms (0.0%)
time spent in implicits : 30 spans, ()60.276ms (0.2%)
successful in scope : 30 spans, ()49.516ms (0.1%)
failed in scope : 0 spans, ()0.0ms (0.0%)
successful of type : 0 spans, ()0.0ms (0.0%)
failed of type : 0 spans, ()0.0ms (0.0%)
assembling parts : 0 spans, ()0.0ms (0.0%)
matchesPT : 60 spans, ()0.224ms (0.0%)
time spent in macroExpand : 0 spans, ()0.0ms (0.0%)
#sametype ops : 536870914
#all lubs/glbs : 60
#typechecked applications : 91
#matching : 30 (100.0%)
Interestingly, I found that specifying the type variances in the type alias *:
for Scala 2 exactly as done in Shapeless (so type *:[+A, +B <: Tuple] = ::[A, B]
) eliminates this problem. This observation is intriguing since, in theory, specifying variances in a type alias should be functionally equivalent to not specifying them.
I'll open a PR shortly with this solution, even though I'll admit I'm not 100% sure of why it seems to solve the problem. In the meantime any insights you might have would be incredibly valuable.
Thanks again!