fix: incomplete type analysis
This commit is contained in:
22
_test/struct39.go
Normal file
22
_test/struct39.go
Normal 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
23
_test/struct40.go
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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); {
|
||||
|
||||
Reference in New Issue
Block a user