类型系统总纲

本文档作为 Dujie 类型系统的总纲,面向语言设计者和编译器开发者。

它的目标不是一次性定完所有细节,而是先建立统一的讨论边界、术语和问题拆分方式。后续涉及 anyopt<T>、类型推导、类型转换、拷贝语义等问题时,都应以本文为入口,再拆分到专题设计文档。

泛型相关问题不在本文中深入展开。本文只在必要处说明“类型系统与泛型系统的边界”,具体的泛型参数、约束、推导和实例化规则,后续统一放到独立文档中讨论。

语言目标

当前将 Dujie 定位为:

  • 只用于描述 UI 的 DSL 语言
  • 当前不实现响应式系统,但不封死未来扩展空间

这个目标直接约束类型系统的取舍:

  • 优先保障组件描述、状态表达、属性传递和局部转换的易用性
  • 优先支持文本、数值、布尔、容器、可选值和组件类型
  • 不以通用系统编程语言为目标
  • 不以底层二进制处理能力为核心目标

设计目标

提供稳定、可预测的静态类型检查

让常见 UI DSL 场景写法足够简洁

控制隐式规则数量,避免“看起来能写但解释不清”

将语言层面的类型规则与 Rust 后端实现细节分离

为后续泛型、约束和内建类型扩展保留空间

非目标

当前阶段不追求以下能力:

  • 复杂的全局 Hindley-Milner 式类型推导
  • 用户自定义子类型体系
  • 隐式自动装箱/拆箱
  • 依赖运行时反射完成常规类型检查
  • 由 Rust 实现细节直接反向决定语言语义
  • 面向底层二进制处理的完整原语集合

类型系统范围

本文讨论的类型系统范围包括:

  • 类型种类
  • 类型语法
  • 类型检查
  • 类型推导
  • 类型转换
  • 内建特殊类型的语言语义
  • 与泛型系统的边界

本文暂不直接规定:

  • 具体 CST / AST 节点长什么样
  • Rust 代码生成的最终映射方式
  • 标准库 API 的完整清单
  • 泛型系统的完整规则

这些内容可以被本文约束,但不应反过来主导本文。

基本立场

1. Dujie 是静态类型语言

变量、表达式、函数参数、函数返回值、结构体字段都应在编译期拥有明确类型。

2. 类型规则优先于运行时实现

例如某个类型最终映射为 Rust 的 Arc<T>Vec<T>Option<T>Box<dyn Any>,这是实现策略,不应直接替代语言语义定义。

3. 显式优先于隐式

除非有非常强的收益和非常低的歧义,否则类型变化应通过显式语法表达。当前可暂时接受的隐式行为,只应限于明确、局部且容易解释的规则,例如 T -> opt<T> 的局部提升。

4. 绑定可变性与类型身份分离

let / var 首先描述绑定是否允许重新赋值,不应混同为“变量所属类型是否会变化”的另一套机制。变量一旦完成类型确定,后续赋值必须与该类型兼容。

类型分类

当前讨论中,Dujie 的类型至少可分为以下几类:

1. 基础类型

  • int
  • float
  • bool
  • rune
  • string

当前阶段只保留一个公开整数类型:int

当前不把 byte 作为核心基础类型纳入默认类型系统范围。原因是 Dujie 的目标是 UI 描述和状态建模,而不是原始二进制处理语言。

2. 参数化容器类型

  • list<T>
  • map<K, V>
  • opt<T>
  • iter<T>

本文后续将这组类型统称为“容器类型”。

3. 名义类型

  • struct

结构体属于语言层的命名类型系统,不应只被视为某种容器的语法糖。 它可以包含其他值,但不归入这里的“容器类型”。

4. 领域特殊类型

  • widget

widget 是为 UI DSL 提供的内建领域类型,需要与普通数据类型区分看待。

5. 边界类型

  • any

any 的职责、边界和允许出现的位置需要单独收敛,不应草率地把它当成“万能类型”。

当前不优先引入的类型

byte

在当前语言目标下,byte 不是优先类型。

