Skip to content

Повторный расчёт значения метода не монотонен: набор типов может обеднеть #4480

Description

@nixel2007

Что не так

Пересчёт значения метода по телу должен только дополнять набор типов — на это опирается и сходимость взаимной рекурсии, и весь механизм доразрешения (MethodReturnTypeIndexer, javadoc класса: «Набор типов при пересчёте только растёт, поэтому взаимная рекурсия сходится»).

На практике это не так: лишний пересчёт может дать более бедный набор, и результат снова начинает зависеть от порядка.

Как обнаружено

При работе над #4429 в MethodReturnTypeIndexer появились отметки «когда метод посчитан» и «когда в документе менялись значения»: по ним проход добирает методы, чья зависимость обогатилась уже после их расчёта.

Отметка изменения снимается до расчёта. Строго правильнее снимать её после публикации значения — тогда ловится и случай, когда зависимость начала считаться раньше потребителя, но выложила новое значение уже после того, как тот её прочитал.

Замер на ssl_3_1 (диагностики UnknownMember и EventHandlerInvalidSignature, по 6 прогонов, все четыре правки из #4476, #4477, #4478, #4479):

отметка изменения мерцающих замечаний за 6 прогонов
до расчёта 0, все подписи побайтово одинаковы
после публикации 10, один прогон из шести выпадает

То есть более строгая — и логически более правильная — пометка устаревания делает результат менее воспроизводимым. Единственное объяснение, согласующееся с данными: часть добранных на пересчёт методов при повторном счёте теряет типы, и разница расходится дальше по цепочке.

Очаг в замерах один и тот же — CommonForms.ПанельОтчетов, функция НачатьЗамер: переменная Замер объявлена переменной модуля, её тип собирается объединением по всему модулю и включает Замер = НачатьЗамер(...), а сама НачатьЗамер возвращает Возврат Замер.

Почему это важно

Пока пересчёт не монотонен, любое усиление пометок устаревания упирается в потолок: чем полнее доразрешение, тем больше шансов потерять уже посчитанное. Из-за этого в #4476 оставлена заведомо более слабая пометка — она пропускает перекрытие расчёта с публикацией, зато не разъезжается.

Что стоит сделать

  1. Найти путь, на котором повторный расчёт даёт более бедный набор, чем первый (подозрение на уточняющий проход по рекурсии и на объединение по переменной модуля).
  2. Либо сделать пересчёт монотонным по построению — например, объединять новый набор с уже сохранённым, — либо явно описать, где и почему монотонность не держится.
  3. После этого вернуть в MethodReturnTypeIndexer отметку изменения, снимаемую после публикации значения.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions