Repository: goplus/gop
Pull request #497 (2020-07-25 08:48:26)

fix inconsistent command line output for different help info
`w io.Writer` is not used in `help.Help(w io.Writer, args []string)`, fix by pass `io.Writer` in all associated help info output function

codecov-commenter: # [Codecov](https://codecov.io/gh/goplus/gop/pull/497?src=pr&el=h1) Report
> Merging [#497](https://codecov.io/gh/goplus/gop/pull/497?src=pr&el=desc) into [master](https://codecov.io/gh/goplus/gop/commit/693b1694e7d97f056a034adc6407eaccff980d0a&el=desc) will **increase** coverage by `0.04%`.
> The diff coverage is `91.15%`.

[![Impacted file tree graph](https://codecov.io/gh/goplus/gop/pull/497/graphs/tree.svg?width=650&height=150&src=pr&token=4qln9Wk3Pn)](https://codecov.io/gh/goplus/gop/pull/497?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #497      +/-   ##
==========================================
+ Coverage   88.92%   88.96%   +0.04%     
==========================================
  Files          38       39       +1     
  Lines        9605     9718     +113     
==========================================
+ Hits         8541     8646     +105     
- Misses        785      791       +6     
- Partials      279      281       +2     
```


| [Impacted Files](https://codecov.io/gh/goplus/gop/pull/497?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [exec/bytecode/code.go](https://codecov.io/gh/goplus/gop/pull/497/diff?src=pr&el=tree#diff-ZXhlYy9ieXRlY29kZS9jb2RlLmdv) | `100.00% <ø> (ø)` | |
| [cl/stmt.go](https://codecov.io/gh/goplus/gop/pull/497/diff?src=pr&el=tree#diff-Y2wvc3RtdC5nbw==) | `91.89% <85.50%> (-1.31%)` | :arrow_down: |
| [cl/ctx\_check.go](https://codecov.io/gh/goplus/gop/pull/497/diff?src=pr&el=tree#diff-Y2wvY3R4X2NoZWNrLmdv) | `75.10% <100.00%> (+1.02%)` | :arrow_up: |
| [exec/bytecode/const.go](https://codecov.io/gh/goplus/gop/pull/497/diff?src=pr&el=tree#diff-ZXhlYy9ieXRlY29kZS9jb25zdC5nbw==) | `90.32% <100.00%> (+0.21%)` | :arrow_up: |
| [exec/bytecode/context.go](https://codecov.io/gh/goplus/gop/pull/497/diff?src=pr&el=tree#diff-ZXhlYy9ieXRlY29kZS9jb250ZXh0Lmdv) | `91.59% <100.00%> (+0.21%)` | :arrow_up: |
| [exec/bytecode/defer.go](https://codecov.io/gh/goplus/gop/pull/497/diff?src=pr&el=tree#diff-ZXhlYy9ieXRlY29kZS9kZWZlci5nbw==) | `100.00% <100.00%> (ø)` | |
| [exec/bytecode/interface.go](https://codecov.io/gh/goplus/gop/pull/497/diff?src=pr&el=tree#diff-ZXhlYy9ieXRlY29kZS9pbnRlcmZhY2UuZ28=) | `99.01% <100.00%> (+0.01%)` | :arrow_up: |
| [exec/golang/builder.go](https://codecov.io/gh/goplus/gop/pull/497/diff?src=pr&el=tree#diff-ZXhlYy9nb2xhbmcvYnVpbGRlci5nbw==) | `91.19% <100.00%> (+0.11%)` | :arrow_up: |
| [exec/golang/interface.go](https://codecov.io/gh/goplus/gop/pull/497/diff?src=pr&el=tree#diff-ZXhlYy9nb2xhbmcvaW50ZXJmYWNlLmdv) | `89.94% <100.00%> (+0.20%)` | :arrow_up: |
| [exec/golang/stmt.go](https://codecov.io/gh/goplus/gop/pull/497/diff?src=pr&el=tree#diff-ZXhlYy9nb2xhbmcvc3RtdC5nbw==) | `96.53% <100.00%> (+0.03%)` | :arrow_up: |
| ... and [2 more](https://codecov.io/gh/goplus/gop/pull/497/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/goplus/gop/pull/497?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/goplus/gop/pull/497?src=pr&el=footer). Last update [28dff1c...34e139a](https://codecov.io/gh/goplus/gop/pull/497?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/cl/context.go b/cl/context.go
index 5c4e1191..98dbfdee 100644
--- a/cl/context.go
+++ b/cl/context.go
@@ -185,12 +185,12 @@ func checkLabel(fl *flowLabel) bool {
 type blockCtx struct {
 	*pkgCtx
 	*funcCtx
-	file      *fileCtx
-	parent    *blockCtx
-	syms      map[string]iSymbol
-	noExecCtx bool
-	checkFlag bool
-	inLHS     bool
+	file           *fileCtx
+	parent         *blockCtx
+	syms           map[string]iSymbol
+	noExecCtx      bool
+	checkFlag      bool
+	checkArrayAddr bool
 }
 
 // function block ctx
@@ -323,6 +323,18 @@ func (p *blockCtx) findFunc(name string) (addr *funcDecl, err error) {
 	return nil, ErrSymbolNotFunc
 }
 
+// getCtxVar finds a var in currentCtx only
+func (p *blockCtx) getCtxVar(name string) (addr iVar, err error) {
+	v, ok := p.syms[name]
+	if !ok {
+		return nil, ErrNotFound
+	}
+	if addr, ok = v.(iVar); ok {
+		return
+	}
+	return nil, ErrSymbolNotVariable
+}
+
 func (p *blockCtx) findVar(name string) (addr iVar, err error) {
 	v, ok := p.find(name)
 	if !ok {
diff --git a/cl/ctx_check.go b/cl/ctx_check.go
index c029f796..6e7120dd 100644
--- a/cl/ctx_check.go
+++ b/cl/ctx_check.go
@@ -345,7 +345,7 @@ func isNoExecCtxAssignStmt(ctx *blockCtx, expr *ast.AssignStmt) bool {
 	return true
 }
 
-func isNoExecCtxExprLHS(ctx *blockCtx, expr ast.Expr, mode compleMode) bool {
+func isNoExecCtxExprLHS(ctx *blockCtx, expr ast.Expr, mode compileMode) bool {
 	switch v := expr.(type) {
 	case *ast.Ident:
 		return isNoExecCtxIdentLHS(ctx, v.Name, mode)
@@ -359,21 +359,21 @@ func isNoExecCtxExprLHS(ctx *blockCtx, expr ast.Expr, mode compleMode) bool {
 	return true
 }
 
-func isNoExecCtxIndexExprLHS(ctx *blockCtx, v *ast.IndexExpr, mode compleMode) bool {
+func isNoExecCtxIndexExprLHS(ctx *blockCtx, v *ast.IndexExpr, mode compileMode) bool {
 	if noExecCtx := isNoExecCtxExpr(ctx, v.X); !noExecCtx {
 		return false
 	}
 	return isNoExecCtxExpr(ctx, v.Index)
 }
 
-func isNoExecCtxIdentLHS(ctx *blockCtx, name string, mode compleMode) bool {
+func isNoExecCtxIdentLHS(ctx *blockCtx, name string, mode compileMode) bool {
 	if mode == lhsDefine && !ctx.exists(name) {
 		ctx.insertVar(name, exec.TyEmptyInterface, true)
 	}
 	return true
 }
 
-func isNoExecCtxSelectorExprLHS(ctx *blockCtx, v *ast.SelectorExpr, mode compleMode) bool {
+func isNoExecCtxSelectorExprLHS(ctx *blockCtx, v *ast.SelectorExpr, mode compileMode) bool {
 	if noExecCtx := isNoExecCtxExpr(ctx, v.X); !noExecCtx {
 		return false
 	}
diff --git a/cl/expr.go b/cl/expr.go
index 8874e5a6..3f849120 100644
--- a/cl/expr.go
+++ b/cl/expr.go
@@ -19,7 +19,6 @@ package cl
 import (
 	"reflect"
 	"strings"
-	"syscall"
 
 	"github.com/goplus/gop/ast"
 	"github.com/goplus/gop/ast/astutil"
@@ -32,17 +31,16 @@ import (
 
 // -----------------------------------------------------------------------------
 
-type compleMode = token.Token
+type compileMode = token.Token
 
 const (
-	lhsAssign compleMode = token.ASSIGN // leftHandSide = ...
-	lhsDefine compleMode = token.DEFINE // leftHandSide := ...
+	lhsAssign compileMode = token.ASSIGN // leftHandSide = ...
+	lhsDefine compileMode = token.DEFINE // leftHandSide := ...
 )
 
 // -----------------------------------------------------------------------------
 
-func compileExprLHS(ctx *blockCtx, expr ast.Expr, mode compleMode) {
-	ctx.inLHS = true
+func compileExprLHS(ctx *blockCtx, expr ast.Expr, mode compileMode) {
 	switch v := expr.(type) {
 	case *ast.Ident:
 		compileIdentLHS(ctx, v.Name, mode)
@@ -53,7 +51,6 @@ func compileExprLHS(ctx *blockCtx, expr ast.Expr, mode compleMode) {
 	default:
 		log.Panicln("compileExpr failed: unknown -", reflect.TypeOf(v))
 	}
-	ctx.inLHS = false
 }
 
 func compileExpr(ctx *blockCtx, expr ast.Expr) func() {
@@ -100,14 +97,20 @@ func compileExpr(ctx *blockCtx, expr ast.Expr) func() {
 	}
 }
 
-func compileIdentLHS(ctx *blockCtx, name string, mode compleMode) {
+func compileIdentLHS(ctx *blockCtx, name string, mode compileMode) {
 	in := ctx.infer.Get(-1)
 	addr, err := ctx.findVar(name)
+	if mode == lhsDefine {
+		addr, err = ctx.getCtxVar(name)
+		if addr != nil {
+			log.Panicf("compileIdentLHS failed: %s redeclared in this block\n", name)
+		}
+	}
 	if err == nil {
 		if mode == lhsDefine && !addr.inCurrentCtx(ctx) {
 			log.Warn("requireVar: variable is shadowed -", name)
 		}
-	} else if mode == lhsAssign || err != syscall.ENOENT {
+	} else if mode == lhsAssign || err != ErrNotFound {
 		log.Panicln("compileIdentLHS failed:", err, "-", name)
 	} else {
 		typ := boundType(in.(iValue))
@@ -155,7 +158,7 @@ func compileIdent(ctx *blockCtx, name string) func() {
 		case *execVar:
 			ctx.infer.Push(&goValue{t: v.v.Type()})
 			return func() {
-				if ctx.inLHS && v.v.Type().Kind() == reflect.Array {
+				if ctx.checkArrayAddr && v.v.Type().Kind() == reflect.Array {
 					ctx.out.AddrVar(v.v)
 				} else {
 					ctx.out.LoadVar(v.v)
@@ -233,19 +236,14 @@ func compileCompositeLit(ctx *blockCtx, v *ast.CompositeLit) func() {
 	typ := toType(ctx, v.Type)
 	switch kind := typ.Kind(); kind {
 	case reflect.Slice, reflect.Array:
-		var typSlice, typRet reflect.Type
+		var typSlice reflect.Type
 		if t, ok := typ.(*unboundArrayType); ok {
 			n := toBoundArrayLen(ctx, v)
 			typSlice = reflect.ArrayOf(n, t.elem)
 		} else {
 			typSlice = typ.(reflect.Type)
 		}
-		if typSlice.Kind() == reflect.Array {
-			typRet = reflect.PtrTo(typSlice)
-		} else {
-			typRet = typSlice
-		}
-		ctx.infer.Push(&goValue{t: typRet})
+		ctx.infer.Push(&goValue{t: typSlice})
 		return func() {
 			var nLen int
 			if kind == reflect.Array {
@@ -695,21 +693,18 @@ func compileCallExprCall(ctx *blockCtx, exprFun func(), v *ast.CallExpr) func()
 	return nil
 }
 
-func compileIndexExprLHS(ctx *blockCtx, v *ast.IndexExpr, mode compleMode) {
+func compileIndexExprLHS(ctx *blockCtx, v *ast.IndexExpr, mode compileMode) {
 	if mode == lhsDefine {
 		log.Panicln("compileIndexExprLHS: `:=` can't be used for index expression")
 	}
 	val := ctx.infer.Get(-1)
+
+	ctx.checkArrayAddr = true
 	compileExpr(ctx, v.X)()
+	ctx.checkArrayAddr = false
+
 	typ := ctx.infer.Get(-1).(iValue).Type()
 	typElem := typ.Elem()
-	if typ.Kind() == reflect.Ptr {
-		if typElem.Kind() != reflect.Array {
-			logPanic(ctx, v, `type %v does not support indexing`, typ)
-		}
-		typ = typElem
-		typElem = typElem.Elem()
-	}
 	if cons, ok := val.(*constVal); ok {
 		cons.bound(typElem, ctx.out)
 	} else if t := val.(iValue).Type(); t != typElem {
@@ -754,16 +749,14 @@ func compileSliceExpr(ctx *blockCtx, v *ast.SliceExpr) func() { // x[i:j:k]
 	exprX := compileExpr(ctx, v.X)
 	x := ctx.infer.Get(-1)
 	typ := x.(iValue).Type()
-	if kind = typ.Kind(); kind == reflect.Ptr {
-		typ = typ.Elem()
-		if kind = typ.Kind(); kind != reflect.Array {
-			logPanic(ctx, v, `cannot slice a (type *%v)`, typ)
-		}
+	if kind = typ.Kind(); kind == reflect.Array {
 		typ = reflect.SliceOf(typ.Elem())
 		ctx.infer.Ret(1, &goValue{typ})
 	}
 	return func() {
+		ctx.checkArrayAddr = true
 		exprX()
+		ctx.checkArrayAddr = false
 		i, j, k := exec.SliceDefaultIndex, exec.SliceDefaultIndex, exec.SliceDefaultIndex
 		if v.Low != nil {
 			i = compileIdx(ctx, v.Low, exec.SliceConstIndexLast, kind)
@@ -811,12 +804,7 @@ func compileIndexExpr(ctx *blockCtx, v *ast.IndexExpr) func() { // x[i]
 	exprX := compileExpr(ctx, v.X)
 	x := ctx.infer.Get(-1)
 	typ := x.(iValue).Type()
-	if kind = typ.Kind(); kind == reflect.Ptr {
-		typ = typ.Elem()
-		if kind = typ.Kind(); kind != reflect.Array {
-			logPanic(ctx, v, `type *%v does not support indexing`, typ)
-		}
-	}
+	kind = typ.Kind()
 	if kind == reflect.String {
 		typElem = exec.TyByte
 	} else {
@@ -910,7 +898,7 @@ func getFuncInfo(fun exec.FuncInfo) (name string, narg int) {
 	return "main", 0
 }
 
-func compileSelectorExprLHS(ctx *blockCtx, v *ast.SelectorExpr, mode compleMode) {
+func compileSelectorExprLHS(ctx *blockCtx, v *ast.SelectorExpr, mode compileMode) {
 	if mode == lhsDefine {
 		log.Panicln("compileSelectorExprLHS: `:=` can't be used for index expression")
 	}
@@ -986,7 +974,7 @@ func compileSelectorExpr(ctx *blockCtx, v *ast.SelectorExpr, allowAutoCall bool)
 				vt := reflect.ValueOf(info.This)
 				ctx.infer.Ret(1, &goValue{t: vt.Elem().Type()})
 				return func() {
-					if ctx.inLHS && vt.Elem().Kind() == reflect.Array {
+					if ctx.checkArrayAddr && vt.Elem().Kind() == reflect.Array {
 						ctx.out.AddrGoVar(exec.GoVarAddr(addr))
 					} else {
 						ctx.out.LoadGoVar(exec.GoVarAddr(addr))
diff --git a/cl/goinstr.go b/cl/goinstr.go
index a0053c80..24901ab6 100644
--- a/cl/goinstr.go
+++ b/cl/goinstr.go
@@ -171,12 +171,6 @@ func igoLenOrCap(ctx *blockCtx, v *ast.CallExpr, op exec.GoBuiltin) func() {
 	x := ctx.infer.Get(-1)
 	typ := x.(iValue).Type()
 	kind := typ.Kind()
-	if kind == reflect.Ptr {
-		typ = typ.Elem()
-		if kind = typ.Kind(); kind != reflect.Array {
-			logPanic(ctx, v, `invalid argument a (type *%v) for %v`, typ, op)
-		}
-	}
 	switch kind {
 	case reflect.Array:
 		n := typ.Len()
diff --git a/cl/stmt.go b/cl/stmt.go
index 3015994e..4a2c112d 100644
--- a/cl/stmt.go
+++ b/cl/stmt.go
@@ -37,6 +37,12 @@ func compileBlockStmtWithout(ctx *blockCtx, body *ast.BlockStmt) {
 	}
 }
 
+func compileNewBlock(ctx *blockCtx, block *ast.BlockStmt) {
+	ctx.out.DefineBlock()
+	compileBlockStmtWith(ctx, block)
+	ctx.out.EndBlock()
+}
+
 func compileBodyWith(ctx *blockCtx, body []ast.Stmt) {
 	ctxWith := newNormBlockCtx(ctx)
 	for _, stmt := range body {
@@ -62,7 +68,7 @@ func compileStmt(ctx *blockCtx, stmt ast.Stmt) {
 	case *ast.ForStmt:
 		compileForStmt(ctx, v)
 	case *ast.BlockStmt:
-		compileBlockStmtWith(ctx, v)
+		compileNewBlock(ctx, v)
 	case *ast.ReturnStmt:
 		compileReturnStmt(ctx, v)
 	case *ast.IncDecStmt:
@@ -147,9 +153,11 @@ func toIdent(e ast.Expr) *ast.Ident {
 }
 
 func compileForStmt(ctx *blockCtx, v *ast.ForStmt) {
-	if v.Init != nil {
-		ctx = newNormBlockCtx(ctx)
-		compileStmt(ctx, v.Init)
+	if init := v.Init; init != nil {
+		v.Init = nil
+		block := &ast.BlockStmt{List: []ast.Stmt{init, v}}
+		compileNewBlock(ctx, block)
+		return
 	}
 	out := ctx.out
 	start := ctx.NewLabel("")
@@ -477,7 +485,11 @@ func compileIfStmt(ctx *blockCtx, v *ast.IfStmt) {
 	}
 	out.Label(label)
 	if hasElse {
-		compileStmt(ctxIf, v.Else)
+		if ve, ok := v.Else.(*ast.BlockStmt); ok {
+			compileBlockStmtWithout(ctx, ve)
+		} else {
+			compileStmt(ctxIf, v.Else)
+		}
 		out.Label(done)
 	}
 }
diff --git a/cmd/gop/main.go b/cmd/gop/main.go
index 515455fa..f3d94656 100644
--- a/cmd/gop/main.go
+++ b/cmd/gop/main.go
@@ -40,7 +40,7 @@ func main() {
 
 	base.CmdName = args[0] // for error messages
 	if args[0] == "help" {
-		help.Help(os.Stdout, args[1:])
+		help.Help(os.Stderr, args[1:])
 		return
 	}
 
@@ -58,7 +58,7 @@ BigCmdLoop:
 					os.Exit(2)
 				}
 				if args[0] == "help" {
-					help.Help(os.Stdout, append(strings.Split(base.CmdName, " "), args[1:]...))
+					help.Help(os.Stderr, append(strings.Split(base.CmdName, " "), args[1:]...))
 					return
 				}
 				base.CmdName += " " + args[0]
diff --git a/cmd/internal/base/base.go b/cmd/internal/base/base.go
index 4d03414c..d59eca63 100644
--- a/cmd/internal/base/base.go
+++ b/cmd/internal/base/base.go
@@ -21,6 +21,7 @@ package base
 import (
 	"flag"
 	"fmt"
+	"io"
 	"os"
 	"strings"
 )
@@ -77,10 +78,15 @@ func (c *Command) Name() string {
 }
 
 // Usage show the command usage.
-func (c *Command) Usage() {
-	fmt.Fprintf(os.Stderr, "%s\n\nUsage: %s\n", c.Short, c.UsageLine)
+func (c *Command) Usage(w io.Writer) {
+	fmt.Fprintf(w, "%s\n\nUsage: %s\n", c.Short, c.UsageLine)
+
+	// restore output of flag
+	defer c.Flag.SetOutput(c.Flag.Output())
+
+	c.Flag.SetOutput(w)
 	c.Flag.PrintDefaults()
-	fmt.Fprintln(os.Stderr)
+	fmt.Fprintln(w)
 	os.Exit(2)
 }
 
diff --git a/cmd/internal/export/export.go b/cmd/internal/export/export.go
index 7013d7ea..28725819 100644
--- a/cmd/internal/export/export.go
+++ b/cmd/internal/export/export.go
@@ -53,7 +53,7 @@ func init() {
 func runCmd(cmd *base.Command, args []string) {
 	flag.Parse(args)
 	if flag.NArg() < 1 {
-		cmd.Usage()
+		cmd.Usage(os.Stderr)
 		return
 	}
 	var libDir string
diff --git a/cmd/internal/gengo/go.go b/cmd/internal/gengo/go.go
index 48dd1b91..0607002b 100644
--- a/cmd/internal/gengo/go.go
+++ b/cmd/internal/gengo/go.go
@@ -185,7 +185,7 @@ func init() {
 func runCmd(cmd *base.Command, args []string) {
 	flag.Parse(args)
 	if flag.NArg() < 1 {
-		cmd.Usage()
+		cmd.Usage(os.Stderr)
 		return
 	}
 	dir := flag.Arg(0)
diff --git a/cmd/internal/help/help.go b/cmd/internal/help/help.go
index 8daf3fa7..11e6a35f 100644
--- a/cmd/internal/help/help.go
+++ b/cmd/internal/help/help.go
@@ -41,9 +41,9 @@ Args:
 	}
 
 	if len(cmd.Commands) > 0 {
-		PrintUsage(os.Stdout, cmd)
+		PrintUsage(w, cmd)
 	} else {
-		cmd.Usage()
+		cmd.Usage(w)
 	}
 	// not exit 2: succeeded at 'gop help cmd'.
 	return
diff --git a/cmd/internal/run/run.go b/cmd/internal/run/run.go
index baca27d9..129d9fad 100644
--- a/cmd/internal/run/run.go
+++ b/cmd/internal/run/run.go
@@ -53,7 +53,7 @@ func init() {
 func runCmd(cmd *base.Command, args []string) {
 	flag.Parse(args)
 	if flag.NArg() < 1 {
-		cmd.Usage()
+		cmd.Usage(os.Stderr)
 	}
 
 	log.SetFlags(log.Ldefault &^ log.LstdFlags)
diff --git a/exec.spec/interface.go b/exec.spec/interface.go
index 83293713..f26485ef 100644
--- a/exec.spec/interface.go
+++ b/exec.spec/interface.go
@@ -363,6 +363,12 @@ type Builder interface {
 
 	// Defer instr
 	Defer(start, end Label) Instr
+
+	// DefineBlock instr
+	DefineBlock() Builder
+
+	// EndBlock instr
+	EndBlock() Builder
 }
 
 // Package represents a Go+ package.
diff --git a/exec/bytecode/goinstr.go b/exec/bytecode/goinstr.go
index f93b67bc..6d402f45 100644
--- a/exec/bytecode/goinstr.go
+++ b/exec/bytecode/goinstr.go
@@ -157,17 +157,24 @@ func execMakeArray(i Instr, p *Context) {
 func makeArray(typSlice reflect.Type, arity int, p *Context) {
 	args := p.GetArgs(arity)
 	var ret, set reflect.Value
-	if typSlice.Kind() == reflect.Slice {
+	kind := typSlice.Kind()
+	if kind == reflect.Slice {
 		ret = reflect.MakeSlice(typSlice, arity, arity)
 		set = ret
-	} else {
+	} else if kind == reflect.Array {
 		ret = reflect.New(typSlice)
 		set = ret.Elem()
+	} else {
+		log.Panic("makeArray bad type:", typSlice)
 	}
 	for i, arg := range args {
 		set.Index(i).Set(getElementOf(arg, typSlice))
 	}
-	p.Ret(arity, ret.Interface())
+	if kind == reflect.Slice {
+		p.Ret(arity, ret.Interface())
+	} else {
+		p.Ret(arity, ret.Elem().Interface())
+	}
 }
 
 func execAppend(i Instr, p *Context) {
diff --git a/exec/bytecode/interface.go b/exec/bytecode/interface.go
index ba7f5542..66252c4b 100644
--- a/exec/bytecode/interface.go
+++ b/exec/bytecode/interface.go
@@ -437,4 +437,14 @@ func (p *iBuilder) Resolve() exec.Code {
 	return ((*Builder)(p)).Resolve()
 }
 
+// DefineBlock
+func (p *iBuilder) DefineBlock() exec.Builder {
+	return p
+}
+
+// EndBlock
+func (p *iBuilder) EndBlock() exec.Builder {
+	return p
+}
+
 // -----------------------------------------------------------------------------
diff --git a/exec/golang/expr.go b/exec/golang/expr.go
index 3e807190..8bc9533e 100644
--- a/exec/golang/expr.go
+++ b/exec/golang/expr.go
@@ -455,9 +455,6 @@ func (p *Builder) MakeArray(typ reflect.Type, arity int) *Builder {
 		Type: typExpr,
 		Elts: elts,
 	}
-	if typ.Kind() == reflect.Array {
-		xExpr = &ast.UnaryExpr{Op: token.AND, X: xExpr}
-	}
 	p.rhs.Ret(arity, xExpr)
 	return p
 }
diff --git a/exec/golang/interface.go b/exec/golang/interface.go
index 38891c7d..7353f261 100644
--- a/exec/golang/interface.go
+++ b/exec/golang/interface.go
@@ -453,4 +453,16 @@ func (p *iBuilder) Resolve() exec.Code {
 	return ((*Builder)(p)).Resolve()
 }
 
+// DefineBlock
+func (p *iBuilder) DefineBlock() exec.Builder {
+	((*Builder)(p)).DefineBlock()
+	return p
+}
+
+// EndBlock
+func (p *iBuilder) EndBlock() exec.Builder {
+	((*Builder)(p)).EndBlock()
+	return p
+}
+
 // -----------------------------------------------------------------------------
diff --git a/exec/golang/stmt.go b/exec/golang/stmt.go
index 539253ae..b774cfde 100644
--- a/exec/golang/stmt.go
+++ b/exec/golang/stmt.go
@@ -397,4 +397,44 @@ func (p *Builder) Defer(start, end *Label) exec.Instr {
 	panic("The method defer under the builder of golang is not yet supported")
 }
 
+// DefineBlock starts a new block
+func (p *Builder) DefineBlock() *Builder {
+	p.scopeCtx = &scopeCtx{parentCtx: p.scopeCtx}
+	p.initStmts()
+	return p
+}
+
+//  EndBlock ends a  block
+func (p *Builder) EndBlock() *Builder {
+	p.endBlockStmt(0)
+	blockStmt := getBlockStmts(p)
+	if p.parentCtx == nil {
+		p.rhs.Push(blockStmt)
+	} else {
+		p.parentCtx.stmts = append(p.parentCtx.stmts, blockStmt)
+		p.scopeCtx = p.parentCtx
+	}
+	return p
+}
+
+// getBlockStmts will check whether the first stmt in block stmts is labeledStmt.
+// if true ,the whole block should be labeled
+func getBlockStmts(p *Builder) ast.Stmt {
+	body := &ast.BlockStmt{List: p.getStmts(p)}
+	if len(body.List) > 0 {
+		for i := 0; i < len(body.List); i++ {
+			if _, ok := body.List[i].(*ast.DeclStmt); ok {
+				continue
+			}
+			if v, ok := body.List[i].(*ast.LabeledStmt); ok {
+				body.List[i] = v.Stmt
+				v.Stmt = body
+				return v
+			}
+			break
+		}
+	}
+	return body
+}
+
 // ----------------------------------------------------------------------------
diff --git a/exec/golang/var.go b/exec/golang/var.go
index b71c486a..7dc0c940 100644
--- a/exec/golang/var.go
+++ b/exec/golang/var.go
@@ -69,8 +69,9 @@ func (p *Var) setScope(where *scopeCtx) {
 // -----------------------------------------------------------------------------
 
 type scopeCtx struct {
-	vlist []exec.Var
-	stmts []ast.Stmt
+	parentCtx *scopeCtx
+	vlist     []exec.Var
+	stmts     []ast.Stmt
 }
 
 func (p *scopeCtx) addVar(vars ...exec.Var) {


Test patch:
diff --git a/cl/expr_test.go b/cl/expr_test.go
index 8d71ad66..90f9f664 100644
--- a/cl/expr_test.go
+++ b/cl/expr_test.go
@@ -205,15 +205,22 @@ func TestArray(t *testing.T) {
 		y := [...]float64{1, 2.3, 3.6}
 		println("y:", y)
 		`,
-		"x: &[2.3 3.6 0 0]\ny: &[1 2.3 3.6]\n",
+		"x: [2.3 3.6 0 0]\ny: [1 2.3 3.6]\n",
 	)
 	cltest.Expect(t, `
 		x := [...]float64{1, 3: 3.4, 5}
 		x[1] = 217
 		println("x:", x, "x[1]:", x[1])
 		`,
-		"x: &[1 217 0 3.4 5] x[1]: 217\n",
+		"x: [1 217 0 3.4 5] x[1]: 217\n",
 	)
+	cltest.Expect(t, `
+		x := [...]float64{1, 2.3, 3, 4}
+		x[2] = 3.1
+		println("x[1:]:", x[1:])
+		println(len(x))
+	`,
+		"x[1:]: [2.3 3.1 4]\n4\n")
 }
 
 func TestMap(t *testing.T) {
diff --git a/cl/stmt_test.go b/cl/stmt_test.go
index afdc9468..34dbadde 100644
--- a/cl/stmt_test.go
+++ b/cl/stmt_test.go
@@ -1305,3 +1305,28 @@ var testDeferClauses = map[string]testData{
 func TestDeferStmt(t *testing.T) {
 	testScripts(t, "TestDeferStmt", testDeferClauses)
 }
+
+// -----------------------------------------------------------------------------
+
+var testVarScopeClauses = map[string]testData{
+	"variable_redefinition_#issue304": {`
+						a := []float64{1, 2, 3.4}
+						println(a)
+						
+						a := []float64{1, 2, 3.4}
+						println(a)
+					`, "", true},
+	"variable_scope_bug_#issue303": {`
+						i:=0
+						{
+						    i:=0
+						    i++
+						    println("inner is",i)
+						}
+						println("outer is",i)
+					`, "inner is 1\nouter is 0\n", false},
+}
+
+func TestVarScopeStmt(t *testing.T) {
+	testScripts(t, "TestVarScopeStmt", testVarScopeClauses)
+}
diff --git a/exec/bytecode/goinstr_test.go b/exec/bytecode/goinstr_test.go
index 52400c16..72e2535b 100644
--- a/exec/bytecode/goinstr_test.go
+++ b/exec/bytecode/goinstr_test.go
@@ -53,7 +53,7 @@ func TestLargeArray(t *testing.T) {
 
 	ctx := NewContext(code)
 	ctx.Exec(0, code.Len())
-	if v := checkPop(ctx); !reflect.DeepEqual(v, &ret) {
+	if v := checkPop(ctx); !reflect.DeepEqual(v, ret) {
 		t.Fatal("32 times(1024) mkslice != `32` times(1024) slice, ret =", v)
 	}
 }
diff --git a/exec/golang/testdata/01.const/bar.gop b/exec/golang/testdata/01.const/bar.gop
deleted file mode 100644
index c46de522..00000000
--- a/exec/golang/testdata/01.const/bar.gop
+++ /dev/null
@@ -1,1 +0,0 @@
-println("Hello "+"qiniu:", 123, 4.5, 7i)
diff --git a/exec/golang/testdata/01.var-const/var_const.gop b/exec/golang/testdata/01.var-const/var_const.gop
new file mode 100644
index 00000000..d9be9099
--- /dev/null
+++ b/exec/golang/testdata/01.var-const/var_const.gop
@@ -0,0 +1,26 @@
+println("Hello "+"qiniu:", 123, 4.5, 7i)
+
+i := 0
+{
+	i := 0
+	i++
+	println("inner is", i)
+}
+println("outer is", i)
+println("start")
+{
+	i := 0
+	{
+		j := 2
+		{
+			c := 3
+			println(i, j, c)
+		}
+		j++
+		i++
+		println(i, j)
+	}
+	i++
+	println(i)
+}
+println("end")