Skip to content

Commit

Permalink
fix: improve handling of untyped complex numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
mvertes authored and traefiker committed Oct 29, 2019
1 parent 714253c commit 3969ab1
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 49 deletions.
12 changes: 12 additions & 0 deletions _test/complex1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import "fmt"

func main() {
var c complex128
c = 1
fmt.Printf("%T %v\n", c, c)
}

// Output:
// complex128 (1+0i)
12 changes: 12 additions & 0 deletions _test/complex2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import "fmt"

func main() {
c := complex(1, 0)
c += 1
fmt.Printf("%T %v\n", c, c)
}

// Output:
// complex128 (2+0i)
11 changes: 11 additions & 0 deletions _test/complex3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

import "fmt"

func main() {
var s int = 1 + complex(1, 0)
fmt.Printf("%T %v\n", s, s)
}

// Output
// int 2
24 changes: 12 additions & 12 deletions internal/genop/genop.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ var constOp = map[action]func(*node){
aXor: xorConst,
}

var constBltn = map[string]func(*node){
"complex": complexConst,
"imag": imagConst,
"real": realConst,
}

// cfg generates a control flow graph (CFG) from AST (wiring successors in AST)
// and pre-compute frame sizes and indexes for all un-named (temporary) and named
// variables. A list of nodes of init functions is returned.
Expand Down Expand Up @@ -450,6 +456,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.gen = nop
src.level = level
src.findex = dest.findex
if src.typ.untyped && !dest.typ.untyped {
src.typ = dest.typ
}
case n.action == aAssign && src.action == aRecv:
// Assign by reading from a receiving channel
n.gen = nop
Expand All @@ -463,6 +472,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
// TODO: perform constant folding and propagation here
switch {
case dest.typ.cat == interfaceT:
case isComplex(dest.typ.TypeOf()):
// value set in genValue
case !src.rval.IsValid():
// Assign to nil
Expand Down Expand Up @@ -707,6 +717,10 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
} else {
n.findex = sc.add(n.typ)
}
if op, ok := constBltn[n.child[0].ident]; ok && n.anc.action != aAssign {
op(n) // pre-compute non-assigned constant builtin calls
}

case n.child[0].isType(sc):
// Type conversion expression
if isInt(n.child[0].typ.TypeOf()) && n.child[1].kind == basicLit && isFloat(n.child[1].typ.TypeOf()) {
Expand Down
48 changes: 24 additions & 24 deletions interp/op.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 39 additions & 7 deletions interp/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ func assign(n *node) {
svalue[i] = func(*frame) reflect.Value { return reflect.New(t).Elem() }
case isRecursiveStruct(dest.typ, dest.typ.rtype):
svalue[i] = genValueInterfacePtr(src)
case src.typ.untyped && isComplex(dest.typ.TypeOf()):
svalue[i] = genValueComplex(src)
case src.typ.untyped && !dest.typ.untyped:
svalue[i] = genValueAs(src, dest.typ.TypeOf())
default:
Expand Down Expand Up @@ -1891,15 +1893,24 @@ func _close(n *node) {

func _complex(n *node) {
i := n.findex
convertLiteralValue(n.child[1], floatType)
convertLiteralValue(n.child[2], floatType)
value0 := genValue(n.child[1])
value1 := genValue(n.child[2])
c1, c2 := n.child[1], n.child[2]
convertLiteralValue(c1, floatType)
convertLiteralValue(c2, floatType)
value0 := genValue(c1)
value1 := genValue(c2)
next := getExec(n.tnext)

n.exec = func(f *frame) bltn {
f.data[i].SetComplex(complex(value0(f).Float(), value1(f).Float()))
return next
if typ := n.typ.TypeOf(); isComplex(typ) {
n.exec = func(f *frame) bltn {
f.data[i].SetComplex(complex(value0(f).Float(), value1(f).Float()))
return next
}
} else {
// Not a complex type: ignore imaginary part
n.exec = func(f *frame) bltn {
f.data[i].Set(value0(f).Convert(typ))
return next
}
}
}

Expand Down Expand Up @@ -2388,3 +2399,24 @@ func isNotNil(n *node) {
}
}
}

func complexConst(n *node) {
if v0, v1 := n.child[1].rval, n.child[2].rval; v0.IsValid() && v1.IsValid() {
n.rval = reflect.ValueOf(complex(vFloat(v0), vFloat(v1)))
n.gen = nop
}
}

func imagConst(n *node) {
if v := n.child[1].rval; v.IsValid() {
n.rval = reflect.ValueOf(imag(v.Complex()))
n.gen = nop
}
}

func realConst(n *node) {
if v := n.child[1].rval; v.IsValid() {
n.rval = reflect.ValueOf(real(v.Complex()))
n.gen = nop
}
}
5 changes: 4 additions & 1 deletion interp/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,9 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
default:
err = n.cfgErrorf("invalid types %s and %s", t0.Kind(), t1.Kind())
}
if nt0.untyped && nt1.untyped {
t.untyped = true
}
}
case "real", "imag":
if t, err = nodeType(interp, sc, n.child[1]); err != nil {
Expand All @@ -300,7 +303,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
case k == reflect.Complex128:
t = sc.getType("float64")
case t.untyped && isNumber(t.TypeOf()):
t = &itype{cat: valueT, rtype: floatType}
t = &itype{cat: valueT, rtype: floatType, untyped: true}
default:
err = n.cfgErrorf("invalid complex type %s", k)
}
Expand Down
Loading

0 comments on commit 3969ab1

Please sign in to comment.