Compare commits

..

4 Commits

Author SHA1 Message Date
Marc Vertes
3cd37645eb fix: correct isValueUntyped() to handle typed constants 2019-12-19 15:38:05 +01:00
Marc Vertes
e1ac83f7d8 fix: correct type extraction for returned value 2019-12-17 10:18:06 +01:00
Marc Vertes
4f93be7f19 fix: emulate struct by interface{} only for recursive struct types 2019-12-16 19:00:07 +01:00
Marc Vertes
7a0c09f5eb fix: detect untyped values when importing from binary packages 2019-12-13 11:18:04 +01:00
9 changed files with 119 additions and 6 deletions

15
_test/nil0.go Normal file
View File

@@ -0,0 +1,15 @@
package main
import "fmt"
func f() (host, port string, err error) {
return "", "", nil
}
func main() {
h, p, err := f()
fmt.Println(h, p, err)
}
// Output:
// <nil>

11
_test/str4.go Normal file
View File

@@ -0,0 +1,11 @@
package main
import "unicode/utf8"
func main() {
r, _ := utf8.DecodeRuneInString("Hello")
println(r < utf8.RuneSelf)
}
// Output:
// true

19
_test/struct29.go Normal file
View File

@@ -0,0 +1,19 @@
package main
type T1 struct {
A []T2
B []T2
}
type T2 struct {
name string
}
var t = T1{}
func main() {
println("ok")
}
// Output:
// ok

19
_test/struct30.go Normal file
View File

@@ -0,0 +1,19 @@
package main
type T1 struct {
A []T2
M map[uint64]T2
}
type T2 struct {
name string
}
var t = T1{}
func main() {
println("ok")
}
// Output:
// ok

15
_test/time11.go Normal file
View File

@@ -0,0 +1,15 @@
package main
import (
"fmt"
"time"
)
const df = time.Minute * 30
func main() {
fmt.Printf("df: %v %T\n", df, df)
}
// Output:
// df: 30m0s time.Duration

View File

@@ -602,8 +602,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
constOp[n.action](n)
}
switch {
//case n.typ != nil && n.typ.cat == BoolT && isAncBranch(n):
// n.findex = -1
case n.rval.IsValid():
n.gen = nop
n.findex = -1
@@ -1068,7 +1066,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
// nil: Set node value to zero of return type
f := sc.def
var typ *itype
if typ, err = nodeType(interp, sc, f.child[2].child[1].child[i].lastChild()); err != nil {
if typ, err = nodeType(interp, sc, f.child[2].child[1].fieldType(i)); err != nil {
return
}
if typ.cat == funcT {
@@ -1155,7 +1153,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.typ = &itype{cat: valueT, rtype: s.Type().Elem()}
} else {
n.kind = rvalueExpr
n.typ = &itype{cat: valueT, rtype: s.Type()}
n.typ = &itype{cat: valueT, rtype: s.Type(), untyped: isValueUntyped(s)}
n.rval = s
}
n.gen = nop
@@ -1643,6 +1641,29 @@ func (n *node) isNatural() bool {
return false
}
// fieldType returns the nth parameter field node (type) of a fieldList node
func (n *node) fieldType(m int) *node {
k := 0
l := len(n.child)
for i := 0; i < l; i++ {
cl := len(n.child[i].child)
if cl < 2 {
if k == m {
return n.child[i].lastChild()
}
k++
continue
}
for j := 0; j < cl-1; j++ {
if k == m {
return n.child[i].lastChild()
}
k++
}
}
return nil
}
// lastChild returns the last child of a node
func (n *node) lastChild() *node { return n.child[len(n.child)-1] }
@@ -1825,3 +1846,13 @@ func arrayTypeLen(n *node) int {
}
return max + 1
}
// isValueUntyped returns true if value is untyped
func isValueUntyped(v reflect.Value) bool {
// Consider only constant values.
if v.CanSet() {
return false
}
t := v.Type()
return t.String() == t.Kind().String()
}

View File

@@ -30,6 +30,7 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
case defineStmt:
var atyp *itype
if n.nleft+n.nright < len(n.child) {
// Type is declared explicitly in the assign expression.
if atyp, err = nodeType(interp, sc, n.child[n.nleft]); err != nil {
return false
}

View File

@@ -239,7 +239,7 @@ func isRecursiveStruct(t *itype, rtype reflect.Type) bool {
if t.cat == structT && rtype.Kind() == reflect.Interface {
return true
}
if t.cat == ptrT {
if t.cat == ptrT && t.rtype != nil {
return isRecursiveStruct(t.val, t.rtype.Elem())
}
return false

View File

@@ -885,7 +885,9 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
panic(err)
}
}
if t.val != nil && defined[t.val.name] {
if t.val != nil && defined[t.val.name] && !t.val.incomplete && t.val.rtype == nil {
// Replace reference to self (direct or indirect) by an interface{} to handle
// recursive types with reflect.
t.val.rtype = interf
}
switch t.cat {