当前位置:网站首页>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()//对哈希中键的类型进行检查
......
}
typecheck
typecheck
typecheck1
func 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
typecheckas
case 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
}
typecheckas
func 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
TMAP
case 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语言底层原理剖析》
- 面向信仰编程-类型检查
边栏推荐
- MySQL transactions
- 手写柯里化 - toString 理解
- Getting started with Polkadot parachain development, this article is enough
- 攻防世界-PWN-new_easypwn
- SMB + SMB2: Accessing shares return an error after prolonged idle period
- Jenkins manual (2) - software configuration
- 百年北欧奢华家电品牌ASKO智能三温区酒柜臻献七夕,共品珍馐爱意
- Meteorological data processing example - matlab string cutting matching and R language date matching (data splicing)
- 茄子科技CEO仇俊:以用户为中心,做用户真正需要的产品
- Open Source Summer | How OpenHarmony Query Device Type (eTS)
猜你喜欢
three.js调试工具dat.gui使用
JS逆向入门学习之回收商网,手机号码简易加密解析
SD NAND Flash简介!
First Decentralized Heist?Loss of nearly 200 million US dollars: analysis of the attack on the cross-chain bridge Nomad
Pytorch深度学习快速入门教程 -- 土堆教程笔记(三)
一文道清什么是SPL
MySQL事务
three.js debugging tool dat.gui use
Introduction to SD NAND Flash!
JS introduction to reverse the recycling business network of learning, simple encryption mobile phone number
随机推荐
Handwriting Currying - toString Comprehension
js hijacks the array push method
Jenkins使用手册(2) —— 软件配置
DFINITY 基金会创始人谈熊市沉浮,DeFi 项目该何去何从
技术干货 | 基于 MindSpore 实现图像分割之豪斯多夫距离
你最隐秘的性格在哪?
为什么sys_class 里显示的很多表的 RELTABLESPACE 值为 0 ?
【温度预警程序de开发】事件驱动模型实例运用
SD NAND Flash简介!
IDEA执行Test操作导致数据插入时出现了重复数据
七夕浪漫约会不加班,RPA机器人帮你搞定工作
一文道清什么是SPL
Data Middle Office Construction (10): Data Security Management
[Android]如何使用RecycleView in Kotlin project
高质量 DeFi 应用构建指南,助力开发者玩转 DeFi Summer
Technical dry goods | Hausdorff distance for image segmentation based on MindSpore
How does the official account operate and maintain?Public account operation and maintenance professional team
Imitation SBUS fixed with serial data conversion
无题七
Offensive World-PWN-new_easypwn