fix: incomplete type analysis

This commit is contained in:
Marc Vertes
2020-04-03 04:14:04 +02:00
committed by GitHub
parent b20ad3a01d
commit b0053c874f
4 changed files with 86 additions and 4 deletions

22
_test/struct39.go Normal file
View File

@@ -0,0 +1,22 @@
package main
type T struct {
t *T1
y *xxx
}
type T1 struct {
T
}
var x = &T1{}
var t = &T{}
type xxx struct{}
func main() {
println("ok")
}
// Output:
// ok

23
_test/struct40.go Normal file
View File

@@ -0,0 +1,23 @@
package main
type T struct {
t *T1
y *xxx
}
type T1 struct {
T
}
func f(t *T) { println("in f") }
var x = &T1{}
type xxx struct{}
func main() {
println("ok")
}
// Output:
// ok

View File

@@ -63,7 +63,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
}
val = src.rval
}
if typ.incomplete {
if !typ.isComplete() {
// Come back when type is known.
revisit = append(revisit, n)
return false
@@ -94,7 +94,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
if n.typ, err = nodeType(interp, sc, n.child[l]); err != nil {
return false
}
if n.typ.incomplete {
if !n.typ.isComplete() {
// Come back when type is known.
revisit = append(revisit, n)
return false
@@ -139,7 +139,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error)
// 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}
}
if n.typ.incomplete {
if !n.typ.isComplete() {
revisit = append(revisit, n)
}
return false
@@ -206,7 +206,7 @@ func (interp *Interpreter) gta(root *node, rpath, pkgID 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 {
if !n.typ.isComplete() {
revisit = append(revisit, n)
}
return false

View File

@@ -654,6 +654,43 @@ func (t *itype) finalize() (*itype, error) {
return t, err
}
// isComplete returns true if type definition is complete.
func (t *itype) isComplete() bool { return isComplete(t, map[string]bool{}) }
func isComplete(t *itype, visited map[string]bool) bool {
if t.incomplete {
return false
}
if visited[t.name] {
return !t.incomplete
}
if t.name != "" {
visited[t.name] = true
}
switch t.cat {
case aliasT, arrayT, chanT, ptrT:
return isComplete(t.val, visited)
case funcT:
complete := true
for _, a := range t.arg {
complete = complete && isComplete(a, visited)
}
for _, a := range t.ret {
complete = complete && isComplete(a, visited)
}
return complete
case interfaceT, structT:
complete := true
for _, f := range t.field {
complete = complete && isComplete(f.typ, visited)
}
return complete
case nilT:
return false
}
return true
}
// Equals returns true if the given type is identical to the receiver one.
func (t *itype) equals(o *itype) bool {
switch ti, oi := isInterface(t), isInterface(o); {