# 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 全局作用域


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gocompiler.shizhz.me/golang-bian-yi-qi-lei-xing-jian-cha/untitled-2.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
