Chiba Level 1 Method Resolution Spec
0. 范围
本文规定 Chiba level-1 的 method resolution、operator overloading、以及 shape-based dispatch 的最小规则。
本文只讨论 level-1。
level-1 没有传统 interface / trait solver,因此本文讨论的是 nominal method system,而不是 interface-based witness resolution。
0. Scope
This document defines the minimum rules for method resolution, operator overloading, and shape-based dispatch in Chiba level-1.
It only discusses level-1. Since level-1 has no traditional interface system, the topic here is a nominal method system rather than interface-based witness resolution.
1. 设计要求
level-1 的方法系统需要同时满足:
- 支持 method surface syntax
- 支持
def Type.method(...) - 支持 operator overloading
- 支持 shape-based dispatch
- 与 checked structural templates 协作
- 保持较快的候选筛选与缓存
1. Design Requirements
The level-1 method system must support method surface syntax, def Type.method(...), operator overloading, shape-based dispatch, and cooperation with checked structural templates while still keeping candidate filtering and caching fast.
2. 基本规则
level-1 的方法解析不以“证明 T : X”为核心。
它的核心是:
- receiver 的 nominal identity 是什么
- 当前 call site 需要哪个名字或 operator
- 在当前 concrete instantiation 下有哪些候选
- 哪个候选最具体且不歧义
在 level-2 引入 named constraint 与 via 后,method resolution 仍应保持分层:
- level-1 nominal methods
- level-2
via namespace路径
因此 method / operator obligation 的实现形状应预留 behavior source:
DefaultVisible
ExplicitVia(namespace_id)
QualifiedPath(symbol_id)
当 behavior source 影响实现选择时,它必须进入 specialization key,避免同一 nominal type 与同一 method/operator 名称在不同 via 来源下复用错实现。
2. Basic Rule
Method resolution in level-1 is not centered on proving T : X.
Instead, it is centered on the receiver’s nominal identity, the requested name or operator at the call site, the candidates available under the current concrete instantiation, and the choice of the most specific non-ambiguous candidate. If level-2 later adds named constraints and via, the layering should remain explicit: nominal methods in level-1 and explicit via namespace paths in level-2.
Therefore method and operator obligations should reserve a behavior-source field such as DefaultVisible, ExplicitVia(namespace_id), or QualifiedPath(symbol_id). When the behavior source affects implementation choice, it must enter the specialization key so that different via sources cannot accidentally reuse the same generated instance.
3. def Type.method(...)
level-1 允许 method-style 定义:
def Type.method(self, ...)
这里的 Type 在 level-1 中可以是:
- 名义类型
本文采用保守规则:
- receiver 约束最终必须落到 nominal identity 上
- 不依赖 interface witness
3. def Type.method(...)
Level-1 allows method-style definitions such as def Type.method(self, ...).
Here Type must be a nominal type in level-1. The conservative rule is that receiver constraints for methods reduce to nominal identity only and may not depend on interface witnesses.
4. Method Call
调用:
v.m(a, b)
至少产生下面几类检查:
v的 receiver nominal type- 名称
m - 参数形状与返回类型约束
- 当前实例化下的候选集合
最终结果不是通过 interface satisfaction 决定,而是通过 nominal identity 与 concrete instantiation 共同决定。
a.b(c) 的 callee 解析分三层:
- 若
a是值表达式,且其值类型有字段b,则选择 field callable,形成(a.b)(c)。 - 否则,若
typeof(a)的 nominal method set 中有方法b,则选择 receiver method,形成TypeOf(a).b(a, c)。 - 否则,若
a是 type / namespace path,且a.b作为整体能解析到可调用项,则选择 qualified callee,形成(a.b)(c)。
第 3 层不做 receiver 注入;a.b 是整体名字。
row 约束在 level-1 中表示 row member contract,而不是全局 nominal-method witness。
若定义期只知道 a 满足 {r | b: ty},那么 checker 应记录成员 b 的 obligation。该 obligation 可以由 stored field 兑现;如果 ty 是 callable,也可以支持 (a.b)(c) 的 field-callable 路线。若实例化时 concrete receiver 是 nominal type 且没有同名字段,则同一个 member obligation 也可以由 concrete receiver method adapter 兑现。
这条规则有两个硬边界:
- 字段优先。若 concrete type 同时有字段
b和 receiver methodb,必须先检查字段;字段不满足 callable / signature contract 时直接报错,不回退到 method。 - method adapter 只能在 concrete nominal receiver 已知时选择,或者在 expected
dyn {r | ...}package injection 时选择;定义期不能把裸 row fact 当成全局 method witness。
若 row-shaped value 需要进入某个具体 nominal type 的 method world,仍必须先通过显式 cast / checked conversion 得到 concrete nominal type。没有这个转换时,普通 receiver method resolution 不从 shape 猜 nominal identity。
4. Method Calls
A call like v.m(a, b) must at least inspect the receiver’s nominal type, the name m, the argument and return-type constraints, and the candidate set available under the current instantiation.
The result is not decided by interface satisfaction. It is decided by nominal identity and the concrete instantiation.
For a.b(c), callee resolution is layered: if a is a value expression with field b, the call is (a.b)(c); otherwise, if typeof(a) has nominal method b, the call lowers to TypeOf(a).b(a, c); otherwise, if a is a type or namespace path and a.b resolves as a callable item, the call is (a.b)(c). The qualified-callee case does not evaluate a and does not inject a receiver.
A row constraint is a row member contract, not a global nominal-method witness.
If definition-time checking only knows that a satisfies {r | b: ty}, the checker records an obligation for member b. That obligation may be discharged by a stored field. If ty is callable, it may also support (a.b)(c) through the field-callable path. When instantiation later produces a concrete nominal receiver and there is no same-named field, the same member obligation may also be discharged by a concrete receiver-method adapter.
There are two hard boundaries:
- Fields take priority. If a concrete type has both field
band receiver methodb, the field must be checked first. If the field does not satisfy the callable or signature contract, the checker reports an error instead of falling back to the method. - A method adapter may be selected only when a concrete nominal receiver is known, or when expected
dyn {r | ...}package injection builds adapters. Definition-time checking must not treat a bare row fact as a global method witness.
If a row-shaped value needs to enter a concrete nominal type’s method world, it must still go through an explicit cast or checked conversion to that concrete nominal type. Without that conversion, ordinary receiver-method resolution must not infer nominal identity from shape.
4.1 self 与 Self
method-style 定义:
def X.y(self, arg: A): R = ...
把 self 绑定为 owner nominal type。method body 内引入特殊 receiver-scope alias:
Self := X
self : Self
method index key 是 (nominal_id(X), "y"),可调用形状是 (Self, A) => R。
generic owner 的方法中,Self 带上 owner 的类型参数:
type Box[T] = { value: T }
def Box[T].get(self): T = self.value
这里 method scope 中有 Self := Box[T],所以 self : Box[T],self.value : T。
Self 不是普通 top-level type name,不参与 row erasure,也不是可在非 method 位置自由引用的 generic 参数。
4.1 self and Self
A method-style definition such as def X.y(self, arg: A): R = ... binds self to the owner nominal type. Inside the method body, the checker introduces a receiver-scope alias Self := X, so self : Self. The method index key is (nominal_id(X), "y"), and the callable shape is (Self, A) => R.
For a checked-template owner, Self includes the owner’s type arguments. In type Box[T] = { value: T } plus def Box[T].get(self): T = self.value, the method scope has Self := Box[T], so self : Box[T] and self.value : T.
Self is not an ordinary top-level type name, not row erasure, and not a generic parameter that can be freely referenced outside a method receiver scope.
4.2 Generic receiver specialization
泛型 receiver method 在 concrete receiver 上调用时,必须先专门化 receiver header。
type Box[T] = { value: T }
def Box[T].update(self: Self, value: T): Self = {
{ self | value: value }
}
def main(): i64 = Box[i64]({ value: 1 }).update(42).value
在 Box[i64].update 的 call site:
- method receiver header
Box[T]与 actual receiverBox[i64]匹配。 - substitution 是
T := i64。 Self专门化为Box[i64]。- 参数
value: T专门化为value: i64。 - 返回
Self专门化为Box[i64]。
这个 substitution 作用于嵌套 type application,例如 Box[Pair[T, U]] 中的 T / U 也必须递归替换。
method candidate 可以通过 parsed type header / symbol table fact 匹配 base nominal identity,但不能通过 ad-hoc string split、大小写、前后缀或 debug name 形状推断语义。
4.2 Generic Receiver Specialization
A generic receiver method must specialize its receiver header before it is called on a concrete receiver.
For Box[T] with def Box[T].update(self: Self, value: T): Self, a call on Box[i64] matches the method receiver header Box[T] against the actual receiver Box[i64]. The substitution is T := i64; Self becomes Box[i64]; value: T becomes value: i64; and the result Self becomes Box[i64].
The substitution applies recursively through nested type applications. A method candidate may match by parsed type-header and symbol-table facts, but semantic resolution must not depend on ad-hoc string splitting, casing, prefixes, suffixes, or debug-name shape.
5. Operator Overloading
operator overloading 在 level-1 中属于方法系统的一部分。
它和普通 method resolution 的差别主要在 surface syntax,而不是 obligation 的本质。
例如:
- infix operator
- prefix operator
- postfix operator
.*
它们都应被统一到:
- 一个可索引的 operator 名称空间
- 一套基于 receiver / operand shape 的候选筛选规则
5. Operator Overloading
Operator overloading is part of the level-1 method system. The difference from ordinary method resolution is mostly surface syntax, not the underlying obligation model.
Infix, prefix, postfix, and forms such as .* should all be unified under an indexable operator namespace and one candidate-selection discipline driven by receiver and operand shapes.
6. Shape-Based Dispatch
shape-based dispatch 仍然是 level-1 的既定目标,但它不再等同于 method resolution。
method resolution 只负责 nominal 方法;shape-based dispatch 属于独立的 structural obligation / codegen 路径。
6. Shape-Based Dispatch
Shape-based dispatch remains a built-in target of level-1, but it is no longer identified with method resolution. Method resolution is only for nominal methods; shape-based dispatch belongs to a separate structural-obligation and codegen path.
7. 候选筛选
为了兼顾编译速度,候选筛选必须分层:
- 先按名称或 operator 查候选集
- 再按 receiver 的 nominal identity 做快速过滤
- 再做精确的 nominal match
- 最后选最具体且不冲突的候选
实现层可结合:
- canonical row / shape key
- field mask
- popcount 或类似分桶
- 方法解析缓存
7. Candidate Filtering
To keep compile time under control, candidate filtering must be layered: first filter by name or operator, then quickly filter by nominal identity and normalized receiver shape, then run precise structural matching, and finally choose the most specific non-conflicting candidate.
The implementation may rely on nominal method indexes, fast nominal-type filters, and method-resolution caches.
8. 与 Checked Templates 的关系
checked-template body 中的 method call 常常不能在定义期完全决议。
因此本文采用:
- 定义期生成 method obligation
- 实例化期在 concrete shape 上完成最终解析
这也是 level-1 保持编译速度的关键手段之一。
8. Relation to Checked Templates
Method calls inside checked-template bodies often cannot be fully resolved at definition time.
The correct model is to generate method obligations during definition-time checking and finish the final resolution over concrete shapes during instantiation. That is one of the main reasons level-1 can stay fast.
9. 与 Row 的关系
method resolution 只建立在名义类型之上。
method resolution 负责:
- 选候选
- 判冲突
- 给出最终目标实现
名义类型负责:
- 保留 receiver 的稳定语义身份
- 避免同 shape 不同 type 的方法世界被混成一个
row / shape 仍服务于字段访问、generic obligation、row member obligation、dynamic adapter construction 与 shape-based dispatch,但不参与默认的全局方法查找。
因此 field callable 是 receiver method resolution 之前的表达式解析结果;qualified callee 是 type / namespace path 解析结果。adapter member 则是 checked-template 实例化或 dyn injection 时,从 concrete nominal receiver method index 中选出的固定目标。三者都不能被混成“运行时按名字重新找 method”。
9. Relation to Rows
Method resolution is built on nominal types. It chooses candidates, detects conflicts, and identifies the final implementation target, while rows and shapes remain available for field access, generic obligations, row member obligations, dynamic-adapter construction, and shape-based dispatch outside default global method lookup.
Field-callable resolution happens before receiver-method resolution, and qualified-callee resolution happens through type or namespace path lookup. Adapter members are fixed targets selected from the concrete nominal receiver-method index during checked-template instantiation or dynamic-package injection. None of these paths may degrade into runtime method lookup by name.
10. 与 Named Constraint / via 的边界
level-1 没有传统 interface 系统。
因此本文明确不做:
- witness search
T : X风格的 satisfaction- interface / trait coherence 规则
这些都属于 level-2。
但为了与 level-2 保持兼容,本文先固定下面规则:
- namespace-scoped named constraint 不做全局传染
via namespace是显式行为来源选择- 没有显式
via时,普通x.m()不进入全局 evidence search
这意味着:
x.m() via ns.path进入显式 namespace 路径- 默认
x.m()只看默认可见世界中的 nominal 候选
10. Boundary with Named Constraints and via
Level-1 has no traditional interface system, so it does not perform witness search, T : X-style satisfaction, or interface/trait coherence rules. Those all belong to level-2.
To stay compatible with that future layer, three forward rules should already be fixed: namespace-scoped named constraints must not become global evidence, via namespace is an explicit behavior-source path, and ordinary x.m() without via must not fall into a global evidence search.
11. 歧义与冲突
level-1 虽然没有完整 interface 系统,但 method resolution 仍必须回答:
- 若两个候选都匹配怎么办
- 若没有唯一最具体候选怎么办
- 若 operator 和 method surface 映射到同一底层名义空间怎么办
本文采用保守规则:
- 不存在唯一最具体候选时,直接报错
- 不在 level-1 引入复杂全局 overlap 规则
若未来同时存在默认候选与显式 via 路径,则默认规则应为:
- 显式
via namespace优先于默认路径 - 普通
x.m()不自动吸入 namespace 外的命名约束 - 同层没有唯一候选时直接报错
11. Ambiguity and Conflict
Even without a full interface system, level-1 method resolution must answer what happens when two candidates match, when no uniquely most-specific candidate exists, or when operator and method syntax map into the same underlying namespace.
The conservative rule is to error out whenever there is no unique most-specific candidate. If level-2 later introduces explicit via namespace paths, those paths should take priority over the default lookup, while ordinary x.m() should remain inside the default nominal world.
12. 编译速度约束
为了兼顾编译速度,实现必须坚持:
- 候选解析懒执行
- 结果缓存到 concrete nominal instantiation
- 不做 eager 全局扩散
- 不要求 level-1 提前构造完整的 interface-like method table
- 不让同 shape 不同 nominal type 在解析阶段被合并
12. Compile-Time Constraints
To preserve compile speed, candidate resolution must remain lazy, cached on concrete nominal instantiations, free of eager global propagation, free of any requirement that level-1 build a full interface-like method table in advance, and careful not to collapse different nominal types merely because their shapes match.
13. 非目标
下列内容不是当前 level-1 首批目标:
- traditional interface-based dispatch
- witness / dictionary passing
- 完整 coherence 形式化
- 全局 eager method propagation
- 依赖命名能力系统的 overload solver
13. Non-Goals
The first generation of level-1 method resolution is not trying to provide traditional interface-based dispatch, witness or dictionary passing, a full formalization of coherence, eager global propagation of methods, or an overload solver built on top of a named capability system.
14. 开放问题
- operator 名称编码最终采用什么方案
- shape dispatch 缓存与 generic 实例化缓存是否共享
- method ambiguity 的错误信息如何尽量保持清晰
14. Open Questions
- What final encoding should operator names use?
- Should shape-dispatch caches and generic-instantiation caches be shared?
- How can ambiguity diagnostics stay clear when method resolution fails?