T2-A — readonly-параметры ресурсных структур
Реализованный первый срез. T2-A добавляет непотребляющее наблюдение пользовательских ресурсных структур. Проект T2-A/B остаётся отдельным документационным PR; локальные subviews и возвращаемый TextView не входят в эту реализацию.
struct Holder {buffer:memory.Buffer<u8>;length:u32}
fn length(borrow value:Holder)->u32 {
return value.length
}
fn capacity(borrow value:Holder)->u32 {
return memory.len(value.buffer)
}
borrow — режим доступа параметра, не свойство типа Holder. На стороне вызова
используется length(owner) без move и без отдельного выражения borrow owner.
Владелец остаётся доступным; после возврата разрешены move, обновление через
потребляющую функцию и завершение ресурса. Функция не обязана и не имеет права
закрывать readonly-параметр.
Права и ограничения
Параметр должен иметь конкретный тип пользовательской ресурсной структуры. Скаляр, обычная копируемая структура, голый Buffer/Vec/Region в такой позиции пока не поддерживаются. Можно наблюдать вложенные ресурсные поля такой структуры. Generic-функции допускаются при инстанцировании ресурсным типом; режим и права сохраняются при подстановке. Тело проверяется после конкретизации, как и раньше.
Разрешены чтение доступных копируемых полей и их независимые снимки, наблюдающие builtin-операции и передача readonly-проекции другому readonly-параметру. Ресурсное поле остаётся проекцией исходного корня: его нельзя связать как owned, скопировать, переместить, разобрать, вернуть, поместить в вариант или агрегат. Нельзя обновить поле readonly-параметра. Приватность проверяется на каждом пути независимо от режима доступа; borrow не открывает поля чужого модуля.
Первый срез требует от функции с readonly-параметрами независимого копируемого результата. View нельзя вернуть или сохранить в агрегат, даже вложенный. Временный ресурс в borrowed-позиции запрещён: требуется доступная именованная привязка или проекция readonly-параметра внутри callee. Ресурсные alias-привязки, borrowed-match вариантов и неоднозначные выбираемые пути к ресурсу не вводятся. Прежние ограничения рекурсивных сводок с зависимостями хранилища сохраняются.
Readonly не равно borrowed_params или pure
Существующие trusted-адаптеры могут получать ресурс без передачи владения и
изменять его. Поэтому borrowed_params не даёт разрешения работать с readonly-
проекцией. Для builtin есть отдельный явный список разрешённых наблюдений:
memory.len,memory.view;vec.len,vec.capacity,vec.get,vec.view.
memory.alloc через readonly-регион запрещён, как и изменяющие вызовы File или
Reactor. Передать readonly-ресурс потребляющему builtin также нельзя. Пользовательские
readonly-функции не помечаются trusted_library: их тела проходят обычные проверки.
Эффекты независимы. Наблюдатель может иметь io и вывести данные через console,
не изменяя ресурс. pure не даёт readonly-полномочий автоматически.
Время жизни и происхождение
Аргументы вычисляются слева направо. Заём аргумента активен до возврата всего
вызова, включая вычисление следующих аргументов и вложенные вызовы. Например,
use(owner, consume(move owner)) запрещён, если первый параметр use — readonly.
В обратном порядке обнаруживается use-after-move. Два readonly-аргумента одного
владельца допустимы. После вызова заём не сохраняется в caller.
Проекции и reborrow сохраняют корневой параметр и происхождение хранилища по полям. Нельзя закрыть тот же регион через другой аргумент. Права не теряются при generic-инстанцировании, ветвлении или цикле; доступность owned-аргументов по-прежнему проверяется на всех продолжающихся путях.
В Semantic IR пользовательский параметр и соответствующий аргумент вызова
имеют режим readonly. Проекции помечаются readonly_projection и ссылкой
owner_binding на корень; наблюдающий вызов через проекцию также сохраняет корень.
Это не owned-извлечение Buffer, хотя физически используется прежний дескриптор.
Сводка отдельно перечисляет readonly_parameters, не объявляя их потреблёнными.
Режим borrow старых адаптеров и существующих owned-вызовов не переименовывается.
Непотребляющий String
Обычный модуль examples/text/string.liza теперь предоставляет:
| Вызов | Результат |
|---|---|
text.string.length(current) |
Логическая длина в байтах |
text.string.capacity(current) |
Вместимость |
text.string.byte_at(current,index) |
Option<u8>; вне длины — None |
После любого из этих вызовов можно вызвать append(move current, data),
clear(move current) или release(move current). inspect(move current)
сохраняется как потребляющая операция T1.
Изменение API: прежний byte_at(move current,index) возвращал структуру Byte
с владельцем и результатом. Теперь используется byte_at(current,index) без
деструктуризации и без move. Тип Byte удалён. Доступ байтовый, не индексирование
Unicode-символов; UTF-8-инвариант строки и атомарность отказа append не меняются.
Внутри byte_at используется существующий полный memory.view и предварительная
проверка index < length. View локален и не выходит наружу. Поддержка именно
диапазона [0,length) как передаваемого view, subviews и корректное наследование
loans при их создании остаются T2-B. Полный capacity нельзя выдавать за текст.
Стоимость и проверка
Для трёх наблюдателей String стоимость не зависит от длины или capacity: передаются дескрипторы, для byte_at читается один байт. Это не обещание O(1) для любого readonly-метода: снимок большого копируемого поля имеет свою стоимость.
Проверка стоимости исследует O0/O2 LLVM конкретных трёх функций: отсутствие аллокатора, bulk-copy и непрозрачных helper-вызовов, наличие runtime-чтения байта. Нативные тесты проверяют независимость большого снимка, вложенные вызовы и циклы. Отрицательные контроли охватывают приватность, owned-извлечение, мутации через legacy borrowed_params, порядок аргументов, region origins и escape view.
V0–V4 и Relay остаются регрессиями прежних программ. Их успешные результаты не доказывают soundness T2-A. Новые правила проверены тестами; отдельная формальная модель readonly-полномочий пока не построена. Многопоточность, mutable borrows, возвращаемые TextView и долгоживущие займы не входят в T2-A.