RFC-029: Система семантики модулей
Аннотация
Подключение системы модулей к компиляционному конвейеру для реализации мног файловой компиляции и контроля видимости на уровне пакетов.
Основной принцип: проверщик типов запрашивает только предварительно построенный реестр модулей, не обращаясь к диску. Граф модулей строится полностью до проверки типов.
Не включает: кэширование, отслеживание файлов, горячую перезагрузку, инкрементную перекомпиляцию. Это оптимизации жизненного цикла компиляции, относятся к будущим отдельным RFC.
Мотивация
Текущие проблемы
- Компилятор поддерживает только один файл:
Compiler::compile(name, source)не может обрабатывать межфайловые зависимости - Правила экспорта конфликтуют: типы экспортируются автоматически, константы экспортируются автоматически, методы экспортируются автоматически, функции проверяют
pub— четыре набора исключений - Два модуля разрешителя:
frontend/module/resolver.rsиpackage/source/module_resolver.rsс разным порядком поиска - Проверщик типов связан с загрузкой файлов: черновик требовал, чтобы
useво время проверки типов вызывалModuleLoader::load()
Цели проектирования
- Один проект может компилировать несколько файлов
.yx - Семантика операторов
useпонятна и однозначна - Правила видимости унифицированы в одно
- Однофайловый режим продолжает работать,
yaoxiang.tomlне требуется - Проверщик типов — чистая логика, не выполняет файловый I/O
Предложение
1. Идентичность модуля и разрешение путей
Определение модуля
Модуль — это файл .yx. Путь к модулю — это точка-разделённый именованный путь, соответствующий расположению в файловой системе.
math.geometry → src/math/geometry.yx
→ src/math/geometry/mod.yx
→ src/math/geometry/index.yxПакет — это проект с yaoxiang.toml, содержащий несколько модулей. Пакет — единственная граница инкапсуляции.
Правила разрешения путей
Порядок поиска (единственное правило, заменяющее существующие два набора):
- Стандартная библиотека:
stdилиstd.*→ встроенные модули, запрашиваются изModuleRegistry - Директория vendor:
.yaoxiang/vendor/<pkg>-*/src/→ зависимые пакеты - Относительный путь текущего файла: относительно директории текущего файла
.yx - Директория src проекта:
<project_root>/src/
Порядок попыток определения файла:
base/name.yx
base/name/mod.yx
base/name/index.yxПри нахождении первого существующего файла поиск прекращается. Если name.yx и name/mod.yx существуют одновременно, выдаётся ошибка:
Неоднозначность пути модуля: `math.geometry` одновременно соответствует:
src/math/geometry.yx
src/math/geometry/mod.yx
Пожалуйста, удалите один из них.Унифицированный разрешитель
Устраняем два существующих ModuleResolver. Сохраняем frontend/module/resolver.rs как единственную реализацию, удаляем package/source/module_resolver.rs. Поддержка переменной окружения YXPATH объединяется в единственном разрешителе.
2. Семантика импорта
Синтаксические формы
use math.geometry # пространство имён модуля
use math.geometry as geo # псевдоним пространства имён модуля
use math.geometry.{Point} # выборочный импорт
use math.geometry.{Point, distance} # множественный выборочный импорт
use math.geometry.{Point as P} # выборочный импорт с псевдонимом
use math.geometry.{Point as P, distance as dist} # множественный с псевдонимамиСемантика
Все формы импорта являются правилами разрешения имён на этапе компиляции, а не копированием ссылок во время выполнения. Импортированные имена указывают на идентичность объявления в таблице экспортов модуля.
| Синтаксис | Привязка к текущей области видимости | Способ использования |
|---|---|---|
use path | последний сегмент path как пространство имён | geometry.Point |
use path as alias | alias как пространство имён | alias.Point |
use path.{item} | сам item | item |
use path.{item as alias} | сам alias | alias |
Удалённый синтаксис
: форма Python from-import не принятаfrom path use item: импорт с подстановочным знаком создаёт риск конфликтов, импорт пространства имён модуля достаточенuse path.*: позиционное сопоставление в параллельных списках — хрупкая структура данных, псевдонимы должны следовать после каждого объявления:use path.{a, b} as c, duse path.{a as c, b as d}
Семантика путей
path в use path всегда является путём модуля, а не объявлением. Если модуль не найден, выдаётся ошибка:
Модуль `math.geometry.Point` не найден.
Если `Point` — это объявление в модуле `math.geometry`, используйте:
use math.geometry.{Point}Fallback «сначала найти полный модуль, при неудаче последний сегмент как объявление» не применяется.
Конфликты импорта
Импорты с одинаковыми именами вызывают ошибку, без тихого перезаписывания:
Конфликт имени `Point`:
math.geometry.Point
graphics.geometry.Point
Пожалуйста, используйте выборочный импорт или псевдоним пространства имён модуля.3. Видимость
Правила
Пакет — единственная граница инкапсуляции. Модули не несут границ прав доступа.
| Запись | В текущем пакете | В другом пакете |
|---|---|---|
По умолчанию (нет pub) | ✅ | ❌ |
pub | ✅ | ✅ |
Одно правило для всех объявлений верхнего уровня: типы, функции, константы, методы.
Устраняем четыре набора исключений из существующего кода:
Определения типов всегда экспортируются→ единое правилоКонстанты экспортируются автоматически→ единое правилоМетоды экспортируются автоматически→ единое правилоТолько функции проверяют→ единое правилоpub
Структуры данных
Заменяем is_pub: bool в AST на:
pub enum Visibility {
Package, // По умолчанию: видимо в текущем пакете
Public, // pub: видимо во всех пакетах
}Таблица экспортов
Каждый модуль поддерживает две таблицы:
- PackageSymbols: полная таблица символов пакета, содержит все объявления верхнего уровня
- PublicExports: подмножество объявлений
pubдля предоставления другим пакетам
Однопакетный use запрашивает PackageSymbols; межпакетный use может запрашивать только PublicExports.
Перекрёстная ссылка на необъявленное pub вызывает ошибку:
`internalHelper` модуля `math.geometry` невидим.
Это не объявление pub, доступно только внутри пакета `math`.4. Процесс компиляции проекта
Компиляционный конвейер
Входная точка проекта
→ Чтение yaoxiang.toml для получения точки входа
→ Рекурсивный разбор операторов use из точки входа, обнаружение всех зависимых модулей
→ Построение графа зависимостей модулей (ModuleDependencyGraph)
→ Обнаружение циклических зависимостей
→ Топологическая сортировка
→ Последовательное выполнение для каждого модуля: лексический анализ → синтаксический анализ → извлечение экспортов
→ Построение ModuleRegistry (содержит таблицы экспортов всех модулей)
→ Последовательная проверка типов каждого модуля в топологическом порядке (запрос ModuleRegistry)
→ Генерация нескольких ModuleIR
→ Агрегация диагностикиПроверщик типов только запрашивает предварительно построенный ModuleRegistry, не выполняет загрузку файлов, не обращается к диску.
Выбор входной точки
Приоритет:
[run].main(если существует)[[bin]]первый элементpath[lib].pathsrc/main.yx(соглашение по умолчанию)
Однофайловый режим не требует yaoxiang.toml, компилирует указанный файл напрямую.
Циклические зависимости
Обнаружена циклическая зависимость:
math.geometry → math.transform → math.geometryЦиклическая зависимость — ошибка компиляции, специальная обработка не применяется.
Агрегация ошибок
Ошибки мног файловой компиляции агрегируются в порядке топологической сортировки модулей. Каждая ошибка помечается исходным модулем и позицией в файле:
Ошибка в модуле `math.geometry`:
src/math/geometry.yx:12:5
Тип `Circle` не определён
Ошибка в модуле `app.main`:
src/main.yx:3:1
Модуль `math.geometry` невидим5. Изменения компилятора
| Компонент | Изменение |
|---|---|
compiler.rs | Добавлен метод compile_project(project_root) |
pipeline.rs | Сохранение ответственности за одномодульную компиляцию, не становится божественным объектом |
typecheck/checker.rs | Операторы use запрашивают ModuleRegistry, не вызывают загрузку файлов |
typecheck/inference/statements.rs | Аналогично, process_use_stmt только запрашивает, не загружает |
frontend/module/resolver.rs | Объединение поддержки YXPATH из package/source/module_resolver.rs, становится единственным разрешителем |
frontend/module/loader.rs | Расширение: поддержка рекурсивного обнаружения, построение полного графа модулей |
frontend/module/dep_graph.rs | Уже реализовано, повторное использование топологической сортировки и обнаружения циклов |
frontend/module/registry.rs | Уже реализовано, повторное использование запросов таблицы экспортов |
frontend/module/cache.rs | Уже реализовано, в этом RFC не подключается к компиляционному конвейеру |
frontend/module/hot_reload.rs | Уже реализовано, в этом RFC не подключается к компиляционному конвейеру |
AST is_pub: bool | Заменён на перечисление Visibility |
package/source/module_resolver.rs | Удалён, функциональность объединена в frontend/module/resolver.rs |
Стратегия реализации
Разделение на фазы
Фаза 1: Унификация разрешения модулей
- Объединение двух
ModuleResolver, удалениеpackage/source/module_resolver.rs - Поддержка переменной окружения
YXPATH - Обнаружение неоднозначности пути модуля
Фаза 2: Структуры данных видимости
- AST
is_pub: bool→ перечислениеVisibility - Разрешитель поддерживает маппинг ключевого слова
pubнаVisibility::Public ModuleLoader::extract_exportsунифицированно используетVisibilityдля определения экспорта
Фаза 3: Входная точка компиляции проекта
- В
compiler.rsдобавлен методcompile_project(project_root) - Рекурсивное обнаружение модулей из входной точки, построение
ModuleDependencyGraph - Топологическая сортировка, последовательная загрузка модулей и извлечение экспортов
- Построение полного
ModuleRegistry - Последовательная проверка типов каждого модуля в топологическом порядке
- Генерация нескольких
ModuleIR, агрегация диагностики
Фаза 4: Синтаксис импорта
- Реализация синтаксиса
use path.{item as alias} - Устранение fallback-предположения для конца пути
Зависимости
- RFC-014 (менеджер пакетов) — имя из
yaoxiang.toml, структура директории vendor - RFC-011 (обобщённая система типов) — trait — структурированный тип, не затрагивает принадлежность модулю
- RFC-009 (модель владения) — импорт модуля — это разрешение имён на этапе компиляции, не затрагивает копирование ссылок во время выполнения
Планирование под-RFC
Следующие под-RFC в предварительном планировании, ещё не начата подготовка черновиков:
| Под-RFC | Ожидаемая функциональность | Ожидаемые предпосылки |
|---|---|---|
| 029a | Кэширование модулей и инкрементная перекомпиляция | Граф модулей и таблицы экспортов стабильны |
| 029b | Отслеживание файлов и горячая перезагрузка | Механизм аннулирования кэша из 029a |
| 029c | Реэкспорт (pub use) | Таблицы экспортов и правила видимости реализованы |
| 029d | CLI параметр --entry переопределение выбора точки входа | Входная точка компиляции проекта доступна |
| 029e | Формат вывода --json мног файловой диагностики | Механизм агрегации диагностики доступен |
| — | pub(package) видимость модуля частная | Нет реальной потребности, пока не включено |
| — | Компиляция нескольких пакетов в рабочем пространстве | Несётся в RFC-014c |
Ссылки
- RFC-009: Модель владения — семантика Move, импорт — это разрешение имён на этапе компиляции
- RFC-011: Обобщённая система типов — структурированные определения типов
- RFC-014: Проектирование системы управления пакетами — источник имён пакетов, директория vendor
- RFC-015: Система конфигурации — определение полей
yaoxiang.toml
