> For the complete documentation index, see [llms.txt](https://gocompiler.shizhz.me/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://gocompiler.shizhz.me/golang-bian-yi-qi-lei-xing-jian-cha/untitled-2.md).

# 4.2 代码结构

## 4.2.1 入口简介

{% hint style="info" %}
在[前言](/master.md)中提到 Go 的编译器团队当前正在重写类型检查器，虽然新版本的代码已经合并到 master 分支，但当前默认仍旧使用的是老版本的类型检查器，新的类型检查器可以通过编译参数 "-G=2" 使用，并且应该会随着泛型的发布而默认启用，因此本文将完全基于新代码进行分析。

老的类型检查代码的入口位置与新的代码位置邻近，相信对老系统感兴趣的同学在阅读完本章之后，也能够无障碍地找到对应的实现，所以本文将不会对老代码做特别的说明。
{% endhint %}

### 代码入口&#x20;

类型检查的输入是语法分析的输出 --- AST，其代码入口位置就在语法解析之后，同在`$GCROOT/compile/internal/noder/noder.go`文件内的函数`LoadPackage()`中。解析器处理完语法解析的错误信息之后，随即进行类型检查：

```go
if base.Flag.G != 0 { // 编译器通过参数 -G 开启新类型检查
    // Use types2 to type-check and possibly generate IR.
    check2(noders) // 类型检查入口函数
    return
}

```

check2 在文件`$GCROOT/compile/internal/noder/irgen.go`中定义，该函数实际上做了两件事情：类型检查；然后生成 IR(Intermediate Representation) Tree，我们当前仅关注前者，下一章将详细介绍如何生成 IR Tree。

### 主体代码位置

类型检查的逻辑非常复杂，涉及到的主体代码都在目录`$GCROOT/compile/internal/types2`下，其中对常量表达式的处理又依赖`$GOROOT/src/go/constant`与`$GOROOT/src/go/token`

{% hint style="info" %}
Go 语言通过包`$GOROOT/src/go` 将词法分析器、语法分析器、包加载器（Importer）以及类型检查器作为库开放了出来，以提供给需要对 go 语言进行分析的第三方工具使用，像gopls, guru等工具都使用该包来对 go 的源代码进行分析，甚至编译器本身也对该库有依赖。

就核心功能而言，该包的功能基本上是编译器完整功能的一个子集，代码也有很大部分的重复，但是因为该包需要保持稳定以及向前兼容，而编译器的开发非常活跃，所以 Go 团队还是保持了两份代码，虽然违背了工程上的一些准则，但从实践上来说维护起来更加简单。
{% endhint %}

## 4.2.2 索引文件

新类型检查器的所有代码都在目录`$GCROOT/compile/internal/types2/`下，各文件及功能简介如下：

* examples: 泛型使用示例
* testdata: 各种测试用例，例如各种循环引用、类型检查等
* api.go: 类型检查器对外提供的重要接口类数据结构及方法，例如 Info, Config, Identical() 等
* assignments.go: 处理赋值语句的检查工作，检查一个类型的值能够赋给另一个类型；常量、变量的初始化函数也在该文件内
* builtins.go: 检查对内置函数的调用是否合法&#x20;
* call.go: 对函数、方法调用进行类型检查
* check.go: 整个类型检查的主控逻辑
* conversions.go: 对类型转换进行类型检查，例如 A(b)
* decl.go: 对单个 Object 对象进行类型检查的主控逻辑
* errors.go: 类型检查错误处理逻辑，包括 error 定义与一些通用逻辑定义
* expr.go: 对表达式进行类型检查
* infer.go: 根据实际类型对类型参数进行推导
* initorder.go: 构建初始化顺序
* labels.go: 对程序中 label 的使用是否正确进行检查
* lookup.go: 属性、方法查找逻辑，以及判断给定类型是否实现了特定接口
* object.go: 定义 Object 对象，该对象是类型检查展开的核心数据结构
* operand.go: 定义数据结构 operand, 该结构用来封装类型检查过程中的操作数。该文件还包括判断一个 operand 能够赋值给指定类型的方法
* package.go: 定义了 Package 数据结构及辅助方法
* pos.go: 主要用来计算给定 syntax.Node 在源文件中的位置，包括开始位置及结束位置
* predicates.go: 定义了很多对类型各种性质进行判断的断言函数，例如 isBoolean(), isOrdered() 等；最重要的是判断两个类型是否等价的 identical() 函数
* resolver.go: 类型检查的预处理函数及入口函数，基本用于辅助 check.go 中的函数
* return.go: 判断语句是否包含 return, 是否包含 break 等
* scope.go: 定义作用域
* selection.go: 定义并处理形如 X.sel 这类表达式的逻辑
* stmt.go: 对程序内的语句进行类型检查，例如函数体
* subst.go: 对包含泛型的类型进行实例化，即根据实际的类型参数创建具体的类型
* type.go: 定义与所有类型相关的数据结构
* typexpr.go: 根据类型表达式创建具体类型，例如根据 \~\[]int\~ 创建出切片类型
* unify.go: 判断包含泛型的两个类型是否等价
* universe.go: 初始化 Universe 全局作用域
