# — 运算符重载编程指南

> 玄铁通过**魔术方法**(Magic Methods)支持运算符重载,使自定义类型可使用 `+`、`==` 等原生运算符。本文档覆盖完整 API、实现细节与实战示例。

---

## 快速开始

```xuantie
型 向量 {
    设 x
    设 y
    函 造(ax, ay) { 此.x = ax ; 此.y = ay }
    函 _加_(other) { 返 造 向量(此.x + other.x, 此.y + other.y) }
}

设 v1 = 造 向量(1, 2)
设 v2 = 造 向量(3, 4)
设 v3 = v1 + v2     // 自动调用 v1._加_(v2)
示("v3=(" & v3.x.转字() & "," & v3.y.转字() & ")")
// 输出: v3=(4,6)
```

---

## 魔术方法对照表

| 运算符 | 魔术方法 | 参数 | 返回值 | 等效调用 |
|--------|---------|------|--------|---------|
| `+` | `_加_` | `(other)` | 新实例 | `a._加_(b)` |
| `-` | `_减_` | `(other)` | 新实例 | `a._减_(b)` |
| `*` | `_乘_` | `(other)` | 新实例 | `a._乘_(b)` |
| `/` | `_除_` | `(other)` | 新实例 | `a._除_(b)` |
| `%` | `_模_` | `(other)` | 新实例 | `a._模_(b)` |
| `==` | `_等_` | `(other)` | `布尔`(真/假) | `a._等_(b)` |
| `!=` | `_等_` | `(other)` | `布尔`(取反) | `非 a._等_(b)` |

### `==` 与 `!=` 的限定规则

`==` 和 `!=` 仅在**至少一个操作数为自定义类型**(变量类型含 `型:` 前缀)时启用重载。否则直接走内建 `xt_eq`(指针/值比较)。这意味着:

- `弱引用 == 字符串` → 内建比较,不触发 `_等_`
- `整型 == 整型` → 内建比较
- `向量 == 向量` → 重载 `_等_`

---

## 算术重载详解

### 单次加法

```xuantie
型 向量 {
    设 x, y
    函 造(ax, ay) { 此.x = ax ; 此.y = ay }
    函 _加_(other) { 返 造 向量(此.x + other.x, 此.y + other.y) }
}

设 v1 = 造 向量(1, 2)
设 v2 = 造 向量(3, 4)
设 v3 = v1 + v2

若 v3.x == 4 且 v3.y == 6 { 示("PASS: 单次加法正确") }
```

### 链式加法

```xuantie
设 total = 造 向量(0, 0)
设 k = 0
当 k < 20 {
    total = total + 造 向量(1, 1)
    k = k + 1
}
若 total.x == 20 且 total.y == 20 { 示("PASS: 链式加法正确") }
```

### 嵌套表达式

```xuantie
设 a = 造 向量(1, 0)
设 b = 造 向量(0, 1)
设 c = 造 向量(2, 3)
设 result = a + b + c     // 等价于 (a + b) + c

若 result.x == 3 且 result.y == 4 { 示("PASS: 嵌套表达式正确") }
```

---

## 比较重载详解

### `==` 重载

```xuantie
型 向量 {
    设 x, y
    函 造(ax, ay) { 此.x = ax ; 此.y = ay }
    函 _等_(other) {
        返 此.x == other.x 且 此.y == other.y
    }
}

设 v1 = 造 向量(5, 5)
设 v2 = 造 向量(5, 5)
若 v1 == v2 { 示("相等") } 否 { 示("不等") }
```

### `!=` 重载

`!=` 不需要单独定义——编译器自动对 `_等_` 的结果取反:

```xuantie
若 非 (v1 != v2) { 示("v1 和 v2 相等") }
// v1 != v2 → 调用 v1._等_(v2) → 取反 → 实现 != 语义
```

---

## 实现原理

### 编译期分派

编译器在遇到运算符时:

1. 检查操作数类型是否为标量(`raw_i64` / `i1` / `double`)→ 标量直接生成 LLVM 原生指令(如 `add i64`)
2. 非标量类型 → 查找魔术方法(如 `_加_`)→ 通过 `xt_dict_get` 动态分派
3. `==` / `!=` 特殊处理:仅当操作数含自定义类型(`型:` 前缀)时启用重载,否则走 `xt_eq`(内建指针/值比较)

### 运行时流程(以 `v1 + v2` 为例)

```
1. 检查 v1 是否为堆指针(bit 0 == 0)
2. 若是:xt_dict_get(v1, "_加_") 查找魔术方法
3. 找到 → 提取 XTFunction → 调用 func_ptr(v1, v2)
4. 未找到 → 回退到内建 LLVM 运算
```

### `==` 的入口 alloca 提升

`==` 的重载路径使用 `alloca` 作为 PHI 节点的替代方案(在 overload/fallback 两分支存储结果,merge 处加载)。为避免 LLVM 支配性错误,此 `alloca` 被提升到函数入口块。

> 此机制是本会话修复的核心内容——此前 inline alloca 在 `若` 条件块内导致"Instruction does not dominate all uses!"错误。

---

## 完整测试示例

参见项目测试文件:[Test/52_运算符重载链.xt](https://github.com/MARKJY-China/XuanTie-Lang/blob/master/Test/52_%E8%BF%90%E7%AE%97%E7%AC%A6%E9%87%8D%E8%BD%BD%E9%93%BE.xt)

```xuantie
型 向量 {
    设 x, y
    函 造(ax, ay) { 此.x = ax ; 此.y = ay }
    函 _加_(other) { 返 造 向量(此.x + other.x, 此.y + other.y) }
    函 _等_(other) { 返 此.x == other.x 且 此.y == other.y }
    函 转字() { 返 "向量(" & 此.x.转字() & "," & 此.y.转字() & ")" }
}

设 v1 = 造 向量(1, 2)
设 v2 = 造 向量(3, 4)
设 v3 = v1 + v2
示("v1+v2=" & v3.转字())                    // 向量(4,6)

设 v4 = 造 向量(5, 5)
设 v5 = 造 向量(5, 5)
若 v4 == v5 { 示("v4 等于 v5") }            // 由 _等_ 判断
若 v4 != v5 { 示("不等") } 否 { 示("相等") } // _等_ 结果取反
```

---

## 已知限制

- **`==` 重载仅限自定义类型**:弱引用、Result、Socket 等运行时类型不触发 `_等_`,直接走内建 `xt_eq`(指针比较)。如需值语义比较,需手动调用方法。
- **链式 `==` 不推荐**:`a == b == c` 会先计算 `a == b`(返回布尔),再与 `c` 比较。布尔与自定义类型的 `==` 走内建路径。