Информация о типах для примитивных типов в полиморфных типах

Учитывая следующий объект:

object Foo {
  val bar: List[Int] = List(1, 2, 3)
}

Когда мы компилируем этот файл в байт-код JVM, из-за стирания типов и из-за того, что Java не поддерживает примитивные типы в качестве параметров для универсальных типов, это преобразуется в файл List<Object>.

Мы можем увидеть это, скомпилировав и проверив .class с javap -l:

public static com.yuvalitzchakov.github.Foo$ MODULE$;
  descriptor: Lcom/yuvalitzchakov/github/Foo$;
  flags: ACC_PUBLIC, ACC_STATIC

public scala.collection.immutable.List<java.lang.Object> bar();
  descriptor: ()Lscala/collection/immutable/List;
  flags: ACC_PUBLIC
  Code:
    stack=1, locals=1, args_size=1
        0: aload_0
        1: getfield      #19                 // Field bar:Lscala/collection/immutable/List;
        4: areturn
      LineNumberTable:
        line 4: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/yuvalitzchakov/github/Foo$;
    Signature: #17                          // ()Lscala/collection/immutable/List<Ljava/lang/Object;>;

Но если мы скомпилируем это в файл JAR, а затем возьмем его как зависимость в другом проекте Scala и попытаемся установить Foo.bar в другое значение, компилятор Scala выведет этот тип как List[Int], а не List[Object]:

Введите после принятия зависимости от упакованного JAR

После просмотра файла .class я не смог найти информацию о параметре типа, который позволил бы компилятору Scala успешно вывести это как List[Int].

Где хранятся эти метаданные, чтобы мы могли ссылаться на этот тип как на фактический List[Int] вместо List[Object]?


person Yuval Itzchakov    schedule 21.11.2018    source источник
comment
Я бы предположил, что для системы типов Scala существуют определенные атрибуты Scala, которые javap не понимает и, следовательно, не печатает.   -  person Holger    schedule 21.11.2018
comment
@Holger Интересно, возможно, поможет рассмотрение фазы JVM scalac.   -  person Yuval Itzchakov    schedule 21.11.2018


Ответы (1)


Формат файла класса JVM позволяет компиляторам помещать пользовательские атрибуты в файл класса, см. Раздел 4.7.1 документа Спецификация виртуальной машины Java. Помимо прочего, компилятор Scala помещает информацию о сигнатуре имен Scala в генерируемые им файлы классов, чтобы при последующем запуске компилятора он мог снова прочитать эту информацию. Виртуальные машины Java должны игнорировать атрибуты, которые они не понимают, поэтому во время выполнения это не имеет значения.

Я не нашел спецификацию бинарного формата для аннотаций, но если вы хотите покопаться в реализации, я нашел:

Для Scala 3.0 даже планируется хранить полное абстрактное синтаксическое дерево, включая информацию, сгенерированную проверкой типов, в файлах классов, используя новый «вкусный» формат. Tasty означает «типизированные абстрактные синтаксические деревья». Основная идея состоит в том, чтобы сериализовать абстрактное синтаксическое дерево после этапа проверки типов и поместить его в файлы классов. Последующие запуски компилятора могут затем загрузить полный абстрактный синтаксис зависимостей. Это может позволить не только проверку типов, но и межмодульное встраивание и другие глобальные оптимизации.

Планируется, что Tasty станет универсальным форматом обмена для абстрактных синтаксических деревьев Scala, а также для связи между компилятором и интегрированными средами разработки и для метапрограммирования.

Если вы хотите покопаться в реализации, возможно, файлы в https://github.com/lampepfl/dotty/tree/master/compiler/src/dotty/tools/dotc/core/tasty — хорошее начало.

person Toxaris    schedule 21.11.2018