"encoding/asn1",
"encoding/base32",
"encoding/base64",
- // "encoding/binary", // complex() doesn't work yet
+ "encoding/binary",
"encoding/csv",
- // "encoding/gob", // complex() doesn't work yet
+ "encoding/gob",
"encoding/hex",
"encoding/json",
"encoding/pem",
"math",
// "math/big", // investigate
- // "math/cmplx", // complex doesn't work yet
+ "math/cmplx",
"math/rand",
"mime",
x.mode = novalue
case _Complex:
+ if !check.complexArg(x) {
+ goto Error
+ }
+
var y operand
check.expr(&y, args[1], nil, iota)
if y.mode == invalid {
goto Error
}
- // TODO(gri) handle complex(a, b) like (a + toImag(b))
- unimplemented()
+ if !check.complexArg(&y) {
+ goto Error
+ }
+
+ check.convertUntyped(x, y.typ)
+ if x.mode == invalid {
+ goto Error
+ }
+ check.convertUntyped(&y, x.typ)
+ if y.mode == invalid {
+ goto Error
+ }
+
+ if !isIdentical(x.typ, y.typ) {
+ check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+ goto Error
+ }
+
+ if x.mode == constant && y.mode == constant {
+ x.val = binaryOpConst(x.val, toImagConst(y.val), token.ADD, false)
+ } else {
+ x.mode = value
+ }
+
+ switch underlying(x.typ).(*Basic).Kind {
+ case Float32:
+ x.typ = Typ[Complex64]
+ case Float64:
+ x.typ = Typ[Complex128]
+ case UntypedInt, UntypedRune, UntypedFloat:
+ x.typ = Typ[UntypedComplex]
+ default:
+ check.invalidArg(x.pos(), "float32 or float64 arguments expected")
+ goto Error
+ }
case _Copy:
// TODO(gri) implements checks
}
return x
}
+
+func (check *checker) complexArg(x *operand) bool {
+ t, _ := underlying(x.typ).(*Basic)
+ if t != nil && (t.Info&IsFloat != 0 || t.Kind == UntypedInt || t.Kind == UntypedRune) {
+ return true
+ }
+ check.invalidArg(x.pos(), "%s must be a float32, float64, or an untyped non-complex numeric constant", x)
+ return false
+}
return nil
}
+// toImagConst returns the constant complex(0, x) for a non-complex x.
+func toImagConst(x interface{}) interface{} {
+ var im *big.Rat
+ switch x := x.(type) {
+ case int64:
+ im = big.NewRat(x, 1)
+ case *big.Int:
+ im = new(big.Rat).SetFrac(x, int1)
+ case *big.Rat:
+ im = x
+ default:
+ unreachable()
+ }
+ return complex{rat0, im}
+}
+
// isZeroConst reports whether the value of constant x is 0.
// x must be normalized.
//
case *ast.SwitchStmt:
check.optionalStmt(s.Init)
var x operand
- if s.Tag != nil {
- check.expr(&x, s.Tag, nil, -1)
- } else {
- // TODO(gri) should provide a position (see IncDec) for good error messages
- x.mode = constant
- x.typ = Typ[UntypedBool]
- x.val = true
+ tag := s.Tag
+ if tag == nil {
+ // create true tag value and position it at the opening { of the switch
+ tag = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true", Obj: Universe.Lookup("true")}
}
+ check.expr(&x, tag, nil, -1)
check.multipleDefaults(s.Body.List)
+ seen := make(map[interface{}]token.Pos)
for _, s := range s.Body.List {
clause, _ := s.(*ast.CaseClause)
if clause == nil {
continue // error reported before
}
- for _, expr := range clause.List {
- var y operand
- check.expr(&y, expr, nil, -1)
- // TODO(gri) x and y must be comparable
+ if x.mode != invalid {
+ for _, expr := range clause.List {
+ x := x // copy of x (don't modify original)
+ var y operand
+ check.expr(&y, expr, nil, -1)
+ if y.mode == invalid {
+ continue // error reported before
+ }
+ // If we have a constant case value, it must appear only
+ // once in the switch statement. Determine if there is a
+ // duplicate entry, but only report an error there are no
+ // other errors.
+ var dupl token.Pos
+ if y.mode == constant {
+ // TODO(gri) This code doesn't work correctly for
+ // large integer, floating point, or
+ // complex values - the respective struct
+ // comparison is shallow. Need to use a
+ // has function to index the seen map.
+ dupl = seen[y.val]
+ seen[y.val] = y.pos()
+ }
+ // TODO(gri) The convertUntyped call pair below appears in other places. Factor!
+ // Order matters: By comparing y against x, error positions are at the case values.
+ check.convertUntyped(&y, x.typ)
+ if y.mode == invalid {
+ continue // error reported before
+ }
+ check.convertUntyped(&x, y.typ)
+ if x.mode == invalid {
+ continue // error reported before
+ }
+ check.comparison(&y, &x, token.EQL)
+ if y.mode != invalid && dupl.IsValid() {
+ check.errorf(y.pos(), "%s is duplicate case in switch\n\tprevious case at %s",
+ &y, check.fset.Position(dupl))
+ }
+ }
}
check.stmtList(clause.Body)
}
}
func _complex() {
- _0 := complex /* ERROR "argument" */ ()
- _1 := complex /* ERROR "argument" */ (1)
- _2 := complex(1, 2)
- // TODO(gri) add tests checking types
+ var i32 int32
+ var f32 float32
+ var f64 float64
+ var c64 complex64
+ _ = complex /* ERROR "argument" */ ()
+ _ = complex /* ERROR "argument" */ (1)
+ _ = complex(true /* ERROR "invalid argument" */ , 0)
+ _ = complex(i32 /* ERROR "invalid argument" */ , 0)
+ _ = complex("foo" /* ERROR "invalid argument" */ , 0)
+ _ = complex(c64 /* ERROR "invalid argument" */ , 0)
+ _ = complex(0, true /* ERROR "invalid argument" */ )
+ _ = complex(0, i32 /* ERROR "invalid argument" */ )
+ _ = complex(0, "foo" /* ERROR "invalid argument" */ )
+ _ = complex(0, c64 /* ERROR "invalid argument" */ )
+ _ = complex(f32, f32)
+ _ = complex(f32, 1)
+ _ = complex(f32, 1.0)
+ _ = complex(f32, 'a')
+ _ = complex(f64, f64)
+ _ = complex(f64, 1)
+ _ = complex(f64, 1.0)
+ _ = complex(f64, 'a')
+ _ = complex(f32 /* ERROR "mismatched types" */, f64)
+ _ = complex(f64 /* ERROR "mismatched types" */, f32)
+ _ = complex(1, 1)
+ _ = complex(1, 1.1)
+ _ = complex(1, 'a')
complex /* ERROR "not used" */ (1, 2)
}
default /* ERROR "multiple defaults" */ :
}
- // TODO(gri) more tests
+ switch {
+ case 1 /* ERROR "cannot convert" */ :
+ }
+
+ switch int32(x) {
+ case 1, 2:
+ case x /* ERROR "cannot compare" */ :
+ }
+
+ switch x {
+ case 1 /* ERROR "overflows int" */ << 100:
+ }
+
+ switch x {
+ case 1:
+ case 1 /* ERROR "duplicate case" */ :
+ case 2, 3, 4:
+ case 1 /* ERROR "duplicate case" */ :
+ }
+
+ // TODO(gri) duplicate 64bit values that don't fit into an int64 are not yet detected
+ switch uint64(x) {
+ case 1<<64-1:
+ case 1<<64-1:
+ }
}
type I interface {