> 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/4.5.31.3b-lei-xing-biao-da-shi-de-lei-xing-jian-cha.md).

# 4.5.3-1.3b 类型表达式的类型检查

Go 在语法分析中使用表达式（Expr）表示类型值，例如对于如下类型申明：

```go
 type T struct {
     name string
 }
```

编译器会为`struct {}`这块代码创建表达式`syntax.StructType`. 而对于下列申明：

```go
 var pipe chan int
```

代表类型的`chan int`对应的是表达式`syntax.ChanType`.

对类型表达式进行类型检查的入口函数是`check.typ()`, 核心逻辑封装在方法`check.typInternal()`中，定义在文件`GCROOT/compile/internal/types2/typexpr.go`内，其代码结构如下：

```go
 func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
     switch e := e0.(type) {
     case *syntax.BadExpr:
         // ignore - error reported before
     case *syntax.Name:
         var x operand
         check.ident(&x, e, def, true)
         switch x.mode {
         case typexpr:
             typ := x.typ
             def.setUnderlying(typ)
             return typ
         case invalid:
             // ignore - error reported before
         case novalue:
             check.errorf(&x, "%s used as type", &x)
         default:
             check.errorf(&x, "%s is not a type", &x)
         }
     case *syntax.SelectorExpr:
     case *syntax.IndexExpr:
     case *syntax.ParenExpr:
     case *syntax.ArrayType:
     case *syntax.SliceType:
     case *syntax.DotsType:
     case *syntax.StructType:
     case *syntax.Operation:
     case *syntax.FuncType:
     case *syntax.InterfaceType:
     case *syntax.MapType:
     case *syntax.ChanType:
         typ := new(Chan)
         def.setUnderlying(typ)

         dir := SendRecv
         switch e.Dir {
         case 0:
             // nothing to do
         case syntax.SendOnly:
             dir = SendOnly
         case syntax.RecvOnly:
             dir = RecvOnly
         default:
             check.errorf(e, invalidAST+"unknown channel direction %d", e.Dir)
             // ok to continue
         }

         typ.dir = dir
         typ.elem = check.varType(e.Elem)
         return typ

     default:
         check.errorf(e0, "%s is not a type", e0)
         check.use(e0)
     }

     typ := Typ[Invalid]
     def.setUnderlying(typ)
     return typ
 }
```

通过方法签名可知：该方法通过一个表达式推导出一个类型。其中每个 case 都对应一个类型表达式，这里只留下`syntax.Name`与`syntax.ChanType`进行演示。

`check.typInternal()`采用递归方式对表达式进行类型检查，例如对于`syntax.ChanType`, 最后调用了`check.varType()`对 channel 的元素类型进行检查，而后者最终又会回到`check.typInternal()`中来。递归算法都是基于[Divide-and-Conquer](https://en.wikipedia.org/wiki/Divide-and-conquer_algorithm)的思路来解决问题的，对于任何递归函数的分析，都需要牢牢把握两方面的信息：&#x20;

1. base-case 是什么？即何时遇到原子问题终止递归&#x20;
2. 问题如何分解？即一个大问题如何被拆分成更小的问题

对于`check.typInternal()`而言，问题分解就是上面方法中每个 case 的处理逻辑；而 base-case 对应的就是语言的基础类型，当类型检查遇到`int32`, `bool`, `string`等类型时，此时对应的是`syntax.Name`这个 case, 接下来编译器会通过`check.ident()`方法对该标识符（identifier）进行类型检查，而在[全局作用域](/golang-bian-yi-qi-lei-xing-jian-cha/4.5.21-quan-ju-zuo-yong-yu.md)的初始化过程中，编译器已经将所有基础类型注册好了，所以`check.ident()`方法会成功完成符号解析并拿到对应的类型结构，如果是`int32`, 则会得到一个`TypeName`的 Object 对象，其类型是`Basic{kind: Int32, info: IsInteger, name: "int32"}`.

如果类型表达式的所有子结构都没有问题，那么`check.typInternal()`最后就会返回对应的类型数据结构，从而成功完成类型检查，该函数是类型检查过程中编译器创建各种类型结构的核心。
