diff --git a/_test/complex1.go b/_test/complex1.go new file mode 100644 index 00000000..b9b69d56 --- /dev/null +++ b/_test/complex1.go @@ -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) diff --git a/_test/complex2.go b/_test/complex2.go new file mode 100644 index 00000000..756468a5 --- /dev/null +++ b/_test/complex2.go @@ -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) diff --git a/_test/complex3.go b/_test/complex3.go new file mode 100644 index 00000000..1e895624 --- /dev/null +++ b/_test/complex3.go @@ -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 diff --git a/internal/genop/genop.go b/internal/genop/genop.go index 20f0f816..173168b6 100644 --- a/internal/genop/genop.go +++ b/internal/genop/genop.go @@ -644,11 +644,11 @@ func {{$name}}(n *node) { switch { case c0.rval.IsValid(): s0 := vComplex(c0.rval) - v1 := genValueComplex(c1) + v1 := genComplex(c1) if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - _, s1 := v1(f) + s1 := v1(f) if s0 {{$op.Name}} s1 { dest(f).SetBool(true) return tnext @@ -658,18 +658,18 @@ func {{$name}}(n *node) { } } else { n.exec = func(f *frame) bltn { - _, s1 := v1(f) + s1 := v1(f) dest(f).SetBool(s0 {{$op.Name}} s1) return tnext } } case c1.rval.IsValid(): s1 := vComplex(c1.rval) - v0 := genValueComplex(c0) + v0 := genComplex(c0) if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - _, s0 := v0(f) + s0 := v0(f) if s0 {{$op.Name}} s1 { dest(f).SetBool(true) return tnext @@ -680,19 +680,19 @@ func {{$name}}(n *node) { } else { dest := genValue(n) n.exec = func(f *frame) bltn { - _, s0 := v0(f) + s0 := v0(f) dest(f).SetBool(s0 {{$op.Name}} s1) return tnext } } default: - v0 := genValueComplex(n.child[0]) - v1 := genValueComplex(n.child[1]) + v0 := genComplex(n.child[0]) + v1 := genComplex(n.child[1]) if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - _, s0 := v0(f) - _, s1 := v1(f) + s0 := v0(f) + s1 := v1(f) if s0 {{$op.Name}} s1 { dest(f).SetBool(true) return tnext @@ -702,8 +702,8 @@ func {{$name}}(n *node) { } } else { n.exec = func(f *frame) bltn { - _, s0 := v0(f) - _, s1 := v1(f) + s0 := v0(f) + s1 := v1(f) dest(f).SetBool(s0 {{$op.Name}} s1) return tnext } diff --git a/interp/cfg.go b/interp/cfg.go index 327753f6..04cb2d61 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -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. @@ -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 @@ -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 @@ -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()) { diff --git a/interp/op.go b/interp/op.go index 4767469b..b6c7fa1a 100644 --- a/interp/op.go +++ b/interp/op.go @@ -2154,11 +2154,11 @@ func equal(n *node) { switch { case c0.rval.IsValid(): s0 := vComplex(c0.rval) - v1 := genValueComplex(c1) + v1 := genComplex(c1) if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - _, s1 := v1(f) + s1 := v1(f) if s0 == s1 { dest(f).SetBool(true) return tnext @@ -2168,18 +2168,18 @@ func equal(n *node) { } } else { n.exec = func(f *frame) bltn { - _, s1 := v1(f) + s1 := v1(f) dest(f).SetBool(s0 == s1) return tnext } } case c1.rval.IsValid(): s1 := vComplex(c1.rval) - v0 := genValueComplex(c0) + v0 := genComplex(c0) if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - _, s0 := v0(f) + s0 := v0(f) if s0 == s1 { dest(f).SetBool(true) return tnext @@ -2190,19 +2190,19 @@ func equal(n *node) { } else { dest := genValue(n) n.exec = func(f *frame) bltn { - _, s0 := v0(f) + s0 := v0(f) dest(f).SetBool(s0 == s1) return tnext } } default: - v0 := genValueComplex(n.child[0]) - v1 := genValueComplex(n.child[1]) + v0 := genComplex(n.child[0]) + v1 := genComplex(n.child[1]) if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - _, s0 := v0(f) - _, s1 := v1(f) + s0 := v0(f) + s1 := v1(f) if s0 == s1 { dest(f).SetBool(true) return tnext @@ -2212,8 +2212,8 @@ func equal(n *node) { } } else { n.exec = func(f *frame) bltn { - _, s0 := v0(f) - _, s1 := v1(f) + s0 := v0(f) + s1 := v1(f) dest(f).SetBool(s0 == s1) return tnext } @@ -3739,11 +3739,11 @@ func notEqual(n *node) { switch { case c0.rval.IsValid(): s0 := vComplex(c0.rval) - v1 := genValueComplex(c1) + v1 := genComplex(c1) if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - _, s1 := v1(f) + s1 := v1(f) if s0 != s1 { dest(f).SetBool(true) return tnext @@ -3753,18 +3753,18 @@ func notEqual(n *node) { } } else { n.exec = func(f *frame) bltn { - _, s1 := v1(f) + s1 := v1(f) dest(f).SetBool(s0 != s1) return tnext } } case c1.rval.IsValid(): s1 := vComplex(c1.rval) - v0 := genValueComplex(c0) + v0 := genComplex(c0) if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - _, s0 := v0(f) + s0 := v0(f) if s0 != s1 { dest(f).SetBool(true) return tnext @@ -3775,19 +3775,19 @@ func notEqual(n *node) { } else { dest := genValue(n) n.exec = func(f *frame) bltn { - _, s0 := v0(f) + s0 := v0(f) dest(f).SetBool(s0 != s1) return tnext } } default: - v0 := genValueComplex(n.child[0]) - v1 := genValueComplex(n.child[1]) + v0 := genComplex(n.child[0]) + v1 := genComplex(n.child[1]) if n.fnext != nil { fnext := getExec(n.fnext) n.exec = func(f *frame) bltn { - _, s0 := v0(f) - _, s1 := v1(f) + s0 := v0(f) + s1 := v1(f) if s0 != s1 { dest(f).SetBool(true) return tnext @@ -3797,8 +3797,8 @@ func notEqual(n *node) { } } else { n.exec = func(f *frame) bltn { - _, s0 := v0(f) - _, s1 := v1(f) + s0 := v0(f) + s1 := v1(f) dest(f).SetBool(s0 != s1) return tnext } diff --git a/interp/run.go b/interp/run.go index f839f919..c9cc3da5 100644 --- a/interp/run.go +++ b/interp/run.go @@ -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: @@ -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 + } } } @@ -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 + } +} diff --git a/interp/type.go b/interp/type.go index 9b1940ce..6e491985 100644 --- a/interp/type.go +++ b/interp/type.go @@ -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 { @@ -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) } diff --git a/interp/value.go b/interp/value.go index 997afe42..a3717a98 100644 --- a/interp/value.go +++ b/interp/value.go @@ -187,6 +187,8 @@ func vInt(v reflect.Value) (i int64) { i = int64(v.Uint()) case reflect.Float32, reflect.Float64: i = int64(v.Float()) + case reflect.Complex64, reflect.Complex128: + i = int64(real(v.Complex())) } return } @@ -199,6 +201,8 @@ func vUint(v reflect.Value) (i uint64) { i = v.Uint() case reflect.Float32, reflect.Float64: i = uint64(v.Float()) + case reflect.Complex64, reflect.Complex128: + i = uint64(real(v.Complex())) } return } @@ -225,6 +229,8 @@ func vFloat(v reflect.Value) (i float64) { i = float64(v.Uint()) case reflect.Float32, reflect.Float64: i = v.Float() + case reflect.Complex64, reflect.Complex128: + i = real(v.Complex()) } return } @@ -239,6 +245,10 @@ func genValueInt(n *node) func(*frame) (reflect.Value, int64) { return func(f *frame) (reflect.Value, int64) { v := value(f); return v, int64(v.Uint()) } case reflect.Float32, reflect.Float64: return func(f *frame) (reflect.Value, int64) { v := value(f); return v, int64(v.Float()) } + case reflect.Complex64, reflect.Complex128: + if n.typ.untyped && n.rval.IsValid() && imag(n.rval.Complex()) == 0 { + return func(f *frame) (reflect.Value, int64) { v := value(f); return v, int64(real(v.Complex())) } + } } return nil } @@ -253,6 +263,10 @@ func genValueUint(n *node) func(*frame) (reflect.Value, uint64) { return func(f *frame) (reflect.Value, uint64) { v := value(f); return v, v.Uint() } case reflect.Float32, reflect.Float64: return func(f *frame) (reflect.Value, uint64) { v := value(f); return v, uint64(v.Float()) } + case reflect.Complex64, reflect.Complex128: + if n.typ.untyped && n.rval.IsValid() && imag(n.rval.Complex()) == 0 { + return func(f *frame) (reflect.Value, uint64) { v := value(f); return v, uint64(real(v.Complex())) } + } } return nil } @@ -267,22 +281,31 @@ func genValueFloat(n *node) func(*frame) (reflect.Value, float64) { return func(f *frame) (reflect.Value, float64) { v := value(f); return v, float64(v.Uint()) } case reflect.Float32, reflect.Float64: return func(f *frame) (reflect.Value, float64) { v := value(f); return v, v.Float() } + case reflect.Complex64, reflect.Complex128: + if n.typ.untyped && n.rval.IsValid() && imag(n.rval.Complex()) == 0 { + return func(f *frame) (reflect.Value, float64) { v := value(f); return v, real(v.Complex()) } + } } return nil } -func genValueComplex(n *node) func(*frame) (reflect.Value, complex128) { +func genValueComplex(n *node) func(*frame) reflect.Value { + vc := genComplex(n) + return func(f *frame) reflect.Value { return reflect.ValueOf(vc(f)) } +} + +func genComplex(n *node) func(*frame) complex128 { value := genValue(n) switch n.typ.TypeOf().Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return func(f *frame) (reflect.Value, complex128) { v := value(f); return v, complex(float64(v.Int()), 0) } + return func(f *frame) complex128 { return complex(float64(value(f).Int()), 0) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return func(f *frame) (reflect.Value, complex128) { v := value(f); return v, complex(float64(v.Uint()), 0) } + return func(f *frame) complex128 { return complex(float64(value(f).Uint()), 0) } case reflect.Float32, reflect.Float64: - return func(f *frame) (reflect.Value, complex128) { v := value(f); return v, complex(v.Float(), 0) } + return func(f *frame) complex128 { return complex(value(f).Float(), 0) } case reflect.Complex64, reflect.Complex128: - return func(f *frame) (reflect.Value, complex128) { v := value(f); return v, v.Complex() } + return func(f *frame) complex128 { return value(f).Complex() } } return nil }