原因:

  • UI DSL 的主数据模型不是字节流,而是文本、状态、属性和组件树
  • 即使未来引入响应式能力,其核心问题仍然不是字节运算
  • 过早引入 byte 会扩张数值类型设计、转换规则和容器语义

如果未来出现明确的二进制场景,例如资源加载、编码处理、哈希或网络协议边界,再单独讨论是否需要:

  • byte
  • bytes
  • 或更高层的二进制抽象类型

与泛型系统的边界

类型系统总纲需要承认泛型系统会存在,但不在这里深入定义其完整机制。

当前只约定以下边界:

  • 本文可以讨论“哪些类型位置未来允许出现类型参数”
  • 本文可以讨论“某类能力要求是否存在”
  • 本文不展开泛型参数声明语法
  • 本文不展开约束系统的完整定义
  • 本文不展开泛型实参推导和实例化规则

例如:

  • list<T>map<K, V>opt<T>iter<T> 这类参数化类型,会在本文中作为类型构造器讨论
  • T: ... 这样的约束语法,以及 key 这类约束的正式定义,放入独立的泛型系统文档

语义层面需要分离的几个概念

当前文档中有一些概念容易混在一起,后续必须拆开定义:

1. 类型类别 vs 运行时表示

“这是 list<T>” 与 “底层是否共享内存” 不是同一个问题。

2. 类型相等性 vs 类型兼容性

需要区分:

  • 两个类型是否完全相同
  • 某个值是否允许赋给某个目标类型
  • 某个类型是否满足某个约束

3. 类型系统规则 vs API 设计

例如 scores["a"] 缺失键时返回什么,既涉及类型,也涉及容器 API 设计。两者要分层处理,不能只靠示例暗示。

4. 用户可见语义 vs 实现优化

比如“拷贝是否共享底层数据”如果要成为语言承诺,就必须写成正式语义;如果只是实现优化,就不应在用户文档里作为核心分类反复出现。

当前建议的总方向

在细节未完全收敛前,类型系统总方向先按以下原则推进:

以静态、显式、局部可推导为主

以名义类型和参数化类型为主,不引入复杂子类型体系

any 视为边界能力,而不是常规建模手段

将类型推导限制在易解释的局部上下文中

将“值/引用/共享/可变”等问题作为独立语义层处理,而不是先塞进类型名义体系

专题拆分与当前状态

当前总纲只保留稳定边界和术语,不再重复专题细则。

已经有明确专题承接的内容:

值语义与共享语义:见 11.value-and-sharing-semantics

函数参数、opt<T>、默认值和调用规则:见 12.functions-and-calls

字面量、表达式、语句、类型推导边界、iter<T>panic 和语言级错误模型:见 13.expressions-and-statements

模块、导入导出、路径规则和入口约束:见 14.module-system

widget、组件函数和渲染内建边界:见 15.render-intrinsics

any 的定位、is 收窄和动态边界:见 16.any-design

泛型系统:见 10.generics-system

仍然值得继续单开文档细化的议题:

  1. 类型转换与标准库格式化/解析的分层

泛型相关内容继续独立处理,不并入本总纲。

与现有文档的关系

  • 00.guide/03.data-types 目前主要是面向使用者的说明,不是最终的设计依据
  • 01.design/06.struct-design 当前只覆盖结构体的一部分实现思路,不能替代整体类型系统设计
  • 01.design/07.comparable-constraint 是历史设计记录,不能替代当前的泛型约束设计
  • 01.design/12.functions-and-calls 收敛函数参数、默认值和调用规则
  • 01.design/13.expressions-and-statements 收敛字面量、控制流、运算、推导边界和语言级错误模型
  • 01.design/14.module-system 收敛模块、导入导出、路径规则和入口约束
  • 01.design/15.render-intrinsics 收敛 widget、组件函数和渲染内建边界
  • 01.design/16.any-design 收敛 any 的定位、边界和显式收窄规则

当前结论

当前阶段的工作方式保持不变:

类型系统问题优先在 01.design 收敛

09.type-system 只负责总纲、术语和专题边界

具体规则优先写入对应专题文档

不直接把当前 00.guide 的描述视为已经定案

每收敛一个专题,再决定是否同步修改 00.guide