Files
TermiNexus 66ebd75dec test(lifetime): 补齐 A2 @life(ret(...)) 的正/负向回归工程
新增 3 个工程(均登记进 regression_test.py / SequentialRegressionTest.py /
run_lifetime_negative_tests.py 的 escape/负向清单):
- NewLifetimeRetOkTest(正向):ret(heap)/ret(static)/ret(borrows=none) 的结果
  可存进堆对象字段;ret(frame)/ret(borrows=x) 的结果只在本帧内使用;
  同模块契约表与跨模块 .vpi(escr=) 两条取用路径都覆盖 → 编译通过 + 退出码 0。
- NewLifetimeRetEscapeTest(负向):同模块 @life(ret(frame)) 的返回值写进堆对象
  字段 → LifetimeError(隔离性:FrameRet 摘要为 0,唯一报错源是 ret 契约)。
- NewLifetimeRetXmodTest(负向):跨模块 @life(noescape(x), ret(borrows=x)) 的结果
  写进堆对象字段 → LifetimeError(契约经对方 .vpi 的 escr= 传来;noescape 清掉了
  实参逃逸路径,判据收敛到 ret 契约)。
README.md 的 escape 测试表与负向清单同步。
2026-10-10 09:03:05 +08:00

25 lines
1.1 KiB
Plaintext

from stdint import *
# =============================================================================
# A2 跨模块负例的**被调方**:契约(逃逸掩码 + 返回值生命期)只能经本模块 .vpi
# 行尾 `# esc=… escn=… escr=…` 传到调用点 —— 本文件与 main.vp 不同模块,
# 调用点的本地契约表按文件重置、必然查不到,命中
# CallGenBase.lookup_ret_kind_via_vpi → VpiReader 的 escr= 缓存这条回退路径。
# =============================================================================
# ret(borrows=x):返回值借用形参 x —— 调用点把结果当 x 的生命期。
# 配 `noescape(x)`:本函数只**借出** x、不把它存进长命存储 → 形参 x 不算逃逸,
# 于是调用点上"实参逃逸"那条路径不会先报错,判据收敛到 ret 契约本身。
@life(noescape(x), ret(borrows=x))
def IdentBorrow(x: int*) -> int*:
return x
# 对照:`ret(frame)`(把 main 的用例换成 CaseFrame 时用)。返回值指向本帧存储。
@life(ret(frame))
def FrameRet() -> int*:
l: int* = new stack int
return l