/
nv-lang
/
nova
Обзор
Документация
Войти
/
nv-lang
/
nova
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
std/src/runtime/char_test.nv
85 строк
5 KB
Evgeniy Golovin
style(225.1): вертикальный ритм — sweep классов a-e (std/src)
26 июл 2026, 02:46
26 июл 2026, 02:46
38ecf16
Код
Авторство
О чём код?
// SPDX-License-Identifier: MIT OR Apache-2.0 // Регрессия [M-char-blanket-shadowed-by-sig-complete] (2026-07-17, стоп-волна // fix-runtime-lint-debt): `char` не имел НИ ОДНОГО конкретного receiver-метода // в `builtin_sig_modules()` (checker's SIG-COMPLETE registry, compiler-codegen/ // src/codegen/external_registry.rs) до появления `char @to_stringbuilder()` // (std/runtime/string_builder.nv). Как только тип получил ЛЮБОЙ конкретный // receiver-метод там, checker'а `check_instance_overload` (types/mod.rs) // признавал метод-набор типа "SIG-COMPLETE" ЦЕЛИКОМ — включая методы, которые // реально резолвятся ТОЛЬКО через bare-T blanket (`fn[T] T @to_str() -> str`, // std/runtime/string/core.nv, D145-форма) — и бил ложный E7320 // (`no field or method to_str on type char`) на std/src/runtime/sync_test.nv // (defaults.nv/string/core.nv/string/transform.nv все звали `c.to_str()`). // // Этот файл — standalone peer-test для `runtime.char` (beside-module // convention, sync_test.nv/string_builder_test.nv precedent): пин co-existence // bare-T blanket метода И конкретного receiver-метода на ОДНОМ И ТОМ ЖЕ // примитиве в одном CU — именно комбинация, что взорвала sync_test. module runtime.char_test import std.runtime.string_builder.{StringBuilder} // `char @to_str()` НЕ конкретный — резолвится через bare-T blanket // (`fn[T] T @to_str() -> str => "${@}"`, string/core.nv). Должен продолжать // резолвиться даже когда `char` уже имеет конкретный receiver-метод // (`@to_stringbuilder()` ниже) в SIG-COMPLETE builtin_sig_modules-реестре. test "char @to_str(): bare-T blanket resolves alongside a concrete char method" { ro a = 'A'.to_str() assert(a == "A") // Multi-byte codepoint (UTF-8 encode путь совпадает с интерполяцией). ro heart = '\u{2764}'.to_str() assert(heart.byte_len() == 3) } // Конкретный extension-метод на `char` (не через blanket) — регистрируется в // builtin_sig_modules (string_builder.nv → BUILTIN_SIG_MODULES), делая `char` // SIG-COMPLETE. Должен резолвиться нормально И не затенять @to_str() выше. test "char @to_stringbuilder(): concrete method coexists with the blanket" { consume sb = 'A'.to_stringbuilder() ro s = sb.into_str() assert(s == "A") } // Оба метода на одном значении в одном выражении — прямой репро исходного // бага (blanket .to_str() рядом со звонком, доказывающим SIG-COMPLETE char). test "char: to_str() and to_stringbuilder() together on the same value" { ro c = 'x' ro viastr = c.to_str() consume sb = c.to_stringbuilder() assert(viastr == sb.into_str()) } // Регрессия [M-forin-crosspkg-char-to_str-blanket-collision] (2026-07-21, // нашедшая A-S4 / for-in cross-package): codegen-side twin бага выше. // `char @to_str()` резолвится ТОЛЬКО через bare-T blanket (`fn[T] T @to_str() // -> str`) — но `[]u8 @to_str() -> Result[str, Utf8Error]` (Plan 174.1/196.7, // std/runtime/string/core.nv) — КОНКРЕТНЫЙ метод на ДРУГОМ типе с ТЕМ ЖЕ // именем. `infer_call_ret_c`'s name-only legacy fallback (`fn_ret_{method}`, // emit_c.rs) — единый ключ БЕЗ receiver-типа, куда пишет forward-decl ЛЮБОГО // `to_str`-метода; т.к. generic-blanket методы возвращаются РАНЬШЕ (свой // early-return в forward-decl pass, никогда не пишут в этот ключ), ключ // всегда содержит return-тип ПОСЛЕДНЕГО зарегистрированного КОНКРЕТНОГО // `to_str` — здесь `[]u8`'s `Result[str, Utf8Error]`, а НЕ `char`'s `str`. // Найдено через `std/src/encoding/url.nv`'s `for b in c.to_str().bytes()` // (внутри `for c in s.chars()`) — `.bytes()` на ошибочно-инференном // `Result`-типе эродировало до `nova_int`, и for-in терял резолв // iterator-типа (`cannot resolve iterator type for expression of C-type // 'nova_int'`) — воспроизведено в `nova-http` (5×CODEGEN-FAIL), но корень // НЕ cross-package: same-CU/same-package коллизия имени метода. Фикс: // codegen предпочитает bare-T blanket (`mono_method_decls[("T"/1-2 uppercase // letters, method)]`) ПЕРЕД name-only fallback для ПРИМИТИВНОГО receiver'а. test "char.to_str().bytes() nested for-in — no []u8.to_str() name collision" { mut total = 0 for c in "aB".chars() { for b in c.to_str().bytes() { total = total + (b as int) } } // 'a' (0x61=97) + 'B' (0x42=66) = 163. assert(total == 163) }