> ## Content Index
> Fetch the complete content index at: https://blog.hacking.pub/llms.txt
> Use this file to discover other available public pages before exploring further.

# 从compare_4.go初识go的typecheck
- URL: https://blog.hacking.pub/2019/07/11/cong-compare_4-gochu-shi-gode-typecheck/
- Published: 2019-07-11T14:18:47.000Z
- Updated: 2019-07-11T14:19:05.000Z
- Author: chainhelen
- Tags: go, go语言, golang, 编译, 编译器, 编译原理, typecheck, 类型检查

主要是上一次的题目的[第四道](https://blog.hacking.pub/2019/07/10/untitled-4/)

上次`compare`梳理了 `go build`在`compile`之前的准备工作，比如收集`import`依赖关系 

针对`compare_4.go`进行编译，看一下一点`compile`的过程，参数`build -x -o ./compare_4 compare_4.go`

```
package main

import "fmt"

func main() {
	a := []byte("helloworld")
	b := []byte("helloworld")

	if a == b {
		fmt.Printf("equal\n")
	} else {
		fmt.Printf("not equal\n")
	}
}

```

可以看到终端输出：

```sh
WORK=/tmp/go-build082348361
mkdir -p $WORK/b001/
cat >$WORK/b001/_gomod_.go << 'EOF' # internal
package main
import _ "unsafe"
//go:linkname __debug_modinfo__ runtime/debug.modinfo
var __debug_modinfo__ = "0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tcommand-line-arguments\nmod\tcommand-line-arguments\t(devel)\t\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\xd8\xf2"
var keepalive_modinfo = __debug_modinfo__
func init() { keepalive_modinfo = __debug_modinfo__ }
	EOF
cat >$WORK/b001/importcfg << 'EOF' # internal
# import config
packagefile fmt=/usr/local/go/pkg/linux_amd64/fmt.a
packagefile runtime=/usr/local/go/pkg/linux_amd64/runtime.a
EOF
cd /media/chainhelen/LENOVO/xlworkspace/code/go/src/sh
/usr/local/go/pkg/tool/linux_amd64/compile -o $WORK/b001/_pkg_.a -trimpath $WORK/b001 -p main -complete -buildid ii314DFgycKna9StCilp/ii314DFgycKna9StCilp -goversion go1.12.5 -D _/media/chainhelen/LENOVO/xlworkspace/code/go/src/sh -importcfg $WORK/b001/importcfg -pack -c=4 ./compare_4.go $WORK/b001/_gomod_.go

（我是在goland里面下了 `/usr/local/go/src/cmd/go` 断点，所以这个时候并没有删除临时WORK目录，断点位置在/usr/local/go/src/cmd/go/internal/work/gc.go:142）

```

可知在收集完信息之后，直接调用`compile`工具（子进程），那么手动模拟一下编译过程 

```sh
1. mkdir /tmp/test_self

2. 进入test_self目录，新建_gomod_.go，内容如下
package main
import _ "unsafe"
//go:linkname __debug_modinfo__ runtime/debug.modinfo
var __debug_modinfo__ = "0w\xaf\f\x92t\b\x02A\xe1\xc1\a\xe6\xd6\x18\xe6path\tcommand-line-arguments\nmod\tcommand-line-arguments\t(devel)\t\n\xf92C1\x86\x18 r\x00\x82B\x10A\x16\xd8\xf2"
var keepalive_modinfo = __debug_modinfo__
func init() { keepalive_modinfo = __debug_modinfo__ }

３．新建importcfg
# import config
packagefile fmt=/usr/local/go/pkg/linux_amd64/fmt.a
packagefile runtime=/usr/local/go/pkg/linux_amd64/runtime.a

4. 进入compare_4.go代码目录
/usr/local/go/pkg/tool/linux_amd64/compile -o /tmp/test_self/_pkg_.a -importcfg /tmp/test_self/importcfg ./compare_4.go /tmp/test_self/_gomod_.go

```

找一下对应的`compile`代码

```sh
		
		/usr/local/go/src/cmd/compile/internal/gc/typecheck.go:773
		
		if !okfor[op][et] {
			yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
			n.Type = nil
			return n
		}

		// okfor allows any array == array, map == map, func == func.
		// restrict to slice/map/func == nil and nil == slice/map/func.
		if l.Type.IsArray() && !IsComparable(l.Type) {
			yyerror("invalid operation: %v (%v cannot be compared)", n, l.Type)
			n.Type = nil
			return n
		}

		if l.Type.IsSlice() && !l.isNil() && !r.isNil() {
			yyerror("invalid operation: %v (slice can only be compared to nil)", n)
			n.Type = nil
			return n
		}

		if l.Type.IsMap() && !l.isNil() && !r.isNil() {
			yyerror("invalid operation: %v (map can only be compared to nil)", n)
			n.Type = nil
			return n
		}

		if l.Type.Etype == TFUNC && !l.isNil() && !r.isNil() {
			yyerror("invalid operation: %v (func can only be compared to nil)", n)
			n.Type = nil
			return n
		}

		if l.Type.IsStruct() {
			if f := IncomparableField(l.Type); f != nil {
				yyerror("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
				n.Type = nil
				return n
			}
		}

```

相同类型中，`map`、`slice`、`func`是不可以与自身类型比较的 

对于`array`比较性来说，其元素不可以拥有`map、slice、func`等不可比较性的属性，否则也是不可以比较的；这种属性是在`IsComparable`里面递归检查的 

![compile](https://blog.hacking.pub/qiniu/compare_4.go/%E5%9B%BE%E8%A1%A81.png)