Repository: goplus/gop
Pull request #520 (2020-08-03 21:54:46)

new

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

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

```diff
@@            Coverage Diff             @@
##           master     #520      +/-   ##
==========================================
+ Coverage   89.37%   89.39%   +0.01%     
==========================================
  Files          40       40              
  Lines        9792     9819      +27     
==========================================
+ Hits         8752     8778      +26     
  Misses        760      760              
- Partials      280      281       +1     
```


| [Impacted Files](https://codecov.io/gh/goplus/gop/pull/520?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [exec/bytecode/code.go](https://codecov.io/gh/goplus/gop/pull/520/diff?src=pr&el=tree#diff-ZXhlYy9ieXRlY29kZS9jb2RlLmdv) | `100.00% <ø> (ø)` | |
| [cl/goinstr.go](https://codecov.io/gh/goplus/gop/pull/520/diff?src=pr&el=tree#diff-Y2wvZ29pbnN0ci5nbw==) | `79.29% <55.55%> (-0.71%)` | :arrow_down: |
| [exec/bytecode/goinstr.go](https://codecov.io/gh/goplus/gop/pull/520/diff?src=pr&el=tree#diff-ZXhlYy9ieXRlY29kZS9nb2luc3RyLmdv) | `93.40% <100.00%> (+0.16%)` | :arrow_up: |
| [exec/bytecode/interface.go](https://codecov.io/gh/goplus/gop/pull/520/diff?src=pr&el=tree#diff-ZXhlYy9ieXRlY29kZS9pbnRlcmZhY2UuZ28=) | `99.06% <100.00%> (+0.01%)` | :arrow_up: |
| [exec/golang/expr.go](https://codecov.io/gh/goplus/gop/pull/520/diff?src=pr&el=tree#diff-ZXhlYy9nb2xhbmcvZXhwci5nbw==) | `93.62% <100.00%> (+0.07%)` | :arrow_up: |
| [exec/golang/interface.go](https://codecov.io/gh/goplus/gop/pull/520/diff?src=pr&el=tree#diff-ZXhlYy9nb2xhbmcvaW50ZXJmYWNlLmdv) | `93.33% <100.00%> (+0.09%)` | :arrow_up: |
| [cl/ctx\_check.go](https://codecov.io/gh/goplus/gop/pull/520/diff?src=pr&el=tree#diff-Y2wvY3R4X2NoZWNrLmdv) | `75.91% <0.00%> (+0.81%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/goplus/gop/pull/520?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/520?src=pr&el=footer). Last update [6acaf0d...262d04d](https://codecov.io/gh/goplus/gop/pull/520?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/cl/goinstr.go b/cl/goinstr.go
index 6dfd3d55..1e1ddaa9 100644
--- a/cl/goinstr.go
+++ b/cl/goinstr.go
@@ -263,7 +263,18 @@ func igoNew(ctx *blockCtx, v *ast.CallExpr, isDefer bool) func() {
 	if isDefer {
 		log.Panicln("defer discards result of", ctx.code(v))
 	}
-	panic("todo")
+	if n := len(v.Args); n != 1 {
+		if n == 0 {
+			log.Panicln("missing argument to new")
+		}
+		log.Panicf("too many arguments to new(%v)\n", ctx.code(v.Args[0]))
+	}
+	t := toType(ctx, v.Args[0]).(reflect.Type)
+	ptrT := reflect.PtrTo(t)
+	ctx.infer.Push(&goValue{t: ptrT})
+	return func() {
+		ctx.out.New(t)
+	}
 }
 
 // func complex(r, i FloatType) ComplexType
diff --git a/exec.spec/interface.go b/exec.spec/interface.go
index ac26f0b9..6c5b4d1e 100644
--- a/exec.spec/interface.go
+++ b/exec.spec/interface.go
@@ -337,6 +337,9 @@ type Builder interface {
 	// Zero instr
 	Zero(typ reflect.Type) Builder
 
+	// New instr
+	New(typ reflect.Type) Builder
+
 	// StartStmt emit a `StartStmt` event.
 	StartStmt(stmt interface{}) interface{}
 
diff --git a/exec/bytecode/code.go b/exec/bytecode/code.go
index ffb508df..335599cb 100644
--- a/exec/bytecode/code.go
+++ b/exec/bytecode/code.go
@@ -38,6 +38,7 @@ const (
 	bitsVarScope   = 6
 	bitsAssignOp   = 4
 	bitsIndexOp    = 2
+	bitsIsPtr      = 2
 
 	bitsOpShift = bitsInstr - bitsOp
 	bitsOperand = (1 << bitsOpShift) - 1
@@ -45,6 +46,9 @@ const (
 	bitsOpIndexShift   = bitsInstr - (bitsOp + bitsIndexOp)
 	bitsOpIndexOperand = (1 << bitsOpIndexShift) - 1
 
+	bitsOpZeroShift   = bitsInstr - (bitsOp + bitsIsPtr)
+	bitsOpZeroOperand = (1 << bitsOpZeroShift) - 1
+
 	bitsOpInt        = bitsOp + bitsIntKind
 	bitsOpIntShift   = bitsInstr - bitsOpInt
 	bitsOpIntOperand = (1 << bitsOpIntShift) - 1
@@ -107,7 +111,7 @@ const (
 	opCallGoClosure = 30 // arity(26)
 	opMakeArray     = 31 // funvArity(10) type(16)
 	opMakeMap       = 32 // funvArity(10) type(16)
-	opZero          = 33 // type(26)
+	opZero          = 33 // isPtr(2) type(24)
 	opForPhrase     = 34 // addr(26)
 	opLstComprehens = 35 // addr(26)
 	opMapComprehens = 36 // addr(26)
@@ -193,7 +197,7 @@ var instrInfos = []InstrInfo{
 	opCallGoClosure: {"callGoClosure", "", "arity", 26},                   // arity(26)
 	opMakeArray:     {"makeArray", "funvArity", "type", (10 << 8) | 16},   // funvArity(10) type(16)
 	opMakeMap:       {"makeMap", "funvArity", "type", (10 << 8) | 16},     // funvArity(10) type(16)
-	opZero:          {"zero", "", "type", 26},                             // type(26)
+	opZero:          {"zero", "isPtr", "type", (2 << 8) | 24},             // isPtr(2) type(24)
 	opForPhrase:     {"forPhrase", "", "addr", 26},                        // addr(26)
 	opLstComprehens: {"listComprehension", "", "addr", 26},                // addr(26)
 	opMapComprehens: {"mapComprehension", "", "addr", 26},                 // addr(26)
diff --git a/exec/bytecode/goinstr.go b/exec/bytecode/goinstr.go
index 9c48be4d..2510db61 100644
--- a/exec/bytecode/goinstr.go
+++ b/exec/bytecode/goinstr.go
@@ -331,8 +331,14 @@ func execSlice3(instr Instr, p *Context) {
 }
 
 func execZero(i Instr, p *Context) {
-	typ := getType(i&bitsOperand, p)
-	p.Push(reflect.Zero(typ).Interface())
+	var v reflect.Value
+	typ := getType(i&bitsOpZeroOperand, p)
+	if (i & (1 << bitsOpZeroShift)) != 0 { // isPtr
+		v = reflect.New(typ)
+	} else {
+		v = reflect.Zero(typ)
+	}
+	p.Push(v.Interface())
 }
 
 // ToValues converts []interface{} into []reflect.Value.
@@ -562,6 +568,13 @@ func (p *Builder) TypeCast(from, to reflect.Type) *Builder {
 	return p
 }
 
+// New instr
+func (p *Builder) New(typ reflect.Type) *Builder {
+	i := (opZero << bitsOpShift) | (1 << bitsOpZeroShift) | p.requireType(typ)
+	p.code.data = append(p.code.data, i)
+	return p
+}
+
 // Zero instr
 func (p *Builder) Zero(typ reflect.Type) *Builder {
 	i := (opZero << bitsOpShift) | p.requireType(typ)
diff --git a/exec/bytecode/interface.go b/exec/bytecode/interface.go
index 27a80588..3f46387e 100644
--- a/exec/bytecode/interface.go
+++ b/exec/bytecode/interface.go
@@ -409,6 +409,12 @@ func (p *iBuilder) Zero(typ reflect.Type) exec.Builder {
 	return p
 }
 
+// New instr
+func (p *iBuilder) New(typ reflect.Type) exec.Builder {
+	((*Builder)(p)).New(typ)
+	return p
+}
+
 // StartStmt receives a `StartStmt` event.
 func (p *iBuilder) StartStmt(stmt interface{}) interface{} {
 	return nil
diff --git a/exec/golang/expr.go b/exec/golang/expr.go
index 5322ba87..44e02d66 100644
--- a/exec/golang/expr.go
+++ b/exec/golang/expr.go
@@ -444,6 +444,13 @@ func (p *Builder) Append(typ reflect.Type, arity int) *Builder {
 	return p
 }
 
+// New instr
+func (p *Builder) New(typ reflect.Type) *Builder {
+	p.rhs.Push(newIdent)
+	p.Call(0, false, Type(p, typ))
+	return p
+}
+
 // Make instr
 func (p *Builder) Make(typ reflect.Type, arity int) *Builder {
 	p.rhs.Push(makeIdent)
diff --git a/exec/golang/interface.go b/exec/golang/interface.go
index 389e719b..6ff6b984 100644
--- a/exec/golang/interface.go
+++ b/exec/golang/interface.go
@@ -418,6 +418,12 @@ func (p *iBuilder) GoBuiltin(typ reflect.Type, op exec.GoBuiltin) exec.Builder {
 	return p
 }
 
+// New instr
+func (p *iBuilder) New(typ reflect.Type) exec.Builder {
+	((*Builder)(p)).New(typ)
+	return p
+}
+
 // Zero instr
 func (p *iBuilder) Zero(typ reflect.Type) exec.Builder {
 	((*Builder)(p)).Zero(typ)


Test patch:
diff --git a/cl/expr_test.go b/cl/expr_test.go
index 90f9f664..8139fd10 100644
--- a/cl/expr_test.go
+++ b/cl/expr_test.go
@@ -25,6 +25,27 @@ import (
 
 // -----------------------------------------------------------------------------
 
+func TestNew(t *testing.T) {
+	cltest.Expect(t, `
+		a := new([2]int)
+		println("a:", a)
+		`,
+		"a: &[0 0]\n",
+	)
+}
+
+func _TestNew2(t *testing.T) {
+	cltest.Expect(t, `
+		a := new([2]int)
+		a[0] = 2
+		println("a:", a[0])
+		`,
+		"a: 2\n",
+	)
+}
+
+// -----------------------------------------------------------------------------
+
 func TestAutoProperty(t *testing.T) {
 	script := `
 		import "io"
diff --git a/exec/bytecode/goinstr_test.go b/exec/bytecode/goinstr_test.go
index 7f2f40a4..c46f451f 100644
--- a/exec/bytecode/goinstr_test.go
+++ b/exec/bytecode/goinstr_test.go
@@ -19,6 +19,8 @@ package bytecode
 import (
 	"reflect"
 	"testing"
+
+	"github.com/goplus/gop/exec.spec"
 )
 
 func TestLargeSlice(t *testing.T) {
@@ -570,6 +572,25 @@ func TestAppend2(t *testing.T) {
 	}
 }
 
+func TestAppend3(t *testing.T) {
+	sliceTy := reflect.SliceOf(TyFloat64)
+	code := newBuilder().
+		New(sliceTy).
+		AddrOp(reflect.Slice, exec.OpAddrVal).
+		Push(3.2).
+		Push(1.2).
+		Push(2.4).
+		MakeArray(sliceTy, 3).
+		Append(TyFloat64, -1).
+		Resolve()
+
+	ctx := NewContext(code)
+	ctx.Exec(0, code.Len())
+	if v := checkPop(ctx); !reflect.DeepEqual(v, []float64{3.2, 1.2, 2.4}) {
+		t.Fatal("ret != [3.2, 1.2, 2.4], ret:", v)
+	}
+}
+
 func TestMakeSlice(t *testing.T) {
 	code := newBuilder().
 		Push(2).
diff --git a/exec/golang/testdata/25.new/new.gop b/exec/golang/testdata/25.new/new.gop
new file mode 100644
index 00000000..0c7c53ad
--- /dev/null
+++ b/exec/golang/testdata/25.new/new.gop
@@ -0,0 +1,2 @@
+a := new([3]int)
+println("a:", a)