# 泛型系统

> 

本文档收敛 Dujie 第一阶段的简单泛型系统。

目标不是建立复杂的类型参数体系，而是提供足够支撑通用容器、简单复用和少量约束检查的最小泛型能力。

## 设计目标

- 只提供最小可用的泛型能力
- 语法简单
- 推导边界清楚
- 不引入复杂子类型、trait 系统或高阶类型
- 不让实现细节反推语言语义

## 总体原则

<steps level="4">

#### 泛型系统保持简单

#### 类型位置优先显式

#### 函数调用位置只做局部、可解释的推导

#### 第一阶段只支持极小的约束集合

#### 不做复杂的跨表达式反向推导

</steps>

## 支持范围

第一阶段泛型只允许出现在：

- 顶层 `func`
- 顶层 `struct`

例如：

```dj
func id<T>(x: T) -> T {
    x
}

struct Box<T> {
    value: T,
}
```

当前不支持：

- 方法级泛型
- 局部函数泛型
- 模块级泛型
- 高阶类型参数

## 语法

泛型参数列表使用尖括号：

```dj
func pair<A, B>(a: A, b: B) -> Pair<A, B> {
    Pair { first: a, second: b }
}

struct Pair<A, B> {
    first: A,
    second: B,
}
```

规则：

- 多个类型参数使用逗号分隔
- 类型参数作用域仅限当前声明

## 类型位置的实参

类型位置必须显式写出类型实参。

例如：

```dj
let a: Box<string>
let b: Pair<int, string>
```

第一阶段不支持：

- 类型位置的省略实参
- 部分类型参数推导

## 泛型函数调用推导

泛型函数调用优先从普通实参做局部推导。

例如：

```dj
id(1)          // T = int
pair(1, "a")   // A = int, B = string
```

如果调用点无法唯一推导类型参数，则必须显式写出类型实参：

```dj
id<int>(1)
```

### 当前不做的推导

第一阶段不做这些推导：

- 从赋值目标反推函数泛型实参
- 从返回类型单独反推函数泛型实参
- 跨表达式的复杂联立求解

例如：

```dj
let x: Box<string> = make_box()
```

这里不依赖左侧目标类型去反推 `make_box<T>()` 的 `T`。如果普通实参推不出来，就必须显式写：

```dj
make_box<string>()
```

### 必须显式写类型实参的典型情况

这些值本身不能唯一推出类型参数：

- `none`
- `[]`
- `{}`
- 仅出现在返回类型中的类型参数

例如：

```dj
id(none)
make_list()
```

都不应自动推导成功，除非有显式类型实参。

## 匿名函数与泛型

第一阶段支持匿名函数，但匿名函数自己不声明泛型参数。

匿名函数可以参与泛型调用，只要其参数类型和返回类型与目标位置要求一致。

例如在内建泛型方法中：

```dj
items.map(func(x: int) -> string {
    `#${x}`
})
```

这里匿名函数的参数类型必须与 `map` 当前实例的元素类型一致，返回类型必须与推导出的目标元素类型一致。

## 泛型 `struct` 构造推导

泛型 `struct` 在构造时允许从字段值推导类型参数，只要能唯一确定。

例如：

```dj
struct Box<T> {
    value: T,
}

let a = Box { value: "x" }   // Box<string>
let b = Box { value: 1 }     // Box<int>
```

如果字段值不能唯一推出类型参数，则必须使用显式类型标注。

例如：

```dj
let x: Box<opt<string>> = Box { value: none }
```

第一阶段先不引入值构造位置的显式类型实参语法，因此不写：

```dj
Box<string> { value: "x" }
```

## 约束

第一阶段支持约束语法，但只支持极小集合。

语法：

```dj
func has_key<K: key, V>(m: map<K, V>, k: K) -> bool {
    m.contains(k)
}
```

规则：

- 约束只允许出现在泛型参数声明上
- 语法形式为 `T: constraint`
- 多个类型参数各自独立声明约束

### 当前唯一内建约束：`key`

`key` 用于表示“可作为 `map` 键”的类型能力。

当前满足 `key` 的类型只有：

- `int`
- `bool`
- `rune`
- `string`

第一阶段不支持：

- 多重约束
- `where` 子句
- 用户自定义约束
- 基于方法集的复杂约束系统
- 恢复旧的 `comparable` 设计作为通用约束

## 与参数化容器类型的关系

内建参数化类型：

- `list<T>`
- `map<K, V>`
- `opt<T>`
- `iter<T>`

和用户定义泛型共用同一套类型参数语法，但它们的具体语义仍由各自的专题文档定义，不由本文件重复展开。

这些内建参数化类型不是用户代码定义出来的普通泛型 `struct`，而是语言内建类型。

因此：

- 语法一致
- 类型参数写法一致
- 但具体操作语义由各自专题定义

例如：

- `list<T>` 的 `push/pop/remove`
- `opt<T>` 的 `none/some/is`
- `iter<T>` 的 `map/filter/collect`

都属于内建语义，不代表所有用户泛型类型自动拥有类似能力。

语言内建方法可以带泛型语义，例如：

- `iter<T>.map<U>(...) -> iter<U>`
- `iter<T>.filter(...) -> iter<T>`
- `iter<T>.collect() -> list<T>`

但这不代表当前语言已经开放“用户自定义方法”或“用户自定义方法泛型”。

## 泛型类型相等性

泛型类型采用名义相等。

规则：

- 同一个泛型声明，类型实参逐个完全相同，类型才相等
- 不同声明即使字段形状相同，也不是同一类型

例如：

```dj
Box<string>
Box<int>
Pair<int, string>
```

其中：

- `Box<string>` 与 `Box<string>` 是同一类型
- `Box<string>` 与 `Box<int>` 不是同一类型
- `Pair<int, string>` 与 `Pair<string, int>` 不是同一类型

## 泛型实例兼容性

第一阶段参数化类型统一按不变处理。

也就是说：

- `Box<string>` 不是 `Box<any>`
- `list<string>` 不是 `list<any>`
- `opt<string>` 不是 `opt<any>`

第一阶段不引入：

- 协变
- 逆变
- 基于子类型关系的参数化兼容

## 用户泛型类型的能力边界

用户定义的泛型 `struct` 不会因为“是泛型”而自动获得额外能力。

例如，泛型本身不会自动决定：

- 是否可比较
- 是否可作 `map` key
- 是否可迭代
- 是否具有特殊内建方法

这些能力仍由语言内建规则或显式约束单独定义。

## 当前不讨论的实现问题

本文不规定：

- 单态化还是共享实现
- Rust 代码生成的具体映射方式
- 运行时表示
- trait/object 风格的底层实现策略

这些属于编译器实现问题，不能反向决定语言语义。

## 当前结论

Dujie 第一阶段的泛型系统可以概括为：

- 只支持顶层 `func` 和顶层 `struct` 泛型
- 类型位置显式写实参
- 函数调用位置做局部推导
- 泛型 `struct` 构造可从字段值局部推导
- 约束系统只保留最小的 `key`
