当前位置:网站首页>Go编译原理系列6(类型检查)
Go编译原理系列6(类型检查)
2022-08-05 10:09:00 【InfoQ】
6. Go编译过程-类型检查
前言
- 常量、类型和函数名及类型验证
- 变量的赋值和初始化
- 计算编译时的常量、将声明与标识符绑定
- 会对一些内置函数进行改写(下边介绍源码时会提到)
- 哈希键值对的类型
- 做特别的语法或语义检查(引用的结构体字段是否是大写可导出的?数组字面量的访问是否超过了其长度?数组的索引是不是正整数?)
类型检查整体概览
var test int
test := 1
Go的编译入口文件:src/cmd/compile/main.go -> gc.Main(archInit)
func Main(archInit func(*Arch)) {
......
lines := parseFiles(flag.Args())//词法分析、语法分析、抽象语法树构建都在这里
......
//开始遍历抽象语法树,对每个结点进行类型检查
for i := 0; i < len(xtop); i++ {
n := xtop[i]
if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias()) {
xtop[i] = typecheck(n, ctxStmt)
}
}
for i := 0; i < len(xtop); i++ {
n := xtop[i]
if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias() {
xtop[i] = typecheck(n, ctxStmt)
}
}
......
checkMapKeys()//对哈希中键的类型进行检查
......
}
typechecktypechecktypecheck1func typecheck1(n *Node, top int) (res *Node) {
......
switch n.Op {
// until typecheck is complete, do nothing.
default:
Dump("typecheck", n)
Fatalf("typecheck %v", n.Op)
// names
case OLITERAL:
ok |= ctxExpr
if n.Type == nil && n.Val().Ctype() == CTSTR {
n.Type = types.UntypedString
}
case ONONAME:
ok |= ctxExpr
case ONAME:
......
case OTARRAY:
......
case OTMAP:
......
}
......
}
深入了解类型检查
OAS:赋值语句
// Left = Right or (if Colas=true) Left := Right
// If Colas, then Ninit includes a DCL node for Left.
OAS
typecheckascase OAS:
ok |= ctxStmt
typecheckas(n)
// Code that creates temps does not bother to set defn, so do it here.
if n.Left.Op == ONAME && n.Left.IsAutoTmp() {
n.Left.Name.Defn = n
}
typecheckasfunc typecheckas(n *Node) {
......
if n.Left.Name != nil && n.Left.Name.Defn == n && n.Left.Name.Param.Ntype == nil {
n.Right = defaultlit(n.Right, nil)
n.Left.Type = n.Right.Type
}
......
}
OTARRAY:切片
OTARRAY // []int, [8]int, [N]int or [...]int
case OTARRAY:
ok |= ctxType
r := typecheck(n.Right, ctxType)
if r.Type == nil {
n.Type = nil
return n
}
- []int:直接调用
t = types.NewSlice(r.Type),返回了一个 TSLICE 类型的结构体,元素的类型信息也会存储在结构体中
- [...]int:交由
typecheckcomplit方法处理,
func typecheckcomplit(n *Node) (res *Node) {
......
// Need to handle [...]T arrays specially.
if n.Right.Op == OTARRAY && n.Right.Left != nil && n.Right.Left.Op == ODDD {
n.Right.Right = typecheck(n.Right.Right, ctxType)
if n.Right.Right.Type == nil {
n.Type = nil
return n
}
elemType := n.Right.Right.Type
length := typecheckarraylit(elemType, -1, n.List.Slice(), "array literal")
n.Op = OARRAYLIT
n.Type = types.NewArray(elemType, length)
n.Right = nil
return n
}
......
}
[types.NewArray](https://draveness.me/golang/tree/cmd/compile/internal/types.NewArray)- [6]int:如果在声明切片时,带了数组的大小,则直接调用
[types.NewArray](https://draveness.me/golang/tree/cmd/compile/internal/types.NewArray) 初始化一个存储着数组中元素类型和数组大小的结构体
setTypeNode(n, t)
n.Left = nil
n.Right = nil
checkwidth(t)
OTMAP:map(哈希)
OTMAP // map[string]int
TMAPcase OTMAP:
ok |= ctxType
n.Left = typecheck(n.Left, ctxType)
n.Right = typecheck(n.Right, ctxType)
l := n.Left
r := n.Right
if l.Type == nil || r.Type == nil {
n.Type = nil
return n
}
if l.Type.NotInHeap() {
yyerror("incomplete (or unallocatable) map key not allowed")
}
if r.Type.NotInHeap() {
yyerror("incomplete (or unallocatable) map value not allowed")
}
setTypeNode(n, types.NewMap(l.Type, r.Type))
mapqueue = append(mapqueue, n) // check map keys when all types are settled
n.Left = nil
n.Right = nil
......
func NewMap(k, v *Type) *Type {
t := New(TMAP)
mt := t.MapType()
mt.Key = k
mt.Elem = v
return t
}
func checkMapKeys() {
for _, n := range mapqueue {
k := n.Type.MapType().Key
if !k.Broke() && !IsComparable(k) {
yyerrorl(n.Pos, "invalid map key type %v", k)
}
}
mapqueue = nil
}
OMAKE:make
OMAKE // make(List) (before type checking converts to one of the following)
OMAKECHAN // make(Type, Left) (type is chan)
OMAKEMAP // make(Type, Left) (type is map)
OMAKESLICE // make(Type, Left, Right) (type is slice)
make slice:OMAKESLICE
make map:OMAKEMAP
make chan:OMAKECHAN
case OMAKE:
ok |= ctxExpr
args := n.List.Slice()
......
l := args[0]
l = typecheck(l, ctxType)
t := l.Type
......
i := 1
switch t.Etype {
default:
yyerror("cannot make type %v", t)
n.Type = nil
return n
case TSLICE:
......
n.Left = l
n.Right = r
n.Op = OMAKESLICE
case TMAP:
......
n.Op = OMAKEMAP
case TCHAN:
......
n.Op = OMAKECHAN
}
n.Type = t
- 如果第一个参数是切片类型:获取切片的长度(len)和容量(cap),然后对len和cap进行合法性校验。并且改写了节点的类型
- 如果第一个参数是map类型:获取make的第二个参数,如果没有,则默认设置为0(map的大小)。并且改写节点的类型
- 如果第一个参数是chan类型:获取make的第二个参数,如果没有,则默认设置为0(chan的缓冲区大小)。并且改写节点的类型
总结
参考
- go-ast-book
- 《Go语言底层原理剖析》
- 面向信仰编程-类型检查
边栏推荐
- Complete image segmentation efficiently based on MindSpore and realize Dice!
- Redis源码解析:Redis Cluster
- mysql进阶(二十七)数据库索引原理
- 哪位大佬有20年4月或者1月的11G GI和ojvm补丁呀,帮忙发下?
- Can MySQL use aggregate functions without GROUP BY?
- 多线程(进阶) - 2.5w字总结
- C语言的高级用法
- 皕杰报表的下拉框联动
- The difference between find, matches, lookingAt matching strings in matcher
- 第三章 : redis数据结构种类
猜你喜欢

2022 Huashu Cup Mathematical Modeling Question A Optimization Design Ideas for Ring Oscillators Code Sharing

19.服务器端会话技术Session

mysql进阶(二十七)数据库索引原理

The technological achievements of Shanghai Konan were selected into the "2021 Shanghai Network Security Industry Innovation Research Achievement Catalog" by the Municipal Commission of Economy and Inf

一文道清什么是SPL

Seata source code analysis: initialization process of TM RM client

什么是CRM决策分析管理?

egg框架使用(一)

Oracle temporary table space role

项目成本控制如何帮助项目成功?
随机推荐
19.服务器端会话技术Session
What is the function of the regular expression replaceFirst() method?
什么是CRM决策分析管理?
[强网杯2022]WP-UM
七夕浪漫约会不加班,RPA机器人帮你搞定工作
告白数字化转型时代:麦聪软件以最简单的方式让企业把数据用起来
无题五
入门 Polkadot 平行链开发,看这一篇就够了
Analysis and practice of antjian webshell dynamic encrypted connection
Four years of weight loss record
NowCoderTOP35-40——持续更新ing
Bias lock/light lock/heavy lock lock is healthier. How is locking and unlocking accomplished?
STM32+ULN2003 drives 28BYJ4 stepper motor (forward and reverse according to the number of turns)
你最隐秘的性格在哪?
ffmpeg drawtext 添加文本水印
Confessing in the era of digital transformation: Mai Cong Software allows enterprises to use data in the easiest way
华为轻量级神经网络架构GhostNet再升级,GPU上大显身手的G-GhostNet(IJCV22)
高质量 DeFi 应用构建指南,助力开发者玩转 DeFi Summer
茄子科技CEO仇俊:以用户为中心,做用户真正需要的产品
Introduction to SD NAND Flash!