从compare_4.go初识go的typecheck

主要是上一次的题目的第四道

上次compare梳理了 go buildcompile之前的准备工作,比如收集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")
    }
}

可以看到终端输出:

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工具(子进程),那么手动模拟一下编译过程  

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__ }

3.新建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代码

        /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
            }
        }

相同类型中,mapslicefunc是不可以与自身类型比较的  

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

compile