# 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()`最后就会返回对应的类型数据结构，从而成功完成类型检查，该函数是类型检查过程中编译器创建各种类型结构的核心。


---

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