fix: improve handling of out of order declarations (#344)
This commit is contained in:
committed by
Ludovic Fernandez
parent
d23a7e1d8b
commit
b0937618b0
21
_test/fun6.go
Normal file
21
_test/fun6.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func NewPool() Pool { return Pool{} }
|
||||
|
||||
type Pool struct {
|
||||
p *sync.Pool
|
||||
}
|
||||
|
||||
var _pool = NewPool()
|
||||
|
||||
func main() {
|
||||
fmt.Println(_pool)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {<nil>}
|
||||
33
_test/method25.go
Normal file
33
_test/method25.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func (p Pool) Get() *Buffer { return &Buffer{} }
|
||||
|
||||
func NewPool() Pool { return Pool{} }
|
||||
|
||||
type Buffer struct {
|
||||
bs []byte
|
||||
pool Pool
|
||||
}
|
||||
|
||||
type Pool struct {
|
||||
p *sync.Pool
|
||||
}
|
||||
|
||||
var (
|
||||
_pool = NewPool()
|
||||
Get = _pool.Get
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(_pool)
|
||||
fmt.Println(Get())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {<nil>}
|
||||
// &{[] {<nil>}}
|
||||
18
_test/method26.go
Normal file
18
_test/method26.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
func NewT(name string) *T { return &T{name} }
|
||||
|
||||
var C = NewT("test")
|
||||
|
||||
func (t *T) f() { println(t == C) }
|
||||
|
||||
type T struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func main() {
|
||||
C.f()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
20
_test/struct26.go
Normal file
20
_test/struct26.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func newT2() *T2 { return &T2{} }
|
||||
|
||||
type T2 struct {
|
||||
T1
|
||||
}
|
||||
|
||||
type T1 struct {
|
||||
bs []byte
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println(newT2())
|
||||
}
|
||||
|
||||
// Output:
|
||||
// &{{[]}}
|
||||
18
_test/struct27.go
Normal file
18
_test/struct27.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func (f *Foo) Boo() { fmt.Println(f.name, "Boo") }
|
||||
|
||||
type Foo struct {
|
||||
name string
|
||||
fun func(f *Foo)
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := &Foo{name: "foo"}
|
||||
t.Boo()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// foo Boo
|
||||
19
_test/struct28.go
Normal file
19
_test/struct28.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type T1 struct {
|
||||
T2
|
||||
}
|
||||
|
||||
type T2 struct {
|
||||
*T1
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := T1{}
|
||||
fmt.Println(t)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// {{<nil>}}
|
||||
@@ -355,6 +355,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
if atyp != nil {
|
||||
dest.typ = atyp
|
||||
} else {
|
||||
if src.typ, err = nodeType(interp, sc, src); err != nil {
|
||||
return
|
||||
}
|
||||
dest.typ = src.typ
|
||||
}
|
||||
if dest.typ.sizedef {
|
||||
|
||||
@@ -79,41 +79,36 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
if n.typ, err = nodeType(interp, sc, n.child[2]); err != nil {
|
||||
return false
|
||||
}
|
||||
if !isMethod(n) {
|
||||
sc.sym[n.child[1].ident] = &symbol{kind: funcSym, typ: n.typ, node: n, index: -1}
|
||||
}
|
||||
if len(n.child[0].child) > 0 {
|
||||
// function is a method, add it to the related type
|
||||
if isMethod(n) {
|
||||
// Add a method symbol in the receiver type name space
|
||||
var rcvrtype *itype
|
||||
var typeName string
|
||||
n.ident = n.child[1].ident
|
||||
rcvr := n.child[0].child[0]
|
||||
if len(rcvr.child) < 2 {
|
||||
// Receiver var name is skipped in method declaration (fix that in AST ?)
|
||||
typeName = rcvr.child[0].ident
|
||||
} else {
|
||||
typeName = rcvr.child[1].ident
|
||||
}
|
||||
rtn := rcvr.lastChild()
|
||||
typeName := rtn.ident
|
||||
if typeName == "" {
|
||||
// The receiver is a pointer, retrieve typeName from indirection
|
||||
typeName = rcvr.lastChild().child[0].ident
|
||||
typeName = rtn.child[0].ident
|
||||
elementType := sc.getType(typeName)
|
||||
if elementType == nil {
|
||||
// Add type if necessary, so method can be registered
|
||||
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, pkgPath: rpath}}
|
||||
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, pkgPath: rpath, incomplete: true, node: rtn.child[0], scope: sc}}
|
||||
elementType = sc.sym[typeName].typ
|
||||
}
|
||||
rcvrtype = &itype{cat: ptrT, val: elementType}
|
||||
rcvrtype = &itype{cat: ptrT, val: elementType, incomplete: elementType.incomplete, node: rtn, scope: sc}
|
||||
elementType.method = append(elementType.method, n)
|
||||
} else {
|
||||
rcvrtype = sc.getType(typeName)
|
||||
if rcvrtype == nil {
|
||||
// Add type if necessary, so method can be registered
|
||||
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, pkgPath: rpath}}
|
||||
sc.sym[typeName] = &symbol{kind: typeSym, typ: &itype{name: typeName, pkgPath: rpath, incomplete: true, node: rtn, scope: sc}}
|
||||
rcvrtype = sc.sym[typeName].typ
|
||||
}
|
||||
}
|
||||
rcvrtype.method = append(rcvrtype.method, n)
|
||||
} else {
|
||||
// Add a function symbol in the package name space
|
||||
sc.sym[n.child[1].ident] = &symbol{kind: funcSym, typ: n.typ, node: n, index: -1}
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -165,6 +160,9 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
n.typ.method = append(n.typ.method, sc.sym[typeName].typ.method...)
|
||||
}
|
||||
sc.sym[typeName].typ = n.typ
|
||||
if n.typ.incomplete {
|
||||
revisit = append(revisit, n)
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -198,12 +198,12 @@ func convert(n *node) {
|
||||
}
|
||||
}
|
||||
|
||||
func isRecursiveStruct(t *itype) bool {
|
||||
if t.cat == structT && t.rtype.Kind() == reflect.Interface {
|
||||
func isRecursiveStruct(t *itype, rtype reflect.Type) bool {
|
||||
if t.cat == structT && rtype.Kind() == reflect.Interface {
|
||||
return true
|
||||
}
|
||||
if t.cat == ptrT {
|
||||
return isRecursiveStruct(t.val)
|
||||
return isRecursiveStruct(t.val, t.rtype.Elem())
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -230,7 +230,7 @@ func assign(n *node) {
|
||||
case src.kind == basicLit && src.val == nil:
|
||||
t := dest.typ.TypeOf()
|
||||
svalue[i] = func(*frame) reflect.Value { return reflect.New(t).Elem() }
|
||||
case isRecursiveStruct(dest.typ):
|
||||
case isRecursiveStruct(dest.typ, dest.typ.rtype):
|
||||
svalue[i] = genValueInterfacePtr(src)
|
||||
default:
|
||||
svalue[i] = genValue(src)
|
||||
@@ -1087,7 +1087,7 @@ func getPtrIndexSeq(n *node) {
|
||||
index := n.val.([]int)
|
||||
tnext := getExec(n.tnext)
|
||||
var value func(*frame) reflect.Value
|
||||
if isRecursiveStruct(n.child[0].typ) {
|
||||
if isRecursiveStruct(n.child[0].typ, n.child[0].typ.rtype) {
|
||||
v := genValue(n.child[0])
|
||||
value = func(f *frame) reflect.Value { return v(f).Elem().Elem() }
|
||||
} else {
|
||||
@@ -1727,7 +1727,7 @@ func _append(n *node) {
|
||||
values := make([]func(*frame) reflect.Value, l)
|
||||
for i, arg := range args {
|
||||
switch {
|
||||
case isRecursiveStruct(n.typ.val):
|
||||
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
|
||||
values[i] = genValueInterfacePtr(arg)
|
||||
case arg.typ.untyped:
|
||||
values[i] = genValueAs(arg, n.child[1].typ.TypeOf().Elem())
|
||||
@@ -1747,7 +1747,7 @@ func _append(n *node) {
|
||||
} else {
|
||||
var value0 func(*frame) reflect.Value
|
||||
switch {
|
||||
case isRecursiveStruct(n.typ.val):
|
||||
case isRecursiveStruct(n.typ.val, n.typ.val.rtype):
|
||||
value0 = genValueInterfacePtr(n.child[2])
|
||||
case n.child[2].typ.untyped:
|
||||
value0 = genValueAs(n.child[2], n.child[1].typ.TypeOf().Elem())
|
||||
|
||||
@@ -44,17 +44,16 @@ func (k sKind) String() string {
|
||||
// A symbol represents an interpreter object such as type, constant, var, func,
|
||||
// label, builtin or binary object. Symbols are defined within a scope.
|
||||
type symbol struct {
|
||||
kind sKind
|
||||
typ *itype // Type of value
|
||||
node *node // Node value if index is negative
|
||||
from []*node // list of nodes jumping to node if kind is label, or nil
|
||||
recv *receiver // receiver node value, if sym refers to a method
|
||||
index int // index of value in frame or -1
|
||||
rval reflect.Value // default value (used for constants)
|
||||
path string // package path if typ.cat is SrcPkgT or BinPkgT
|
||||
builtin bltnGenerator // Builtin function or nil
|
||||
global bool // true if symbol is defined in global space
|
||||
recursive bool // true if symbol is a recursive type definition
|
||||
kind sKind
|
||||
typ *itype // Type of value
|
||||
node *node // Node value if index is negative
|
||||
from []*node // list of nodes jumping to node if kind is label, or nil
|
||||
recv *receiver // receiver node value, if sym refers to a method
|
||||
index int // index of value in frame or -1
|
||||
rval reflect.Value // default value (used for constants)
|
||||
path string // package path if typ.cat is SrcPkgT or BinPkgT
|
||||
builtin bltnGenerator // Builtin function or nil
|
||||
global bool // true if symbol is defined in global space
|
||||
// TODO: implement constant checking
|
||||
//constant bool // true if symbol value is constant
|
||||
}
|
||||
|
||||
@@ -130,6 +130,16 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
|
||||
var t = &itype{node: n, scope: sc}
|
||||
|
||||
if n.anc.kind == typeSpec {
|
||||
name := n.anc.child[0].ident
|
||||
if sym := sc.sym[name]; sym != nil {
|
||||
// recover previously declared methods
|
||||
t.method = sym.typ.method
|
||||
t.pkgPath = sym.typ.pkgPath
|
||||
t.name = name
|
||||
}
|
||||
}
|
||||
|
||||
switch n.kind {
|
||||
case addressExpr, starExpr:
|
||||
t.cat = ptrT
|
||||
@@ -314,11 +324,6 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
case identExpr:
|
||||
if sym, _, found := sc.lookup(n.ident); found {
|
||||
t = sym.typ
|
||||
if sym.recursive && t.incomplete {
|
||||
t.incomplete = false
|
||||
t.rtype = reflect.TypeOf((*interface{})(nil)).Elem()
|
||||
sym.typ = t
|
||||
}
|
||||
if t.incomplete && t.node != n {
|
||||
m := t.method
|
||||
if t, err = nodeType(interp, sc, t.node); err != nil {
|
||||
@@ -416,7 +421,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
var sym *symbol
|
||||
if sname := structName(n); sname != "" {
|
||||
if sym, _, found = sc.lookup(sname); found && sym.kind == typeSym {
|
||||
sym.recursive = true
|
||||
sym.typ = t
|
||||
}
|
||||
}
|
||||
for _, c := range n.child[0].child {
|
||||
@@ -460,7 +465,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
}
|
||||
|
||||
if t.cat == nilT && !t.incomplete {
|
||||
err = n.cfgErrorf("use of untyped nil")
|
||||
err = n.cfgErrorf("use of untyped nil %s", t.name)
|
||||
}
|
||||
|
||||
return t, err
|
||||
@@ -517,15 +522,23 @@ func init() {
|
||||
func (t *itype) finalize() (*itype, error) {
|
||||
var err cfgError
|
||||
if t.incomplete {
|
||||
sym, _, found := t.scope.lookup(t.name)
|
||||
if found && !sym.typ.incomplete {
|
||||
sym.typ.method = append(sym.typ.method, t.method...)
|
||||
return sym.typ, nil
|
||||
}
|
||||
m := t.method
|
||||
if t, err = nodeType(t.node.interp, t.scope, t.node); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if t.incomplete {
|
||||
return nil, t.node.cfgErrorf("incomplete type")
|
||||
return nil, t.node.cfgErrorf("incomplete type %s", t.name)
|
||||
}
|
||||
t.method = m
|
||||
t.node.typ = t
|
||||
if sym != nil {
|
||||
sym.typ = t
|
||||
}
|
||||
}
|
||||
return t, err
|
||||
}
|
||||
@@ -691,7 +704,7 @@ func exportName(s string) string {
|
||||
}
|
||||
|
||||
// TypeOf returns the reflection type of dynamic interpreter type t.
|
||||
func (t *itype) TypeOf() reflect.Type {
|
||||
func (t *itype) Type(name string) reflect.Type {
|
||||
if t.rtype != nil {
|
||||
return t.rtype
|
||||
}
|
||||
@@ -702,26 +715,29 @@ func (t *itype) TypeOf() reflect.Type {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
if name == "" {
|
||||
name = t.name
|
||||
}
|
||||
|
||||
switch t.cat {
|
||||
case arrayT:
|
||||
if t.size > 0 {
|
||||
t.rtype = reflect.ArrayOf(t.size, t.val.TypeOf())
|
||||
t.rtype = reflect.ArrayOf(t.size, t.val.Type(name))
|
||||
} else {
|
||||
t.rtype = reflect.SliceOf(t.val.TypeOf())
|
||||
t.rtype = reflect.SliceOf(t.val.Type(name))
|
||||
}
|
||||
case chanT:
|
||||
t.rtype = reflect.ChanOf(reflect.BothDir, t.val.TypeOf())
|
||||
t.rtype = reflect.ChanOf(reflect.BothDir, t.val.Type(name))
|
||||
case errorT:
|
||||
t.rtype = reflect.TypeOf(new(error)).Elem()
|
||||
case funcT:
|
||||
in := make([]reflect.Type, len(t.arg))
|
||||
out := make([]reflect.Type, len(t.ret))
|
||||
for i, v := range t.arg {
|
||||
in[i] = v.TypeOf()
|
||||
in[i] = v.Type(name)
|
||||
}
|
||||
for i, v := range t.ret {
|
||||
out[i] = v.TypeOf()
|
||||
out[i] = v.Type(name)
|
||||
}
|
||||
t.rtype = reflect.FuncOf(in, out, false)
|
||||
case interfaceT:
|
||||
@@ -729,18 +745,14 @@ func (t *itype) TypeOf() reflect.Type {
|
||||
case mapT:
|
||||
t.rtype = reflect.MapOf(t.key.TypeOf(), t.val.TypeOf())
|
||||
case ptrT:
|
||||
// FIXME: the following should probably be done in nodeType() instead
|
||||
if t.val.cat == nilT {
|
||||
t.val.incomplete = true
|
||||
if s, _, ok := t.scope.lookup(t.val.name); ok {
|
||||
t.val = s.typ
|
||||
}
|
||||
if t.val != nil && name != "" && t.val.name == name {
|
||||
t.val.rtype = reflect.TypeOf(new(interface{})).Elem()
|
||||
}
|
||||
t.rtype = reflect.PtrTo(t.val.TypeOf())
|
||||
t.rtype = reflect.PtrTo(t.val.Type(name))
|
||||
case structT:
|
||||
var fields []reflect.StructField
|
||||
for _, f := range t.field {
|
||||
field := reflect.StructField{Name: exportName(f.name), Type: f.typ.TypeOf(), Tag: reflect.StructTag(f.tag)}
|
||||
field := reflect.StructField{Name: exportName(f.name), Type: f.typ.Type(name), Tag: reflect.StructTag(f.tag)}
|
||||
fields = append(fields, field)
|
||||
}
|
||||
t.rtype = reflect.StructOf(fields)
|
||||
@@ -752,6 +764,10 @@ func (t *itype) TypeOf() reflect.Type {
|
||||
return t.rtype
|
||||
}
|
||||
|
||||
func (t *itype) TypeOf() reflect.Type {
|
||||
return t.Type(t.name)
|
||||
}
|
||||
|
||||
func (t *itype) frameType() (r reflect.Type) {
|
||||
var err error
|
||||
if t, err = t.finalize(); err != nil {
|
||||
@@ -764,29 +780,11 @@ func (t *itype) frameType() (r reflect.Type) {
|
||||
} else {
|
||||
r = reflect.SliceOf(t.val.frameType())
|
||||
}
|
||||
//case ChanT:
|
||||
// r = reflect.ChanOf(reflect.BothDir, t.val.frameType())
|
||||
//case ErrorT:
|
||||
// r = reflect.TypeOf(new(error)).Elem()
|
||||
case funcT:
|
||||
r = reflect.TypeOf((*node)(nil))
|
||||
case interfaceT:
|
||||
r = reflect.TypeOf((*valueInterface)(nil)).Elem()
|
||||
//case MapT:
|
||||
// r = reflect.MapOf(t.key.frameType(), t.val.frameType())
|
||||
//case PtrT:
|
||||
// r = reflect.PtrTo(t.val.frameType())
|
||||
//case StructT:
|
||||
// var fields []reflect.StructField
|
||||
// for _, f := range t.field {
|
||||
// field := reflect.StructField{Name: exportName(f.name), Type: f.typ.frameType()}
|
||||
// fields = append(fields, field)
|
||||
// }
|
||||
// r = reflect.StructOf(fields)
|
||||
default:
|
||||
// if z, _ := t.zero(); z.IsValid() {
|
||||
// r = z.Type()
|
||||
// }
|
||||
r = t.TypeOf()
|
||||
}
|
||||
return r
|
||||
|
||||
Reference in New Issue
Block a user