fix: iterate on global type analyis when necessary (#335)
This commit is contained in:
committed by
Ludovic Fernandez
parent
a4e15d7788
commit
869b6d2850
@@ -13,3 +13,6 @@ func (*Hello) Hi() string {
|
||||
func main() {
|
||||
fmt.Println(&Hello{})
|
||||
}
|
||||
|
||||
// Output:
|
||||
// &{}
|
||||
|
||||
19
_test/method22.go
Normal file
19
_test/method22.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
func Bar() {
|
||||
s := Obj.Foo()
|
||||
println(s)
|
||||
}
|
||||
|
||||
var Obj = &T{}
|
||||
|
||||
type T struct{}
|
||||
|
||||
func (t *T) Foo() bool { return t != nil }
|
||||
|
||||
func main() {
|
||||
Bar()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
21
_test/method23.go
Normal file
21
_test/method23.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
func Bar() {
|
||||
s := Obj.Foo()
|
||||
println(s)
|
||||
}
|
||||
|
||||
var Obj = NewT()
|
||||
|
||||
func NewT() *T { return &T{} }
|
||||
|
||||
type T struct{}
|
||||
|
||||
func (t *T) Foo() bool { return t != nil }
|
||||
|
||||
func main() {
|
||||
Bar()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
@@ -13,3 +13,6 @@ type S2 struct {
|
||||
func main() {
|
||||
fmt.Println(S2{})
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {<nil>}
|
||||
|
||||
@@ -21,3 +21,6 @@ func (w GzipResponseWriterWithCloseNotify) CloseNotify() <-chan bool {
|
||||
func main() {
|
||||
fmt.Println("hello")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
|
||||
@@ -21,3 +21,6 @@ func main() {
|
||||
c := CreateConfig()
|
||||
fmt.Println(c)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// &{[] false }
|
||||
|
||||
@@ -25,3 +25,6 @@ func main() {
|
||||
t := &T1{}
|
||||
println(t.Get())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// no name
|
||||
|
||||
12
_test/type13.go
Normal file
12
_test/type13.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
var a = &T{}
|
||||
|
||||
type T struct{}
|
||||
|
||||
func main() {
|
||||
println(a != nil)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
14
_test/type14.go
Normal file
14
_test/type14.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var a = T{}
|
||||
|
||||
type T struct{}
|
||||
|
||||
func main() {
|
||||
fmt.Println(a)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {}
|
||||
@@ -9,10 +9,11 @@ import (
|
||||
// variables and functions symbols at package level, prior to CFG.
|
||||
// All function bodies are skipped. GTA is necessary to handle out of
|
||||
// order declarations and multiple source files packages.
|
||||
func (interp *Interpreter) gta(root *node, rpath string) error {
|
||||
func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
sc, _ := interp.initScopePkg(root)
|
||||
var err error
|
||||
var iotaValue int
|
||||
var revisit []*node
|
||||
|
||||
root.Walk(func(n *node) bool {
|
||||
if err != nil {
|
||||
@@ -42,23 +43,24 @@ func (interp *Interpreter) gta(root *node, rpath string) error {
|
||||
|
||||
for i := 0; i < n.nleft; i++ {
|
||||
dest, src := n.child[i], n.child[sbase+i]
|
||||
typ := atyp
|
||||
val := reflect.ValueOf(iotaValue)
|
||||
typ := atyp
|
||||
if typ == nil {
|
||||
if typ, err = nodeType(interp, sc, src); err != nil {
|
||||
return false
|
||||
}
|
||||
val = src.rval
|
||||
}
|
||||
var index int
|
||||
if !typ.incomplete {
|
||||
if typ.cat == nilT {
|
||||
err = n.cfgErrorf("use of untyped nil")
|
||||
return false
|
||||
}
|
||||
index = sc.add(typ)
|
||||
if typ.incomplete {
|
||||
// Come back when type is known
|
||||
revisit = append(revisit, n)
|
||||
return false
|
||||
}
|
||||
sc.sym[dest.ident] = &symbol{kind: varSym, global: true, index: index, typ: typ, rval: val}
|
||||
if typ.cat == nilT {
|
||||
err = n.cfgErrorf("use of untyped nil")
|
||||
return false
|
||||
}
|
||||
sc.sym[dest.ident] = &symbol{kind: varSym, global: true, index: sc.add(typ), typ: typ, rval: val}
|
||||
if n.anc.kind == constDecl {
|
||||
sc.sym[dest.ident].kind = constSym
|
||||
iotaValue++
|
||||
@@ -171,5 +173,5 @@ func (interp *Interpreter) gta(root *node, rpath string) error {
|
||||
if sc != interp.universe {
|
||||
sc.pop()
|
||||
}
|
||||
return err
|
||||
return revisit, err
|
||||
}
|
||||
|
||||
@@ -245,9 +245,15 @@ func (interp *Interpreter) Eval(src string) (reflect.Value, error) {
|
||||
}
|
||||
|
||||
// Global type analysis
|
||||
if err = interp.gta(root, pkgName); err != nil {
|
||||
revisit, err := interp.gta(root, pkgName)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
for _, n := range revisit {
|
||||
if _, err = interp.gta(n, pkgName); err != nil {
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
|
||||
// Annotate AST with CFG infos
|
||||
initNodes, err := interp.cfg(root)
|
||||
|
||||
@@ -33,6 +33,7 @@ func (interp *Interpreter) importSrcFile(rPath, path, alias string) error {
|
||||
|
||||
var initNodes []*node
|
||||
var rootNodes []*node
|
||||
revisit := make(map[string][]*node)
|
||||
|
||||
var root *node
|
||||
var pkgName string
|
||||
@@ -65,9 +66,21 @@ func (interp *Interpreter) importSrcFile(rPath, path, alias string) error {
|
||||
rootNodes = append(rootNodes, root)
|
||||
|
||||
subRPath := effectivePkg(rPath, path)
|
||||
if err = interp.gta(root, subRPath); err != nil {
|
||||
var list []*node
|
||||
list, err = interp.gta(root, subRPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
revisit[subRPath] = append(revisit[subRPath], list...)
|
||||
}
|
||||
|
||||
// revisit incomplete nodes where GTA could not complete
|
||||
for pkg, nodes := range revisit {
|
||||
for _, n := range nodes {
|
||||
if _, err = interp.gta(n, pkg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate control flow graphs
|
||||
|
||||
Reference in New Issue
Block a user