Compiler version
3.9.0, and still present in 3.10.0-RC1.
Bisected against the release artifacts:
| version |
result |
| 3.8.4 |
ok |
| 3.9.0-RC1 … RC4 |
ok |
| 3.9.0-RC5 |
crash |
| 3.9.0-RC6, 3.9.0 |
crash |
| 3.10.0-RC1 |
crash |
Minimized code
object O:
object I:
object C
export I.*
val a: C.type = C
Output
Error while emitting O$
( (of class java.lang.Character)
1 error found
(No stack trace is printed, so the MatchError scrutinee — the char ( — is all the
diagnostic there is.)
Expectation
It should compile, as it does on 3.8.4.
Notes
The crash needs two ingredients: an export, and a val whose declared type is the
singleton type of the exported alias. It goes away if either one is removed:
object O:
object I:
object C
export I.*
val a: I.C.type = C // ok — type written through the original, not the alias
object O:
object I:
object C
export I.*
val a = C // ok — inferred type
object O:
object I:
object C
export I.*
def a: C.type = C // ok — def instead of val
Variations that all still crash, so the trigger is narrow but not exotic:
case class C(x: Int) or an enum case instead of object C
- a plain term:
object I { val x: Int = 1 }; export I.*; val a: x.type = x
- targeted export (
export I.C) as well as wildcard
- top level rather than inside an object (crashes as
Error while emitting G$package$)
- the exporting object being top-level rather than nested
-Xno-generic-signatures makes it compile, which places the failure in generic-signature
handling rather than in descriptor emission.
A likely mechanism: export I.* emits a forwarder method C() (confirmed with javap
on a build using -Xno-generic-signatures):
public final O$E$C$ C();
public O$E$C$ a();
so C.type in val a: C.type is the singleton type of a method reference, and the
generic signature computed for the field appears to come out as (or to contain) a method
descriptor — hence a ( reaching something that expects a reference type signature.
This looks like the same failure family as #26786 ("Match-error in JVM backend when emitting
HK-type with type lambda containing primitive"), which reported
Z (of class java.lang.Character) from GenericSignatureVisitor.referenceTypeSignature.
The version bisect above matches that issue's backport window (it landed in 3.9.0-RC5), so
this is plausibly the same #26632 lineage with a different malformed input. #26787 is in
3.9.0 and does not cover this case.
Found on real code during a 3.8.4 -> 3.9.0 upgrade; the shapes above are reduced from it.
Provenance: the minimization, the version bisect and the flag experiments above were done by
Claude (Claude Code), prompted by a developer who hit the crash while upgrading a real project.
Take it for what it is — but note what is and is not verified. Every row of the version table and
every ok/crash claim is an actual run of the published release artifact against the snippet as
written, reproducible in a few seconds each. The proposed mechanism, and the suggested link to
#26786 and #26632, are inference from black-box behaviour: no one read the 3.9.0 backend source,
and the compiler prints no stack trace for this crash. Discount those two paragraphs accordingly;
the reproducer and the bisect stand on their own.
Compiler version
3.9.0, and still present in 3.10.0-RC1.
Bisected against the release artifacts:
Minimized code
Output
(No stack trace is printed, so the
MatchErrorscrutinee — the char(— is all thediagnostic there is.)
Expectation
It should compile, as it does on 3.8.4.
Notes
The crash needs two ingredients: an
export, and avalwhose declared type is thesingleton type of the exported alias. It goes away if either one is removed:
Variations that all still crash, so the trigger is narrow but not exotic:
case class C(x: Int)or anenumcase instead ofobject Cobject I { val x: Int = 1 }; export I.*; val a: x.type = xexport I.C) as well as wildcardError while emitting G$package$)-Xno-generic-signaturesmakes it compile, which places the failure in generic-signaturehandling rather than in descriptor emission.
A likely mechanism:
export I.*emits a forwarder methodC()(confirmed withjavapon a build using
-Xno-generic-signatures):so
C.typeinval a: C.typeis the singleton type of a method reference, and thegeneric signature computed for the field appears to come out as (or to contain) a method
descriptor — hence a
(reaching something that expects a reference type signature.This looks like the same failure family as #26786 ("Match-error in JVM backend when emitting
HK-type with type lambda containing primitive"), which reported
Z (of class java.lang.Character)fromGenericSignatureVisitor.referenceTypeSignature.The version bisect above matches that issue's backport window (it landed in 3.9.0-RC5), so
this is plausibly the same #26632 lineage with a different malformed input. #26787 is in
3.9.0 and does not cover this case.
Found on real code during a 3.8.4 -> 3.9.0 upgrade; the shapes above are reduced from it.
Provenance: the minimization, the version bisect and the flag experiments above were done by
Claude (Claude Code), prompted by a developer who hit the crash while upgrading a real project.
Take it for what it is — but note what is and is not verified. Every row of the version table and
every ok/crash claim is an actual run of the published release artifact against the snippet as
written, reproducible in a few seconds each. The proposed mechanism, and the suggested link to
#26786 and #26632, are inference from black-box behaviour: no one read the 3.9.0 backend source,
and the compiler prints no stack trace for this crash. Discount those two paragraphs accordingly;
the reproducer and the bisect stand on their own.