interp: make use of type constructors

It was initially assumed that `nodeType` needed to rebuild the type from scratch, but this is not the case anymore. The existing type constructors are now used in `nodeType` to make it more readable. In doing this some bugs in type strings were found and fixed, along with adding the real package name to the type.

As `ptrOf` is now the only place that pointer types are constructed, it is feasible to cache the pointer type on the value type. To ensures that we have a consistent pointer type for any value type.
This commit is contained in:
Nicholas Wiersma
2021-08-31 04:34:12 -04:00
committed by GitHub
parent 4af992bccb
commit 772cd68fea
4 changed files with 37 additions and 45 deletions

View File

@@ -11,7 +11,7 @@ import (
// All function bodies are skipped. GTA is necessary to handle out of // All function bodies are skipped. GTA is necessary to handle out of
// order declarations and multiple source files packages. // order declarations and multiple source files packages.
// rpath is the relative path to the directory containing the source for the package. // rpath is the relative path to the directory containing the source for the package.
func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, error) { func (interp *Interpreter) gta(root *node, rpath, importPath, pkgName string) ([]*node, error) {
sc := interp.initScopePkg(importPath) sc := interp.initScopePkg(importPath)
var err error var err error
var revisit []*node var revisit []*node
@@ -266,14 +266,14 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
switch n.child[1].kind { switch n.child[1].kind {
case identExpr, selectorExpr: case identExpr, selectorExpr:
n.typ = namedOf(typ, importPath, typeName, withNode(n.child[0]), withScope(sc)) n.typ = namedOf(typ, pkgName, typeName, withNode(n.child[0]), withScope(sc))
n.typ.incomplete = typ.incomplete n.typ.incomplete = typ.incomplete
n.typ.field = typ.field n.typ.field = typ.field
copy(n.typ.method, typ.method) copy(n.typ.method, typ.method)
default: default:
n.typ = typ n.typ = typ
n.typ.name = typeName n.typ.name = typeName
n.typ.path = importPath n.typ.path = pkgName
} }
n.typ.str = n.typ.path + "." + n.typ.name n.typ.str = n.typ.path + "." + n.typ.name
@@ -312,11 +312,11 @@ func (interp *Interpreter) gta(root *node, rpath, importPath string) ([]*node, e
} }
// gtaRetry (re)applies gta until all global constants and types are defined. // gtaRetry (re)applies gta until all global constants and types are defined.
func (interp *Interpreter) gtaRetry(nodes []*node, importPath string) error { func (interp *Interpreter) gtaRetry(nodes []*node, importPath, pkgName string) error {
revisit := []*node{} revisit := []*node{}
for { for {
for _, n := range nodes { for _, n := range nodes {
list, err := interp.gta(n, importPath, importPath) list, err := interp.gta(n, importPath, importPath, pkgName)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -537,7 +537,7 @@ func (interp *Interpreter) eval(src, name string, inc bool) (res reflect.Value,
} }
// Perform global types analysis. // Perform global types analysis.
if err = interp.gtaRetry([]*node{root}, pkgName); err != nil { if err = interp.gtaRetry([]*node{root}, pkgName, pkgName); err != nil {
return res, err return res, err
} }

View File

@@ -97,7 +97,7 @@ func (interp *Interpreter) importSrc(rPath, importPath string, skipTest bool) (s
subRPath := effectivePkg(rPath, importPath) subRPath := effectivePkg(rPath, importPath)
var list []*node var list []*node
list, err = interp.gta(root, subRPath, importPath) list, err = interp.gta(root, subRPath, importPath, pkgName)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -106,7 +106,7 @@ func (interp *Interpreter) importSrc(rPath, importPath string, skipTest bool) (s
// Revisit incomplete nodes where GTA could not complete. // Revisit incomplete nodes where GTA could not complete.
for _, nodes := range revisit { for _, nodes := range revisit {
if err = interp.gtaRetry(nodes, importPath); err != nil { if err = interp.gtaRetry(nodes, importPath, pkgName); err != nil {
return "", err return "", err
} }
} }

View File

@@ -118,6 +118,7 @@ type itype struct {
recv *itype // Receiver type for funcT or nil recv *itype // Receiver type for funcT or nil
arg []*itype // Argument types if funcT or nil arg []*itype // Argument types if funcT or nil
ret []*itype // Return types if funcT or nil ret []*itype // Return types if funcT or nil
ptr *itype // Pointer to this type. Might be nil
method []*node // Associated methods or nil method []*node // Associated methods or nil
name string // name of type within its package for a defined type name string // name of type within its package for a defined type
path string // for a defined type, the package import path path string // for a defined type, the package import path
@@ -215,10 +216,14 @@ func wrapperValueTOf(rtype reflect.Type, val *itype, opts ...itypeOption) *itype
// ptrOf returns a pointer to t. // ptrOf returns a pointer to t.
func ptrOf(val *itype, opts ...itypeOption) *itype { func ptrOf(val *itype, opts ...itypeOption) *itype {
if val.ptr != nil {
return val.ptr
}
t := &itype{cat: ptrT, val: val, str: "*" + val.str} t := &itype{cat: ptrT, val: val, str: "*" + val.str}
for _, opt := range opts { for _, opt := range opts {
opt(t) opt(t)
} }
val.ptr = t
return t return t
} }
@@ -255,7 +260,7 @@ func chanOf(val *itype, dir chanDir, opts ...itypeOption) *itype {
cat = chanRecvT cat = chanRecvT
str = "<-chan " str = "<-chan "
} }
t := &itype{cat: cat, val: val, str: str} t := &itype{cat: cat, val: val, str: str + val.str}
for _, opt := range opts { for _, opt := range opts {
opt(t) opt(t)
} }
@@ -298,25 +303,22 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
var err error var err error
switch n.kind { switch n.kind {
case addressExpr, starExpr: case addressExpr, starExpr:
t.cat = ptrT val, err := nodeType(interp, sc, n.child[0])
if t.val, err = nodeType(interp, sc, n.child[0]); err != nil { if err != nil {
return nil, err return nil, err
} }
repr.WriteString("*" + t.val.str) t = ptrOf(val, withNode(n), withScope(sc))
t.incomplete = t.val.incomplete t.incomplete = val.incomplete
case arrayType: case arrayType:
c0 := n.child[0] c0 := n.child[0]
if len(n.child) == 1 { if len(n.child) == 1 {
// Array size is not defined. val, err := nodeType(interp, sc, c0)
t.cat = sliceT if err != nil {
if t.val, err = nodeType(interp, sc, c0); err != nil {
return nil, err return nil, err
} }
t.incomplete = t.val.incomplete t = sliceOf(val, withNode(n), withScope(sc))
if t.val != nil { t.incomplete = val.incomplete
repr.WriteString("[]" + t.val.str)
}
break break
} }
// Array size is defined. // Array size is defined.
@@ -526,29 +528,20 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
case compositeLitExpr: case compositeLitExpr:
t, err = nodeType(interp, sc, n.child[0]) t, err = nodeType(interp, sc, n.child[0])
case chanType: case chanType, chanTypeRecv, chanTypeSend:
t.cat = chanT dir := chanSendRecv
if t.val, err = nodeType(interp, sc, n.child[0]); err != nil { switch n.kind {
return nil, err
}
repr.WriteString("chan " + t.val.str)
t.incomplete = t.val.incomplete
case chanTypeRecv: case chanTypeRecv:
t.cat = chanRecvT dir = chanRecv
if t.val, err = nodeType(interp, sc, n.child[0]); err != nil {
return nil, err
}
repr.WriteString("<-chan " + t.val.str)
t.incomplete = t.val.incomplete
case chanTypeSend: case chanTypeSend:
t.cat = chanSendT dir = chanSend
if t.val, err = nodeType(interp, sc, n.child[0]); err != nil { }
val, err := nodeType(interp, sc, n.child[0])
if err != nil {
return nil, err return nil, err
} }
repr.WriteString("chan<- " + t.val.str) t = chanOf(val, dir, withNode(n), withScope(sc))
t.incomplete = t.val.incomplete t.incomplete = val.incomplete
case ellipsisExpr: case ellipsisExpr:
t.cat = variadicT t.cat = variadicT
@@ -690,7 +683,6 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
return nil, err return nil, err
} }
t.field = append(t.field, structField{name: f0.ident, typ: typ}) t.field = append(t.field, structField{name: f0.ident, typ: typ})
repr.WriteString(" " + f0.ident + typ.str[4:])
incomplete = incomplete || typ.incomplete incomplete = incomplete || typ.incomplete
} }
methStr := methodsTypeString(t.field) methStr := methodsTypeString(t.field)