interp: allow early constant evaluation from builtin call
One builtin has been identified to be used for constant definition: len(), with a constant string argument. Add support for this. Fixes #1012.
This commit is contained in:
12
_test/const23.go
Normal file
12
_test/const23.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
const maxlen = len("hello")
|
||||
|
||||
var gfm = [maxlen]byte{}
|
||||
|
||||
func main() {
|
||||
println(len(gfm))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 5
|
||||
14
_test/const24.go
Normal file
14
_test/const24.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
var aa = [...]int{1, 2, 3}
|
||||
|
||||
const maxlen = cap(aa)
|
||||
|
||||
var gfm = [maxlen]byte{}
|
||||
|
||||
func main() {
|
||||
println(len(gfm))
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
@@ -565,6 +565,8 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
switch {
|
||||
case n.action != aAssign:
|
||||
// Do not optimize assign combined with another operator.
|
||||
case src.rval.IsValid():
|
||||
// Do not skip assign operation when setting from a constant value.
|
||||
case isMapEntry(dest):
|
||||
// Setting a map entry needs an additional step, do not optimize.
|
||||
// As we only write, skip the default useless getIndexMap dest action.
|
||||
@@ -855,13 +857,15 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
wireChild(n)
|
||||
switch {
|
||||
case interp.isBuiltinCall(n):
|
||||
err = check.builtin(n.child[0].ident, n, n.child[1:], n.action == aCallSlice)
|
||||
c0 := n.child[0]
|
||||
bname := c0.ident
|
||||
err = check.builtin(bname, n, n.child[1:], n.action == aCallSlice)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
n.gen = n.child[0].sym.builtin
|
||||
n.child[0].typ = &itype{cat: builtinT}
|
||||
n.gen = c0.sym.builtin
|
||||
c0.typ = &itype{cat: builtinT}
|
||||
if n.typ, err = nodeType(interp, sc, n); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -872,10 +876,18 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
case n.anc.kind == returnStmt:
|
||||
// Store result directly to frame output location, to avoid a frame copy.
|
||||
n.findex = 0
|
||||
case bname == "cap" && isInConstOrTypeDecl(n):
|
||||
capConst(n)
|
||||
n.findex = notInFrame
|
||||
n.gen = nop
|
||||
case bname == "len" && isInConstOrTypeDecl(n):
|
||||
lenConst(n)
|
||||
n.findex = notInFrame
|
||||
n.gen = nop
|
||||
default:
|
||||
n.findex = sc.add(n.typ)
|
||||
}
|
||||
if op, ok := constBltn[n.child[0].ident]; ok && n.anc.action != aAssign {
|
||||
if op, ok := constBltn[bname]; ok && n.anc.action != aAssign {
|
||||
op(n) // pre-compute non-assigned constant :
|
||||
}
|
||||
case n.child[0].isType(sc):
|
||||
@@ -2326,6 +2338,20 @@ func isRecursiveField(n *node) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func isInConstOrTypeDecl(n *node) bool {
|
||||
anc := n.anc
|
||||
for anc != nil {
|
||||
switch anc.kind {
|
||||
case constDecl, typeDecl:
|
||||
return true
|
||||
case varDecl, funcDecl:
|
||||
return false
|
||||
}
|
||||
anc = anc.anc
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isNewDefine returns true if node refers to a new definition.
|
||||
func isNewDefine(n *node, sc *scope) bool {
|
||||
if n.ident == "_" {
|
||||
|
||||
@@ -2847,6 +2847,21 @@ func _delete(n *node) {
|
||||
})
|
||||
}
|
||||
|
||||
func capConst(n *node) {
|
||||
n.rval = reflect.New(reflect.TypeOf(int(0))).Elem()
|
||||
// There is no Cap() method for reflect.Type, just return Len() instead.
|
||||
n.rval.SetInt(int64(n.child[1].typ.TypeOf().Len()))
|
||||
}
|
||||
|
||||
func lenConst(n *node) {
|
||||
n.rval = reflect.New(reflect.TypeOf(int(0))).Elem()
|
||||
if c1 := n.child[1]; c1.rval.IsValid() {
|
||||
n.rval.SetInt(int64(len(vString(c1.rval))))
|
||||
} else {
|
||||
n.rval.SetInt(int64(c1.typ.TypeOf().Len()))
|
||||
}
|
||||
}
|
||||
|
||||
func _len(n *node) {
|
||||
dest := genValueOutput(n, reflect.TypeOf(int(0)))
|
||||
value := genValue(n.child[1])
|
||||
|
||||
@@ -198,7 +198,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
if sym.kind != constSym {
|
||||
return nil, c0.cfgErrorf("non-constant array bound %q", c0.ident)
|
||||
}
|
||||
if sym.typ == nil || sym.typ.cat != intT {
|
||||
if sym.typ == nil || sym.typ.cat != intT || !sym.rval.IsValid() {
|
||||
t.incomplete = true
|
||||
break
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user