4

I'm currently playing with ASM and analysing the classes' generics signatures. The documented possible content in this section is described here and could be summarised with the following grammar:

TypeSignature: Z | C | B | S | I | F | J | D | FieldTypeSignature

FieldTypeSignature: ClassTypeSignature | [ TypeSignature | TypeVar

ClassTypeSignature: L Id ( / Id ) TypeArgs? ( . Id TypeArgs? )* ;*

TypeArgs: < TypeArg+ >

TypeArg: ** | ( + | - )? FieldTypeSignature*

TypeVar: T Id ;

However, I found for one case that it's not true:

trait SomeTrait
class SomeClass[T <: SomeTrait]

Generics signature for SomeClass: <T::LSomeTrait;>Ljava/lang/Object;

I don't understand why :: appeared here and what does it mean. Doubled : is not valid from the grammar point of view. What's interesting, if I'll replace trait with abstract class the :: will be replaced with a single : (what's expected).

Any ideas?

cchantep
  • 9,118
  • 3
  • 30
  • 41
Adam Sznajder
  • 9,108
  • 4
  • 39
  • 60

1 Answers1

3

The class file spec says (in section 4.7.9.1. Signatures):

ReferenceTypeSignature:
  ClassTypeSignature
  TypeVariableSignature
  ArrayTypeSignature
TypeParameters:
  < TypeParameter {TypeParameter} >
TypeParameter:
  Identifier ClassBound {InterfaceBound}
ClassBound:
  : [ReferenceTypeSignature]
InterfaceBound:
  : ReferenceTypeSignature

Applying this to <T::LSomeTrait;> means:

   TypeParameters
=> < TypeParameter {TypeParameter} >
=> < Identifier ClassBound {InterfaceBound} {TypeParameter} >
=> < T ClassBound {InterfaceBound} {TypeParameter} >
=> < T : [ReferenceTypeSignature] {InterfaceBound} {TypeParameter} >
=> < T : {InterfaceBound} {TypeParameter} >
=> < T : : ReferenceTypeSignature {TypeParameter} >
=> < T : : LSomeTrait; {TypeParameter} >
=> < T : : LSomeTrait; >
=> <T::LSomeTrait;>

All in all, the first colon introduces the class bound and the second colon introduces the interface bound. The fact that the two colons stay together means that there is no class bound.

Signature with both a class and an interface:

scala> trait T
defined trait T

scala> abstract class A
defined class A

scala> class C[X <: A with T]
defined class C

scala> :javap C
  Size 554 bytes
  MD5 checksum 6273d85df5987e350e7112726756a55f
  Compiled from "<console>"
public class C<X extends A & T> extends java.lang.Object
  minor version: 0
  major version: 50
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Utf8               C
   #2 = Class              #1             // C
   #3 = Utf8               <X:LA;:LT;>Ljava/lang/Object;
...
kiritsuku
  • 52,967
  • 18
  • 114
  • 136