# 开发者变更记录
> 内部实现细节、重构、测试、CI;用户可见功能见 `CHANGELOG.md`。
## 0.6.2 (2026-08-05)
### 基于 span 的诊断(L3)
- **结构改造**:`enum Ty` → `struct Ty { span: Span, kind: TyKind }`(变体级 span
被否决——"span 放 Ty 层,不放 TyNum");`TyKind` 以普通方法承载右操作数分发
(`TyKind::apply` / `TyKind::apply_help`),`trait Apply` 只留
`apply_help(self, o, span)`(bound 为 `Clone + Into<Ty>`——TyKind 无法满足
`Into<Ty>`,故用普通方法而非 trait);`Ty::apply` 取 span 后委托——span 贯穿
的唯一入口;
- **递归修复**:迁移时 `TyGroup::apply_help` 被改成"包回 Group 再 apply",
`o` 为普通类型时无限递归(fuzz `parse_no_panic` / `full_pipeline_no_panic`
栈溢出);改回 `self.0.apply(o)`(组的透明性)。fuzz 抓到了它——no-panic
承诺的价值所在;
- **诊断层**:`compile_error_str(msg, span)`;ident-span 方案——
`Ident::new("compile_error", span)` + `quote!`(括号/字符串/分号保持
call-site),因为 `quote_spanned!(span => compile_error!(...))` 会让 rustc
把错误当作 item 位置的用户代码("macros that expand to items must be
delimited with braces...");新增 `compile_err_at!(span, ...)` 宏;
- **接线**:parse(cursor/op 的 span——`^` 缺操作数现在指向 `^`)、consts
(`@` 引用 span)、blanket 包装、where_process、entry、lib、codegen;
apply 错误用 `err_ty_at`(span 参数已由 `apply_help` 贯穿);
- **平台限制(已记录)**:属性宏输入 span——顶层 token 精确、组内 token
退化 call-site、`Err` 返回的错误显示在宏调用行。精确 span 只出现在
Ok 输出的 `Ty::Error` 路径(parse/apply)。这是 rustc 行为,宏侧无法修复;
- ui 快照经 TRYBUILD=overwrite 重新生成(span 变化移动了错误位置)。
### 按 receiver 种类的 `@all` 过滤(L1)
- `ReceiverFilter` 枚举(Ref / Value / Static)+ `AllMarkerSpec` 类型别名在
`helpers.rs`;`resolve_all_marker` 表新增 `all_ref_methods` /
`all_value_methods` / `all_static_methods`,`get_trait_item_names` 增加
receiver 过滤维度;
- syn 3 receiver API:`f.sig.receiver()` 返回 `Option<&Receiver>`,其
`kind: ReceiverKind` 为 `Value` / `Reference(..)` / `Typed(..)`
(syn 2 风格的 `receiver.reference` 字段已不存在——E0609 抓出,
改为匹配 `ReceiverKind`);
- 动机:blanket 的 by-value 委托语义模糊(展开时无法判定 Deref/移动能力);
`#blanket(@all_ref_methods)` 让用户只委托 `&self`/`&mut self` 方法、
by-value 方法保留 trait 默认实现;
- 测试:`receiver_kind_filters`(ref/mut/val/static 各被正确标记选中)+
`blanket_receiver_filter`(Box blanket 委托 `by_ref`、`by_val` 回落默认——
注意默认实现需要 `where Self: Sized`,因为默认方法里的 `self` receiver
要求它,E0277);
- 文档(zh-CN):tutorial 常量表 + architecture 的 `@all` 描述与指令表已更新;
英文镜像发布时补。
### `#blanket` 静态方法委托(F1,重构)
- 评测员报告:`#blanket(@all_static_methods)` 生成 `(**self).make()` —
E0424(关联函数没有 `self`)。blanket 的既有漏洞(委托体总引用 self),
被 L1 静态过滤暴露;
- 第一版修复:守卫 + 指向 `#fill(@all_static_methods)` 的报错(评测员方案 A);
- 设计评审后重构:委托严格更优——静态方法没有可 deref 的 receiver,但
blanket impl 携带 `t: Trait`,`t::make(...)` 与 `<t as Trait>::Item`
投影完全同构。`expand_blanket` 现在按 receiver 选择委托体:
`(#self_ty).#name(...)`(有 receiver)vs `#t::#name(...)`(无 receiver)。
dsl 测试 `blanket_static_delegation` 锁定直接、链式(`Box<Box<u8>>`)与
参数转发三种形态;临时 ui 报错 fixture 已删除。符合 blanket 哲学:
实例方法经 deref 转发、静态方法经 bound 转发——都是转发,不特判。
### 全英文化(注释、错误消息、文档)
- **范围**:`src/` 全部中文注释(`//`、`///`、`//!`,29 文件 ~356 处)与
`tests/`(28 .rs + 31 .stderr)译为英文;59 条 `compile_err!` /
`compile_error_str!` 消息全部翻译;消息中的 DSL 记号原样保留;
- **过程**:5 个并行子代理按模块分组(preprocess / parse+apply /
ast+codegen / entry+util+analyze+testing+lib / tests),每组带
"绝不改动代码逻辑"的硬规则;ui `.stderr` 快照经 `TRYBUILD=overwrite`
重新生成(56 文件)——权威消息文本以实际输出为准,快照从真实输出重写;
- **翻译后清理**:子代理嵌套列表引入的 clippy `doc list item without
indentation` 警告,把 doc 注释拍平为散文修复;
- **文档**:中文文档移入 `docs/zh-CN/`(冻结归档),英文版原地书写
(README / CHANGELOG 全量 19 版本条目翻译 / tutorial 816 行 40 个 rust
块逐字保留 / architecture / dev-changelog);二次扫描翻译了 doc 代码块
**内部**的中文注释(仅 rust 块的 `//` 注释,代码 token 不动);
- **损坏围栏修复**:tutorial 段级 `@trait` 示例的围栏损坏
(`` `ust `` — backtick + CR + `ust`),修成 ```rust 后作为 doctest
编译通过;块内容与通过的 `tests/dsl.rs` 段级测试一致,安全;
- **验证**:fmt 干净、clippy 零警告、`cargo test --all-targets` 全绿
(lib 10 / dsl 46 / regression 26 / ui 全部 fixture)、doctest 46
(原 45,+1 修复块)、`src/`、`tests/` 与全部英文 doc 中文零残留。
## 0.6.1 (2026-08-05)
### 递归深度护栏恢复(0.1 承诺的回归修复)
- 复盘发现 0.1.0 的「递归深度限制(128 层)」在 0.3.0 重写时丢失:实测 30000 层
`[[[...]]]` 与 `Vec<Vec<...>>` 嵌套导致 `STATUS_STACK_OVERFLOW`(abort 非 panic,
fuzz 深度 3 测不出);
- 恢复:`angle_collect` 拆出 `angle_collect_at(tokens, depth)`,4 处递归点
(None 组扁平化 / Paren / Bracket / `<>` 内容)depth+1,`MAX_NEST_DEPTH = 128`
超限报「嵌套深度超过 128 层」——入口拦截后下游 consts/expand_tokens/parse/
codegen 的组深度全部 ≤ 128;
- 附带:`parse_primitive` 连续 body/where 附着(`T{a}{b}`)从递归改**迭代**
(attaches 栈收集 + 从内到外 apply)——线性链本不该递归,消除该递归源;
- 边界澄清:>128 层被宏内拦截;**数万层 `[` 嵌套的崩溃发生在 rustc tokenize
阶段**(宏被调用前,任何 proc-macro 库无法拦截的外部边界)——128 层远低于
rustc 阈值,合法输入永不触发;
- 测试:ui fixture `deep_nesting.rs`(200 层 `[`)+ angle 单测
`angle_nesting_limit`(129 层组)。
### 文档修正:`batch_trait!` 指令缺口如实声明(不改代码)
- 实测确认 `expand_tokens` 仅 `expand_attr_macro` 调用——`batch_trait!` 从未做
指令展开,`#fill` 等直接报 `found '#'`;而 lib.rs:111 / tutorial.md 原声称
"与 `#[batch_impl]` 相同语法"(虚假承诺);
- 决策:**不改代码**——`batch_trait!` 保持函数式宏纯 spec 语义(加入 trait
定义是 `#[batch_impl]`/`#[batch_impl_only]` 的职责);run_pipeline 的
`start_trait`/`trait_bounds` 参数已预留,未来若扩展语法可直接接入;
- 修正 lib.rs `batch_trait!` doc + tutorial.md 对应章节:`:` 右侧为类型 DSL +
`@` 常量,`#` 指令需属性宏入口;CHANGELOG 0.6.1 条目同步。
- 与 0.5.6(`A<>` 透传)/ 0.5.7(bound 不继承)限制同源:指令域依赖 trait
定义,仅属性宏入口可用。
### 模块重组:文件夹 mod + 文件(消除"平"结构)
- 根下 10 个平文件收编为分层目录,每目录 `mod.rs` 聚合 re-export
(引用侧统一写目录级 `crate::xxx::X`,不写子模块路径):
- `entry/`:入口与驱动(原 `expand.rs` → `mod.rs`、`batch_trait_entry.rs` →
`driver.rs`、`path_prefix.rs` 收编);
- `preprocess/`:token 重写器(原根下 `consts.rs`、`empty_generics.rs` 移入,
`preprocess_helpers.rs` 更名 `helpers.rs`);
- `analyze/`:trait 定义语义分析(原 `trait_bounds.rs` 移入);
- `util/`:共享工具(原 `scan.rs` / `diagnostic.rs` 移入,mod.rs 聚合);
- `testing/`:测试基建(原 `fuzz.rs` 移入,`cfg(test)`)。
- `parse/` `apply/` `ast/` `codegen/` 四层不动;lib.rs 仅剩宏声明 + 模块树。
- 依赖方向单向:util → ast → parse/apply → preprocess/analyze → codegen →
entry → lib。
### 逻辑合并(D 阶段,去重而非删注释)
- `trait_bounds::generic_param_names`:blanket.rs / empty_generics.rs 的泛型
参数名收集循环收敛为共享函数;
- `parse::parse_binary_chain`:`-`(左结合)与 `^`(右结合)两分支骨架同构,
收敛为参数化函数(错误消息保留 `(如 T-U)` 示例后缀,ui 快照不变);
- `types_render::render_param` / `render_optional`:codegen impl 泛型渲染复用
单条声明渲染;WithPrefix/WithAttr/WithCode/WithWhere 四臂双态渲染收敛;
- `apply_tuple` 两宏:WithTrait/WithType/WithCode/WithWhere 四类包装的
"透传到内层再重包" apply_help 宏化(教训:`self.1` 作宏参数会因调用处
hygiene 解析为模块 self——E0424,字段访问必须写在宏体内);
- `fuzz::full_pipeline_no_panic` 改走真实入口 `expand_attr_macro`(此前手写
管线漏掉常量展开与 `A<>` 照抄,fuzz 覆盖路径与线上不一致);
`expand_attr_macro` 改收 proc_macro2 类型使单元测试可调,lib.rs 入口转换;
- 放弃三项(有理由):路径收集统一(path_prefix 严格状态机 vs 段循环宽松
收集,统一会劣化诊断)、expand_wrapped/expand_rebuild 合一(需引入
expect 违反"永不 panic")、consts 换 scan_stop(无重复可换)。
### 评测修复(评测员 B1-B4 + 补充测试)
- **B1(真 bug,一行)**:codegen/mod.rs 的 @trait 分支写 id == "Trait"
(大写)——普通 where 谓词(where{@0: @trait<T>})的 @trait 被错误拒绝、
错误消息自相矛盾;全库其余 4 处均小写。**教训**:dev-changelog 此前声称
"resolve_where_at 同步小写"实际未替换——PowerShell Select-String 大小写
不敏感的反噬(残留检查误报通过)。测试:dsl
eview_fixes_locked
(B1 场景 + 自引用 bound 需补 impl WhereAtTrait<u32> for u32)。
- **B2(回归隐患)**:新顺序(@ 先于 <> 配对)下 expand_consts 运行时
真实 None 组(宏变量 $(...)*/$x:ty 展开产物)尚未被 angle_collect
扁平化——组内 @ 不再展开(0.6.0 顺序可以);原注释"真实 None 组已由
angle_collect 在入口扁平化,此处永远不会出现"在新顺序下不成立。修复:
expand_consts 加 delimiter![none] 分支——新顺序下 <> 组尚未存在,
None 组必是真实透明组,无旧歧义(0.6.0 曾踩过的 delimiter![none] 误伤
尖括号组问题不复存在)。测试:dsl
eview_fixes_locked(宏变量 + 组内
@uint 探针实测,2024 edition 下 gen 是保留字、宏名须换)。
- **B3(文档)**:@all_default_types 依赖 trait 关联类型默认值
( ype T = u8;)——nightly(ssociated_type_defaults,stable 报
E0658)——tutorial 标注该标记仅 nightly 场景可用(@all_required_types
的 ype T; 声明 stable 可用)。
- **B4(防御)**:atch_trait! 定义 @trait=[...] 常量会被特殊记号拦截、
被段级替换静默遮蔽——collect_user_consts 拒绝 rait 作常量名
("保留记号"报错)。
- 评测员补充测试 dsl 35 节 macro_meta_review_extras(正向路径全覆盖:
@all_required 全种类 / @all_default_constants / 标记减法 /
@trait<T> 顶层 spec / [a,b] 于 #delegate / blanket where 仅 @0 /
()^3 where{@2: Clone} 多参数位置引用)——全部通过。
### 宏元层完整化(0.6.1 主线:`@` 唯一宏元记号 + blanket 约束合并)
- 背景:用户提出「`#all` 看着不顺眼,违反 `#` 的两种格式」——`#` 应
只剩指令名;范围选择(选哪些 item)是宏元层操作,统一归 `@`;
- `@all` 系:try_expand_at 加分支(`resolve_all_marker` 抽公共表——指令域
与宏元层共用),展开为 Bracket 组(`render_list_strings`);batch_impl
专属(需 trait_def),batch_trait! 报错;`#all` 系全删(parse_marker 删除、
parse_name_tokens/parse_minus_target 的 `#` 分支删除);
- 指令参数支持 `[a,b]`(递归解析组内容;空组报错;`-` 排除支持
`-[a,b]`)——`@all` 展开产物即此形态,用户手写等价;
- trait 感知常量(ConstCtx::Attribute 携带 trait_def):`@trait` 展开本地
trait 名;`@Cow` 内置(`Cow<'_>` + 固有约束谓词——quote 不配对尖括号,
ty 须手动 `Group::new(delimiter![<>])`;与砍掉的裸类型名常量不同类:
携带约束才有复用价值);
- blanket 包装约束谓词:尾随 `where{...}`(在 `:N` 后)并入 impl where;
`resolve_target_predicates` 处理 `@0`(→ fresh T)与 `@trait`;
**教训**:`quote!(where { #(#wrapper_preds),* })` 会把每个 TokenTree 当
列表元素逗号连接——谓词流须整体插入;
- `<>` 只留名字:blanket 泛型声明 TypeParam 只取 ident、const/lifetime
原样(纯名字 `N` 会 E0747);`T: Trait` 进 where 基础谓词(与包装谓词
并列合并);trait 形参 inline bound 由 codegen 继承逻辑处理(曾转移导致
X: Clone 重复——继承按位置补 bound,见 `gen_where_probe` 实测);
- `@0` 通用化:codegen 渲染 where 谓词时替换 `@N`(→ impl 泛型第 N 位名字)与
`@trait`(→ trait 名)——元组 `()^2 where{@0: Clone}` 与普通 spec
`where{@0: Default}` 可用(此前仅 blanket 包装 where 特化:`@0` 恒指
目标泛型 fresh T,由 resolve_target_predicates 预替换,两处不冲突);
越界/格式错误并入 errs 收集报错(generate_impl 非 Result 返回);
测试 dsl `where_position_refs`。
- `@Trait` → `@trait` 改名 + 路径化:内置名族全小写统一(`@uint`/`@scalar`/…);
内容从「本地 trait 名」改为「trait 完整路径」——`batch_impl` = 本地名、
`batch_impl_only` = 外部路径(`#ext::Trait:` 前缀)——blanket 包装 where
写 `@0::Owned: @trait` 免手写路径;实现:路径前缀解析**提前**到 `@` 展开前
(`@trait` 需要 trait_full_path;ConstCtx::Attribute 加 trait_full_path 字段、
trait_full_path() 访问器);blanket 的 resolve_target_predicates 改用
trait_full_path(原 trait_def.ident 只给本地名,外部场景错);codegen 的
resolve_where_at 同步小写;**教训**:PowerShell Select-String 大小写不敏感,
残留检查误报(实际已替换)。
- `batch_trait!` 段级 `@trait`:多段每段 trait 名不同,常量值(如
`@type_t=<T>@trait<T>`)里的 `@trait` 由 entry 分段循环逐段替换为本段
trait 路径(`replace_segment_trait`)——跨段复用「泛型声明+trait 名」打包;
实现要点:try_expand_at 改返回 `Option`——Trait ctx 的 `@trait` 返回
`None`(原样保留、不触发懒展开递归——展开为原样→再遇→栈溢出的死循环,
实测 STATUS_STACK_OVERFLOW);check_value_refs 跳过 `@trait`(特殊记号
非常量引用);测试 dsl `trait_const_segment`(教训:trait 定义须带泛型
匹配 spec 的 `<T> Trait<T>`;`Box^[T,(T,)]` 泛型重叠 E0119 是用户写法
问题,测试改用 `[T, Vec<T>]`)。
- 测试:dsl `macro_meta_complete`(@trait/@Cow/blanket where/[a,b]/where
规范)、`trait_const_value_with_angles` 保持;全量回归绿。
### 预处理顺序修正:`@ <> # where`
- 背景:用户提议宏元层(`@`)应是最外一趟。实测当前顺序(`<> @ #`)
的 bug:`batch_trait!( @inner = Vec<u8>; @outer = Vec<@inner>; ... )`
——`Vec<@inner>` 的 `@inner` 被 angle_collect 配对进尖括号组,而
expand_consts 刻意不进入 `<>` 组(`delimiter![<>]` 与真实 None 组
展开值相同不可同臂,注释已记录)——`@` 残留报 `found '@'`;
直接值 `@map = HashMap<u32, String>` 恰好因定义处配对兜底不炸,
嵌套/引用场景暴露;
- 修正:entry 两入口把 `collect_user_consts` + `expand_consts` 移到
`angle_collect` 之前——`@` 展开产物(可能含扁平 `<...>`)统一由
后续 angle_collect 配对;`#` 指令与裸 where 改写位置不变;
- 能力矩阵:batch_impl/only = 内置 `@` + `<>` + `#` + where;
batch_trait! = 自定义 `@` + `<>` + where;
- 测试:dsl `trait_const_value_with_angles`(`@map` 直接值 + `@outer`
嵌套值;E0252 教训——dsl.rs 已 use HashMap;E0119 教训——batch_trait!
自身生成 impl,勿手写重复)。
### 新范围标记:`@all_required*` / `@all_default*`
- 背景:`@all` 系一直未区分 trait item 的默认实现状态(`#fill(@all)` 连有
默认实现的也覆盖,`@all + -name` 逐个排除繁琐);用户提出按状态过滤;
- 实现:`get_trait_item_names` 加 `default: Option<bool>` 过滤参数
(`Some(true)` 仅默认、`Some(false)` 仅 required、`None` 全含),
syn 判断字段:`TraitItem::Fn(f).default` / `Const(c).default` /
`Type(t).default`(fn=默认体、const=默认值、type=默认类型);
- `parse_marker` 改表格分发(kinds, default)——12 个标记内联,删除
`get_all_trait_methods/items/constants/types` 四个薄 wrapper;
- 语义要点:`@all_required*` 单独用完整(只填必须的、默认保留);`@all_default*`
单独用缺 required → E0046,须与 required 侧/手写组合;required ∪ default = all;
- 测试:dsl `all_default_required_markers`(fill 组合 / fill 只 required /
blanket 只 required 三场景;E0034 教训:三个 trait 须各占一个整数类型);
- 三指令(fill/delegate/blanket)共享 `parse_names_from_tokens`,一处改全部获得。
### 旧测试用例抽查(git 历史)——发现并修复 `T^<A,B>` 参数丢失
- 对照 v0.5.0 删除的 examples/{tests,ds_tests,my_tests,debug_tests}.rs
(~4800 行)与当前 dsl/regression 测试矩阵,4 个候选盲区实测:
- `[&, self]^[u32, i64]`(前缀混合列表叉积)、
`()-[usize, isize]-[u32, i32]`(空元组双列表减法链)——行为正确,已覆盖;
- `HashMap^<u32, String>`(caret 后跟泛型参数列表)——**真 bug**;
- `[usize #fill(@all){..}, isize #fill(@all){..}]`(列表元素独立指令)——
与 dsl `directive_fill` 重叠,未单独补。
- **bug 根因**:parse_primary 顺序缺陷——单个 `Group(<>)` 输入在
`[TokenTree::Group] → parse_group` 分支被抢先拦截,parse_group 不认
`<>` 组落 `_ => empty()`,而 `parse_type_params`(本应处理 `<A,B>` 独立
操作数)永远到不了;带 body 时 empty 被 `TyWithCode` 包裹后逃过
`is_empty_operand` 检查 → `<u32, String>` 静默丢失、输出裸 `HashMap`,
无任何诊断(不带 body 则报"`^` 后缺少操作数",行为分裂);
- **修复**:`[Group] → parse_group` 分支排除 `delimiter![<>]`,尖括号组
落到 parse_type_params——按 apply/mod.rs 注释既定语义
`T^<A,B> => T<A,B>`(`HashMap^<u32, String>` → `HashMap<u32, String>`);
- 测试:regression `caret_angle_param_list`(`contains_key` 断言 impl 落在
泛型完整类型上,防退化为裸 `HashMap`)。
## 0.6.0 (2026-08-04)
### 新特性:`@` 常量系统(src/consts.rs)
- 内置名字族(`@uint`/`@int`/`@float`/`@num`/`@scalar`)+ 范围族
(`@u8..u128` 等,含端点、宽度/族/顺序校验),展开为 Bracket 列表与
手写等价,走原管线(宏元层只做词法替换,不参与域内解析)
- `batch_trait!` 前导 `@name=值;` 定义段(`collect_user_consts`):**懒展开**
——值任意 token 原样入库,引用处拼接后递归展开(`expand_consts` 引用分支
先递归再 extend);`check_value_refs` 定义处校验引用可见性(循环/前向
引用拦截——懒展开下 `@a=@a` 会无限递归)
- 引用替换(`expand_consts`)递归进入 `Paren`/`Bracket`、透传 Brace 与
`ident![...]`/`#[...]`(复用 `bracket_is_passthrough`)
- 管线位置:`angle_collect` 之后、指令预处理之前(两个入口各插一次;
`batch_trait!` 在 `where_process` 之前)
- 教训×2:`expand_consts` 初版误加 `delimiter![none]` 分支把尖括号组
(同值)当真实 None 组扁平化,已删;懒展开后值形态校验取消(B1/B2 的
定义处拒绝语义被引用处 DSL 报错取代,评审认可)
### 新特性:`#blanket` 覆盖式委托
- `expand_directive` 返回类型 `TokenTree` → `Vec<TokenTree>`(指令可产出
多 token;既有五种指令在分发处包 `vec!`,内部零改动)
- `expand_blanket`:**包装元素普适化**(任意类型表达式 + 可选尾 `:N` 深度
标注,`parse_blanket_wrappers` 返回 `BlanketWrapper { ty, depth }`;
`is_single_colon` 区分 `::` 路径)、fresh 泛型、逐包装生成
`<T: Trait> 包装^T { 委托体 }` 多段 spec
- 委托体 `*` 数量 = depth + 1(`"*".repeat(depth + 1) + "self"` parse);
目标类型 = 包装 `^T`(`Box^Arc:2` → `Box<Arc<T>>`、`Cow<'_>` → `Cow<'_, T>`)
- **泛型 trait**:trait 形参照抄为 impl 泛型(形参在前、fresh `T` 在后,
`T: Trait<X>` 反序 E0401)+ trait 实参填参数名 + where 谓词透传;
spec 的 trait 名部分仅泛型时输出(非泛型省略——`Trait &^T` 前缀目标
跟在 trait 名后无法解析,回归曾破坏 `{&,Box,Rc}`)
- **assoc type/const 委托**:`TraitItem::Fn` 窄匹配放开,Type/Const 走
`build_from_item` 既有输出形态,body 用 `<T as Trait<X>>::name` 投影
- 关键修复×2:blanket 在 `angle_collect` 之后运行——泛型声明手动构造尖括号组
(`Group::new(delimiter![<>], ...)`);body 是 Brace 组(angle_collect 不进入),
其内 `Cow<'_>` 等扁平 `<...>` 补一次 `angle_collect` 配对
- 坑:`quote!(#tp.ident)` 字段访问插值(`.ident` 当字面量),先取引用再插值
- 边界:`*const`/`*mut` / `self` / 空元素 / 非法 `:N` 报错引导手写
`#delegate`;默认 depth 1(宏不猜 Deref 层数);by-value receiver 放行
(Deref/move 语义信息不对称,rustc 兜底)
### 测试与文档
- dsl 第 35/36 节(const 系统、blanket 双属性叠加);ui 新增 fixture
(const_unknown / const_range_bad / blanket_ptr / blanket_bad_depth;
blanket_generic 随泛型 trait 支持移除;const_cycle / const_forward 见评审修复节)
- architecture.md:模块图加 consts.rs、管线更新(const 展开、多 token 指令)、
域隔离表格宏元层落地、新增「附着语义」章节
- tutorial.md:第 7 章 `#blanket` 小节、第 11 章 `@` 常量小节
### 评审修复(发布前)
- **F1**:`cargo +nightly fmt` 修复 consts.rs / preprocess/mod.rs 格式差异
- **F2**:dsl.rs `BlanketInc` dead_code(clippy -D warnings 阻断)——`b.inc()`
走 Deref 到 u16 自身 impl、blanket `&mut` impl 从未被调用;测试改为 UFCS
直接测 blanket 委托路径(`&mut u16` 同时命中两个 impl 需消歧)
- **F3**:`@name=值;` 定义段写在 trait 段之后时,`try_expand_at` 定义段分支
按上下文区分诊断——batch_trait! 报「常量定义必须位于所有 trait 段之前」,
batch_impl/batch_impl_only 保留「不支持自定义常量」
- **F4**:blanket 泛型 bound `T: Trait<X>` 的实参扁平 `<A, B>` 会被
`split_at_depth0` 在逗号处错误切分(`T: Two<A` / `B>`),初版靠渲染幂等
侥幸正确(脆点);修复为**实参组化**(`t_bound` 与 `trait_part` 同款
`Group::new(delimiter![<>], ...)`),解析即正确不依赖幂等;dsl 38 的
`Two<A, B>` 用例回归锁定;parse/generic.rs 注释改为「组内宏生成尖括号
必须预配对」的通用警告
- **B1**:`collect_user_consts` 的 `@` 引用值校验 `consumed == value.len()`
——`@a=@num garbage` 报"引用后有多余 token",不再静默丢弃尾随内容
(**已被懒展开取代**:值形态放开为任意 token,见本版本新特性节)
- **B2**:常量**列表**值内嵌 `@`(`[@uint, u16]`)在定义处拒绝——接受但不
展开会推迟到使用处才报错(诊断远离源头);列表是原子值,请用 `@name` 形态
(**已被懒展开取代**:列表值内嵌引用现在正常展开,见 dsl 38)
- **B3**:`#blanket` 的委托 bound 改用 `trait_full_path`——`#[batch_impl_only
(#ext::Trait: ...)]` 路径前缀场景裸 dummy 名解析不到(E0412/E0277);
`expand_tokens`/`expand_directive`/`expand_blanket` 签名链加 `trait_full_path`
参数(fuzz 同步)
- **B4**:未知 `@` 常量诊断在 batch_trait! 场景追加"用户常量须在引用前定义"
(懒展开后由 `check_value_refs` 的定义处可见性校验接管,见新特性节)
- **B6**:`contains_at` 递归进所有组(`[Foo<@uint>]` 的 `@uint` 被 angle_collect
配对进 None 组,扁平检查会漏过)——**已被 `check_value_refs` 取代**(懒展开
后定义处统一做引用可见性校验,递归进所有组)
- 测试:regression 加路径前缀 + blanket pass 用例(`cmp_path_prefix_blanket`,
`&u8` 与 u8 自身 impl 的方法歧义用 UFCS 消歧);ui 加
const_cycle / const_forward 两个 fixture(循环/前向引用定义处报错)
### 文档体系重构(并入自原 0.5.8)
- README 重写为推销版(669 → 117 行):为什么用它 / 心智模型 / 快速开始 /
特性一览表 / 链接
- 教程独立 `docs/tutorial.md`(原语法参考 + 组合拳重排为 13 章渐进式,
lib.rs 增加 `#![doc = include_str!(docs/tutorial.md)]`,docs.rs 首页 =
推销 + 教程,教程代码块全部进 doctest)
- 开发者文档独立 `docs/architecture.md`(架构图、关键设计决策、错误机制、
测试矩阵、发布流程)
- CHANGELOG 拆分为用户版(CHANGELOG.md)与开发者版(本文件),0.1.0 →
最新全部历史条目分类迁移
- 注意:rustdoc 对无语言标注代码块默认按 rust 编译(`<impl-泛型>...` 骨架
需 `text` 标注)
## 0.5.7 (2026-08-03)
### `delimiter!` 分隔符拼写宏
- 定义于 `preprocess/mod.rs` 顶部(经 `#[macro_use]` 导入 crate 根),用源码
分隔符拼写统一取缔散落的 `Delimiter::*` 字面量,调用统一用 `[]` 定界
- `Delimiter::None` 两种语义用两种拼写区分:`delimiter![<>]`(尖括号组载体)
与 `delimiter![none]`(真实透明组);全库 43 处收敛
- 修 angle.rs 模块文档悬空的 `ANGLE_BRACKET` 引用
- proc-macro crate 禁止 `#[macro_export]`,宏无法定义在 `angle.rs` 并全
crate 可见,故置于父模块顶部(文本作用域要求声明先于所有使用者)
### Bracket 守卫对齐
- `expand_tokens` 与 `where_process` 的 Bracket 递归守卫补 `#`(此前仅排除
`ident![...]`,`#[...]` 属性内的 `#name{body}` 会被误当指令展开报错;
与 `angle_collect` 的属性守卫对齐)
### lib.rs 拆分(632 → 202 行)
- `expand.rs`:入口实现 + 公共管线 `run_pipeline`(解析 → 生成 → 尖括号组
还原;`angle_collect` 与裸 where 改写不进入管线——配对破坏性、where 须
先于 `A<>` 展开)
- `trait_bounds.rs`:TraitBounds + syn AST 引用收集
- `empty_generics.rs`:`A<>` 照抄展开
- `angle_tests` 迁入 `angle.rs`;`crate::TraitBounds` 路径经 `pub(crate) use`
保持兼容
- 错误机制分工说明:入口层 `Result` 传播 vs DSL 层 `Ty::Error` 透传;
`batch_trait!` 段级错误统一 `return Err`
### syn AST 引用收集(where 谓词)
- 新增 `syn` 的 `visit` feature:单段路径与泛型实参是形参引用位置;
`::` 后路径段(`A::B` 的 `B`)、关联类型绑定名(`dyn Trait<Item = T>`
的 `Item`)、HRTB binder(`for<'a>` 的 `'a`)天然排除——替换 `bound_refs`
的 token 扫描(顺带修掉内联 bound 的 HRTB 误报)
- 补 `visit_expr` 收集 const 泛型实参 / 数组长度(`[T; N]` 的 `N`,实测发现
漏报会静默生成引用未声明名字的代码);impl 泛型名 `const N` 归一如 `N`
- `TraitBounds.extra_predicates`:未合并谓词(token + 引用的形参名),
codegen 引用检查后附加到 impl where
### 其他
- CI:MSRV job 补 doctest(`--doc` 不能与其他选择项混用,拆两步)
- 测试:angle 单测(属性/宏体守卫、渲染嵌套组重建、span 保留不可测说明——
fallback 模式 `Span::mixed_site()` 即 call_site);regression 补
`batch_trait!` 的 `A<>` 透传;dsl 第 34 节覆盖矩阵;ui 新增
`rename_where.rs` / `where_const_ref.rs`;codegen 单测锁定 `WhereArr<>`
展开(防"测试过但 IDE 展开含 compile_error"的缓存类误报)
## 0.5.6 (2026-08-03)
### src 按层分目录
- 管线分层:`parse/`(解析器 + 原子层 + 泛型)、`preprocess/`(指令 + 辅助 +
裸 where + 尖括号组)、`ast/`(Ty 定义 + 渲染)、`apply/`(Apply trait +
元组容器)、`codegen/`;同名文件并入 `mod.rs`(消除
`module_has_same_name`),子模块经 `pub(crate) use` 重导出,外部路径不变
### 尖括号组预处理(angle.rs)
- proc-macro2 只对 `()`/`[]`/`{}` 分组,`<>` 是扁平 Punct——新增
`angle_collect` 在管线入口一趟扫描:真实 `None` 组扁平化 + 扁平 `<...>`
配对为 `None` 组(`->` 箭头不参与);`Paren`/`Bracket` 递归进入、
`Brace` 不进入(body 透传)、`ident![...]` 宏体 / `#[...]` 属性不进入
- `render_angles` 输出侧镜像(`None` 组 → `<...>` 扁平),重建 `Paren`/
`Bracket` 时保留原 span(修复 doc 属性 span 变 call_site 的 clippy 诊断
映射问题)
- 收尾:孤立 `<`/`>` 报错(解锁下游深度逻辑删除);`scan_with` /
`scan_body_boundary` / 路径扫描删除 `<>` 深度分支
- fuzz 全管线补 `angle_collect`
## 0.5.5 (2026-08-03)
### `A<>` 照抄实现
- `TraitBounds` 重写为位置结构(`TraitParam`: name / bound / refs)
- `bound_refs` 保守 token 级引用检测(宁可误报拒绝自动继承,绝不生成错代码)
- `expand_empty_trait_generics` 预处理扫描(深度 0 的 `Ident<>`,`->` 箭头守卫)
- 取代初版"生命周期按名匹配 + 退化为不继承":改名场景从静默退化升级为明确报错
## 0.5.4 (2026-08-03)
### `-name` 减法实现
- `parse_name_tokens` 重写为 keep/exclude 双列表 + `#` 标记展开
(`parse_marker` / `parse_minus_target` 辅助),`#except` 分支移除
### bound 继承实现
- `extract_trait_bounds` 从 trait generics 提取 name→bound 映射(Punctuated
经 ToTokens 渲染 `A + B`),经 `parse_batch_trait_entry` 传入
`generate_impl` 对 `(name, None)` 参数补 bound
- 修复 `quote!(#tp.bounds)` 陷阱:quote 插值不支持字段访问(会把 `.bounds`
当字面量),改用先取引用
### 其他
- 发布物冒烟验证(首次验证真实发布物可用)
- README 快速开始版本号修复(0.5.1 → 0.5.4,crates.io 版本不可变故重新发布)
## 0.5.3 (2026-08-02)
### 重构与内部实现
- **preprocess 返回类型收敛**:指令展开产物收敛为恰好一个 `{...}` 组 token
- **指令参数解析重构**:`parse_names_from_tokens` 的别扭写法(逗号编码成
`Err(None)`)改为普通迭代收集
- **fuzz 扩到全管线**:`full_pipeline_no_panic` 随机 token 流跑完整管线
- **`Apply` trait 重构**:右操作数"结构上下文"提前分发下沉为默认方法
(Array 分发 / Group 透明 / WithCode、WithWhere 透传 / WithType 外提 /
Range 展开 / Error 透传);移除 `TyArray` 不可达笛卡尔积分支与 `TyFn`
不可达 Group 分支;`trait Apply: Clone + Into<Ty>`(分发需复用左操作数)
- **`Ty::expand` 返回值改为显式枚举**:`enum Expand { Leaf, Many }`
(原 `Result<Vec<Ty>, Ty>` 以 `Err` 表示叶子的反直觉设计)
- **组合展开数量上限**:`MAX_EXPAND = 1024`,`tuple_pow` / `pow_cartesian`
(每轮产物数)/ `map_range` / `TyArray` 笛卡尔积分支校验,
`apply::check_expand_limit` 统一入口
- **数组链式展开产物上限**:`count_leaves` 叶子数校验
- **元组笛卡尔积 bound 修复**:`instantiate_combo` 误把参数名当 bound
(`(A: Clone, T)^N` 生成 `_Param: A`),改为保留真正的 bound
- **逻辑精简重构**(行为零变化):`Ty::expand` 包装样板抽为
`expand_wrapped` / `expand_rebuild`;指令展开骨架合并为 `expand_many`
- **文档漂移修复**:README 元组生成 u8 范围删除、测试矩阵计数更新、
补充 unsafe fn / `#except` / 操作数严格性说明
### 修复(内部)
- `#delegate` 参数转发加固:`collect_call_args` 对非标识符模式返回错误
- 空范围诊断:`map_range` 对空范围报错
- 尾随运算符静默吞段修复:Dash/Caret 分支空操作数报错
- 空操作数严格化:左空检查 + 前导/连续逗号在 3 个入口判定
- 指令参数逗号严格化
## 0.5.2 (2026-08-01)
### 测试与工程
- **解析器 fuzz 验证**:`src/fuzz.rs`(proptest)随机 token 喂
`where_process` / `parse_item`,断言不 panic
- **发布卫生**:`#![forbid(unsafe_code)]`、`#![deny(missing_docs)]`、
修复 Windows MSVC `linker_messages` 告警
- **CI**:GitHub Actions(fmt / clippy -D warnings / test / doc,
stable + MSRV 1.93 双工具链)
### 数组/切片 builder(`TyPrimitiveArray`)
- 合并 `TySlice` 与 `TyFixedArray` 为
`TyPrimitiveArray(Option<Box<Ty>>, Option<TokenStream>)`
- `()^N` fresh 泛型元组自动外提(`T^<A>X` => `<A>(T^X)`,嵌套 `WithType`
参数并入 impl 泛型)
- `TyNum` / `TyRange` 由 `u8` 改为 `usize`
## 0.5.1 (2026-07-31)
### where 支持实现
- `where{...}` 后缀:`TyWithWhere` / `TyWhere` 节点,codegen 合并到
impl 的 where 子句
- 裸 where 改写:新增 `where_process.rs`(指令预处理之后、DSL 解析之前),
边界判定排除 `ident!{...}` 宏调用体与尖括号内代码块
## 0.5.0 (2026-07-28)
### 工程
- `try_parse_path_prefix` 状态机(要求至少一个 `::`,避免 `#Display: ...`
歧义)
- `Spacing::Joint` 精确检查(`::`、`->`、`..` 防相邻不粘连标点误判)
- Range 处理集中化(`Apply for Ty` 外层 match 统一右侧 Range 展开)
- 模块级文档(`//!`)全量补齐
- 模块拆分:`scan.rs` / `parse_atom.rs` / `generic.rs` / `types_render.rs` /
`apply_tuple.rs` / `batch_trait_entry.rs` / `path_prefix.rs` /
`preprocess_helpers.rs`
## 0.4.2 (2026-07-27)
### 工程化重构
- `apply::trait Type` 重命名为 `trait Apply`
- `rustfmt.toml`(edition=2024、max_width=75 等),PR 要求
`cargo +nightly fmt --check`
- `src/diagnostic.rs`:唯一 `compile_error_str(msg)` 构造器(删除两份同名
实现,防诊断构造点漂移)
- `ScanMode { Lossy, Strict }` + 单一 `scan_with`(消除两份近似但行为不同的
`<>` 深度循环)
- `extract_impl_parts` 的 `WithType` 分支 append → prepend(
`<A>[<B>T1, <C>T2]` 现输出 `impl<A, B>` 与 `impl<A, C>`)
- 错误加固:`expand_tokens` 两处 `peek().unwrap()` 替换为 `let Some else`;
`tuple_pow` 单元素分支 `.unwrap()` 改带消息 `expect`
- 入口收敛:`extract_trait_path` / `extract_last_ident` 内联进 `batch_trait!`
- 测试体系:`tests/dsl.rs`(20 个)+ `tests/ui.rs`(8 fail + 1 pass,trybuild)
- 测试与示例重组:删除 examples 4 个测试文件(~4800 行),新增
`examples/quickstart.rs` + `tests/regression.rs`
### 其他
- `expand_delegate` 的 `todo!("error")` 替换为 `compile_error!`
- preprocess.rs 注释与 `get_trait_item` 错误信息更新
## 0.4.1 (2026-07-25)
- 修复自定义宏未携带 trait_def 问题
## 0.4.0 (2026-07-25)
### 指令系统实现
- 新增 `preprocess.rs`:指令预处理模块,仅递归展开 `[...]`(Bracket)Group
- `expand_tokens` / `expand_directive` 返回 `Result`,错误输出
`compile_error!` 而非 panic
- 全库零 `panic!` / `unreachable!`:AST 层 `Ty::Error` 变体经 ToTokens 输出;
预处理层 `parse_method_names_from_tokens` / `get_trait_method_sig` 返回
`Result`
- 指令扩展性:不认识的 `#name` 委托给 Rust 属性宏系统(0.5.3 改为函数式
宏调用)
- `examples/my_tests.rs`:36 项指令测试
## 0.3.0 (2026-07-24)
### 完全重写
- 从零开始重写,公开 API 与 DSL 语法与 v0.2.x 一致,内部与旧版无代码联系
- 架构:`lib.rs`(入口 + 共享驱动)/ `preprocess.rs` / `parse.rs` /
`types.rs` / `apply.rs` / `codegen.rs`
- 解析模型:`Cursor<'a>` 借用切片游标 + 优先级攀爬(`Semi` < `Comma` <
`Dash` < `Caret`),`scan_stop` 统一处理 `<>` 深度与 `->` 守卫;
任意 Rust 类型透传为 Primitive 节点
- AST 设计:`Ty` 枚举 20 个变体(叶子 / 包装 / 容器三类)
- 运算符语义:`Type` trait 的 `apply(self, o)`(`^` 右结合、`-` 左结合、
数组分发、元组生成)
- 测试:tests 95+ 项 / ds_tests 56+ 项全部通过,clippy 零警告
## 0.2.2 (2026-07-20)
### 修复与代码审查
- `fn^i32` 自动生成括号
- 统一 `->` 处理(`has_top_level_char` / `parse_balanced` /
`find_top_level_colon` / `split_at_punct` 排除 `->` 中的 `>`)
- P0:`split_raw` 检测多余 `>`;`parse_balanced` 详细错误("未闭合的 `<`(还有
N 层)")
- P1:`expand_nested_bracket` 注释(`unwrap_count - 1` 语义);
`generate_tuples` 返回 Result(笛卡尔积超限);`batch_trait!` 空路径检查
## 0.2.1 (2026-07-20)
### 修复(BUG-1/2/3 与优先级)
- BUG-1:`expand_caret` 右侧在第一个顶层 `-` 处分割(`^` 优先级高于 `-`)
- BUG-2:`parse_target_items` 丢弃 `<>` 之后内容(`parse_balanced` 的 pos 被
丢弃)
- BUG-3:`expand_single` 未过滤 Attribute/Unsafe 前缀(`unsafe^#[attr]^T`)
- fn 类型优先级:`fn^(u32,i32)-usize` 的 `-` 作为返回类型
- 嵌套 caret 保留 `Fn` 前缀
### Code Quality
- `ImplSpec::new()` 构造器;`expand_caret` 拆出
`expand_bracket_with_comma` / `expand_nested_bracket`;`dash_append` 拆出
fn 处理;`#![allow(linker_messages)]`
## 0.2.0 (2026-07-19)
### 实现细节
- `ImplSpec` 新增 `assoc_bindings` / `attributes` 字段
- `PrefixItem` 新增 `ConstPtr` / `MutPtr` / `Fn` / `Attribute` 变体
- `parse_segment` 解析 `TraitName<Item=T>` 时分离关联类型绑定
- 测试:macro-test 113 / ds-test 15 / 一致性 / 嵌套 / 并行
## 0.1.1 (2026-07-19)
### 实现细节
- `PrefixItem::Container` 增加 `prefill` 字段;`parse_single_prefix` 识别
`Ident<...>`;`apply_caret` 预填泛型追加;`append_to_generic_container`
- README 优先级说明;移除 Planned 部分
## 0.1.0 (2026-07-19)
### 初始发布
- 安全性:递归深度限制(128 层)、`byte_range()` 稳定位置后缀、
笛卡尔积组合数上限(1024)
- 错误处理:中文提示、保留原始 Span、`compile_error!` 而非 panic
- 测试:macro-test 99 / ds-test 15
## 项目演进史
> 每代一句话主线(正式版本):
> **0.1 发布** · **0.2 属性与前缀**(fn/指针/`#[attr]`/assoc)·
> **0.3 重写**(手动重建统一模型)· **0.4 指令系统**(`#fill`/`#delegate`/开放扩展)·
> **0.5 where 系统**(`where{...}` + bound 继承 + `A<>` 照抄)· **0.6 常量系统**(`@` 名字族/范围族/自定义)。
> 0.1.0 之前的两代原型(crate 原名 `auto_impl`)与 0.2 的重写动机,见下。
### 早期结构对照(crate 原名 auto_impl 起,至 0.2 重写前)
### 0.-1 (2026-07 原型,684 行单文件)
- **静态类型列表**:spec 是"泛型 + trait泛型 + 目标 + body"的顺序结构,
无 `^`/`-` 运算符、无元组生成、无前缀系统——目标类型是 token 透传的静态类型
- 但 **80% 的设计已定稿**:`[]` 歧义(逗号=列表/无=切片)、`()` 分组 vs 元组、
泛型继承(子项追加父级)、body 继承(列表级共享/子项覆盖)、
trait 泛型悬空诊断("`MyTrait<T>` 被解析为 trait 泛型参数,但缺少目标类型")、
`compile_error_at` span 定位、中文错误消息
- **trait 泛型自动补全**:trait 有泛型时从 `trait_generics` 自动补全
(`#trait_name<#(#params),*>`)——0.0 因 `^` 引入砍掉,0.5.5 的 `A<>` 照抄回归
### 0.0 (2026-07 原型,1961 行单文件)
- **灵光一跃:类型组合运算符化**——`^`(右结合:`A^B=A<B>`、`&^T=&T`、
`[A]^[B]` 笛卡尔积)、`-`(左结合元组构建)、`()^N`/`^M..N` 元组生成、
fresh 泛型(`A_7f3a_` span 位置哈希后缀)、前缀系统(`&`/`&mut`/`self`/`unsafe`)、
递归护栏(`RecursionGuard` 128 层,第一天就有)——DSL 的全部核心概念在此定稿,
之后 0.1→0.6 未再引入新概念,只有精化与外围系统
- 已埋的缺陷(0.2.1/0.2.2 才修):`split_raw` 无 `->` 守卫、
`expand_caret` 右侧无 dash 分割(`HashMap^K-V` 解析成嵌套而非并列)
### 0.1.x (2026-07 首个发布系列)
- **模块拆分完成**:0.0 单文件分节直接切为 `core/` 9 文件
(types/recursion/utils/codegen/tuple/caret/dash/parser + lib.rs 入口)——
0.2 的 9 文件结构就是它;
- **prefill 预填泛型**(`HashMap<K>^V → HashMap<K, V>`):`PrefixItem::Container`
加 `prefill` 字段,caret 与 dash 两条路径都接入;
- 递归护栏原样保留(`RecursionGuard` 与 0.0 逐字相同);
- 0.1.1 尚无:fn/指针/属性前缀(PrefixItem 仅 6 变体)、assoc 绑定
(ImplSpec 5 字段)、全局 `->` 守卫(仅 dash 局部有)——0.2.0/0.2.2 补。
### 0.2 (2026-07-19,9 文件 3197 行)
- 在 0.1.1 结构上延续:+`fn`/`*const`/`*mut`/`#[attr]` 前缀变体、
+assoc_bindings/attributes 字段、+`->` 全局守卫(0.2.2 统一);
- BUG-1/2/3 集中爆发(`^` 右侧 dash 分割、`parse_balanced` pos 丢弃、
前缀链过滤)——"按操作符组织 + 深度散落"模型走到极限,0.3.0 重写。
> **重写动机(作者注)**:0.2 之前是"阐述设计思路 + AI 增量实现"——
> 思路一个个蹦出,架构随补丁生长,无人完整持有整体模型;0.2.x 时修改一个
> 常识级 bug(如 `->` 守卫)要定位半天——深度逻辑散落五处、`^`/`-` 双实现,
> 改一处须确认其余各处行为一致。于是 0.3.0 由作者**手动重写**:先重建统一
> 模型(优先级链 + Apply trait + Ty 枚举),安全设施(递归护栏)未随模型
> 重建,直到 0.6.1 回归(见 0.6.1 段)。
> 0.3 之后架构稳定的真正原因不是重写本身,而是**模型从此由作者完整持有**——
> 每一行都知道为什么,改 bug 不再需要跨散落处核对。
### 三条"砍掉又回归"暗线
- **trait 泛型自动补全**:0.-1 有 → 0.0 砍(`^` 引入后 trait 名后 `<...>` 歧义)
→ 0.5.5 `A<>` 照抄回归;
- **递归护栏**:0.0 有 → 0.3 重写从零开始时丢失(未重建)→ 0.6.1 恢复
(`MAX_NEST_DEPTH`,见 0.6.1 段);
- **body 合并语义**:0.-1/0.0/0.1.1 子项覆盖列表级 → 0.2 改拼接
(独立 body 与共享 body 合并,同名方法由编译器报错)。
### 行数演进
`684 (0.-1) → 1961 (0.0) → ≈2153 (0.1.1) → 3197 (0.2) → 1628 (0.3.0 初版)`
`→ ≈1586 (0.3.0 正式版,五文件) → 4400 (0.6)`