Что не так
Пересчёт значения метода по телу должен только дополнять набор типов — на это опирается и сходимость взаимной рекурсии, и весь механизм доразрешения (MethodReturnTypeIndexer, javadoc класса: «Набор типов при пересчёте только растёт, поэтому взаимная рекурсия сходится»).
На практике это не так: лишний пересчёт может дать более бедный набор, и результат снова начинает зависеть от порядка.
Как обнаружено
При работе над #4429 в MethodReturnTypeIndexer появились отметки «когда метод посчитан» и «когда в документе менялись значения»: по ним проход добирает методы, чья зависимость обогатилась уже после их расчёта.
Отметка изменения снимается до расчёта. Строго правильнее снимать её после публикации значения — тогда ловится и случай, когда зависимость начала считаться раньше потребителя, но выложила новое значение уже после того, как тот её прочитал.
Замер на ssl_3_1 (диагностики UnknownMember и EventHandlerInvalidSignature, по 6 прогонов, все четыре правки из #4476, #4477, #4478, #4479):
| отметка изменения |
мерцающих замечаний за 6 прогонов |
| до расчёта |
0, все подписи побайтово одинаковы |
| после публикации |
10, один прогон из шести выпадает |
То есть более строгая — и логически более правильная — пометка устаревания делает результат менее воспроизводимым. Единственное объяснение, согласующееся с данными: часть добранных на пересчёт методов при повторном счёте теряет типы, и разница расходится дальше по цепочке.
Очаг в замерах один и тот же — CommonForms.ПанельОтчетов, функция НачатьЗамер: переменная Замер объявлена переменной модуля, её тип собирается объединением по всему модулю и включает Замер = НачатьЗамер(...), а сама НачатьЗамер возвращает Возврат Замер.
Почему это важно
Пока пересчёт не монотонен, любое усиление пометок устаревания упирается в потолок: чем полнее доразрешение, тем больше шансов потерять уже посчитанное. Из-за этого в #4476 оставлена заведомо более слабая пометка — она пропускает перекрытие расчёта с публикацией, зато не разъезжается.
Что стоит сделать
- Найти путь, на котором повторный расчёт даёт более бедный набор, чем первый (подозрение на уточняющий проход по рекурсии и на объединение по переменной модуля).
- Либо сделать пересчёт монотонным по построению — например, объединять новый набор с уже сохранённым, — либо явно описать, где и почему монотонность не держится.
- После этого вернуть в
MethodReturnTypeIndexer отметку изменения, снимаемую после публикации значения.
Что не так
Пересчёт значения метода по телу должен только дополнять набор типов — на это опирается и сходимость взаимной рекурсии, и весь механизм доразрешения (
MethodReturnTypeIndexer, javadoc класса: «Набор типов при пересчёте только растёт, поэтому взаимная рекурсия сходится»).На практике это не так: лишний пересчёт может дать более бедный набор, и результат снова начинает зависеть от порядка.
Как обнаружено
При работе над #4429 в
MethodReturnTypeIndexerпоявились отметки «когда метод посчитан» и «когда в документе менялись значения»: по ним проход добирает методы, чья зависимость обогатилась уже после их расчёта.Отметка изменения снимается до расчёта. Строго правильнее снимать её после публикации значения — тогда ловится и случай, когда зависимость начала считаться раньше потребителя, но выложила новое значение уже после того, как тот её прочитал.
Замер на ssl_3_1 (диагностики
UnknownMemberиEventHandlerInvalidSignature, по 6 прогонов, все четыре правки из #4476, #4477, #4478, #4479):То есть более строгая — и логически более правильная — пометка устаревания делает результат менее воспроизводимым. Единственное объяснение, согласующееся с данными: часть добранных на пересчёт методов при повторном счёте теряет типы, и разница расходится дальше по цепочке.
Очаг в замерах один и тот же —
CommonForms.ПанельОтчетов, функцияНачатьЗамер: переменнаяЗамеробъявлена переменной модуля, её тип собирается объединением по всему модулю и включаетЗамер = НачатьЗамер(...), а самаНачатьЗамервозвращаетВозврат Замер.Почему это важно
Пока пересчёт не монотонен, любое усиление пометок устаревания упирается в потолок: чем полнее доразрешение, тем больше шансов потерять уже посчитанное. Из-за этого в #4476 оставлена заведомо более слабая пометка — она пропускает перекрытие расчёта с публикацией, зато не разъезжается.
Что стоит сделать
MethodReturnTypeIndexerотметку изменения, снимаемую после публикации значения.