fix: iterate on global type analyis when necessary (#335)

This commit is contained in:
Marc Vertes
2019-08-22 17:36:23 +02:00
committed by Ludovic Fernandez
parent a4e15d7788
commit 869b6d2850
12 changed files with 115 additions and 13 deletions

View File

@@ -13,3 +13,6 @@ func (*Hello) Hi() string {
func main() {
fmt.Println(&Hello{})
}
// Output:
// &{}

19
_test/method22.go Normal file
View 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
View 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

View File

@@ -13,3 +13,6 @@ type S2 struct {
func main() {
fmt.Println(S2{})
}
// Output:
// {<nil>}

View File

@@ -21,3 +21,6 @@ func (w GzipResponseWriterWithCloseNotify) CloseNotify() <-chan bool {
func main() {
fmt.Println("hello")
}
// Output:
// hello

View File

@@ -21,3 +21,6 @@ func main() {
c := CreateConfig()
fmt.Println(c)
}
// Output:
// &{[] false }

View File

@@ -25,3 +25,6 @@ func main() {
t := &T1{}
println(t.Get())
}
// Output:
// no name

12
_test/type13.go Normal file
View 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
View File

@@ -0,0 +1,14 @@
package main
import "fmt"
var a = T{}
type T struct{}
func main() {
fmt.Println(a)
}
// Output:
// {}

View File

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

View File

@@ -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)

View File

@@ -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