Skip to content

lib: enforce dependency direction and bind inferred struct params - #214

Merged
dslsdzc merged 1 commit into
developfrom
lib-direction-struct-bind
Oct 26, 2026
Merged

dslsdzc merged 1 commit into
developfrom
lib-direction-struct-bind

Conversation

@dslsdzc

@dslsdzc dslsdzc commented Oct 26, 2026

Copy link
Copy Markdown
Owner

概要

收口库机制的两个真实缺口,并修复 struct ... val: . 的显式参数注解。

1. 依赖方向在 import 与符号两层都生效

之前 lib_can_import 只在 selftest 里被调用;运行时只检查 pub,@std/@user 仍可加载 @core 文件(虽然符号被隐藏)。

  • sym_visible / func_visible / mod_func_visible / 方法查找都要求 lib_can_import(g_cur_lib, owner) == 1。
  • res_imports 在加载前检查导入边:@user -> @core、@std -> @core 直接报
    cannot import '...' (@user -> @core): library dependency direction,不再加载。
  • lib_dep_add 拒绝自环与回边;selftest-lib 覆盖方向、自环、回边。
  • impl HiddenI for P 之前绕过可见性:parser 只记录 trait/type 名字。现在每条 impl 边记录声明行,checker 按所在库检查接口符号的 owner/pub;跨库隐藏接口报 N01,同库隐藏接口与 pub 接口行为不变。

2. 绝对路径归属

lib_lookup_path 只匹配仓库相对前缀,LSP 的绝对路径(/repo/src/stdlib/...)会被当成 @user,导致 pub 过滤失效。现在按 cwd 与可执行文件所在仓库根做规范化;@std/@core 的绝对路径归属正确。

3. LSP 诊断行号

诊断保存的是拼接源码的行号。发布到导入文件时未转回该文件本地行号,会出现 110 行的 os.cr 报第 392 行。现在 lsp_diag_json 用 analysis_line_offset 转回本地行;lsp_check_file 记录 g_source_name。

4. os.cr 的依赖声明

get_env 使用 read_file,但 os.cr 没有 import io,单独 import os 必然报 N06。补上真实依赖。

5. struct Box: val: . + fn get(b: Box)

struct Box:
    val: .

fn get(b: Box) -> int:
    return b.val

之前 b: Box 只解析成 TYP_NAMED(Box),字段 val 的结构体泛型位未绑定,直接 TF01。现在 collect_decls 为参数注解里的裸泛型结构体名分配函数级类型变量,并把注解改写为 Box[__bindN];调用点用既有 unify_types 从实参绑定,monomorph 实例化。

  • fn get(b) / fn get(b: .) 的既有写法不变。
  • Box { val = "x" } 传给声明 -> int 的函数会在实例化点拒绝。
  • 未调用的泛型函数照常通过模板检查。

验证

  • selfhost-tests / bootstrap-tests / check 全绿。
  • canary 5/5 不变。
  • 新增判据:
    • test_lib_manager:@user -> @core、@std -> @core 导入拒绝;方向/自环/回边 selftest。
    • test_pub_visibility:临时 src/stdlib fixture 覆盖隐藏/公开的 enum、interface impl、type alias。
    • test_lsp_visibility:导入文件诊断行号必须落在该文件本地行。
    • test_v4_field_inference:b: Box 注解正例与类型不匹配负例。

Library boundary:
- Symbol, function, module-function and method visibility now require the
  dependency edge itself; @std/@user cannot read @core even when a symbol is
  pub. Import resolution rejects the same direction at load time instead of
  merely hiding symbols.
- lib_dep_add rejects self edges and cycles; selftest covers both directions.
- `impl I for T` records its declaration line and a hidden interface cannot be
  implemented cross-library (same-library impls and pub interfaces unchanged).
- Library ownership normalizes absolute source paths against cwd and the
  executable repo root, so LSP documents in src/stdlib/src/compiler are owned
  by the right library.
- LSP diagnostics convert concatenated line coordinates back to the owning
  file, and lsp_check_file records g_source_name.
- os.cr imports io for read_file (import os now compiles standalone).

Inferred struct parameters:
- `struct Box: val: .` used as `fn get(b: Box)` leaves the field parameter
  unbound. collect_decls now binds each bare generic struct annotation to
  fresh function-scoped type variables and rewrites it to Box[__bindN];
  call sites unify them with the concrete argument. `fn get(b)` and
  `fn get(b: .)` keep working.
- Tests: by-value annotation returns the field; a Box<string> passed to a
  function declared -> int is rejected.

Canary 5/5 unchanged. selfhost/bootstrap/check green.
@dslsdzc
dslsdzc merged commit b67ae8d into develop Oct 26, 2026
4 checks passed
@dslsdzc
dslsdzc deleted the lib-direction-struct-bind branch October 26, 2026 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant