mirror of
https://github.com/golang/go
synced 2024-11-23 12:00:14 -07:00
exp/types: filling in more blanks
- implemented built-in complex() - implemented missing expression switch checks R=rsc CC=golang-dev https://golang.org/cl/6920046
This commit is contained in:
parent
0dd0e1ad0c
commit
1a6f8dcbaf
@ -99,9 +99,9 @@ var tests = []string{
|
|||||||
"encoding/asn1",
|
"encoding/asn1",
|
||||||
"encoding/base32",
|
"encoding/base32",
|
||||||
"encoding/base64",
|
"encoding/base64",
|
||||||
// "encoding/binary", // complex() doesn't work yet
|
"encoding/binary",
|
||||||
"encoding/csv",
|
"encoding/csv",
|
||||||
// "encoding/gob", // complex() doesn't work yet
|
"encoding/gob",
|
||||||
"encoding/hex",
|
"encoding/hex",
|
||||||
"encoding/json",
|
"encoding/json",
|
||||||
"encoding/pem",
|
"encoding/pem",
|
||||||
@ -146,7 +146,7 @@ var tests = []string{
|
|||||||
|
|
||||||
"math",
|
"math",
|
||||||
// "math/big", // investigate
|
// "math/big", // investigate
|
||||||
// "math/cmplx", // complex doesn't work yet
|
"math/cmplx",
|
||||||
"math/rand",
|
"math/rand",
|
||||||
|
|
||||||
"mime",
|
"mime",
|
||||||
|
@ -128,13 +128,50 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
|
|||||||
x.mode = novalue
|
x.mode = novalue
|
||||||
|
|
||||||
case _Complex:
|
case _Complex:
|
||||||
|
if !check.complexArg(x) {
|
||||||
|
goto Error
|
||||||
|
}
|
||||||
|
|
||||||
var y operand
|
var y operand
|
||||||
check.expr(&y, args[1], nil, iota)
|
check.expr(&y, args[1], nil, iota)
|
||||||
if y.mode == invalid {
|
if y.mode == invalid {
|
||||||
goto Error
|
goto Error
|
||||||
}
|
}
|
||||||
// TODO(gri) handle complex(a, b) like (a + toImag(b))
|
if !check.complexArg(&y) {
|
||||||
unimplemented()
|
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:
|
case _Copy:
|
||||||
// TODO(gri) implements checks
|
// TODO(gri) implements checks
|
||||||
@ -361,3 +398,12 @@ func unparen(x ast.Expr) ast.Expr {
|
|||||||
}
|
}
|
||||||
return x
|
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
|
||||||
|
}
|
||||||
|
@ -157,6 +157,22 @@ func makeStringConst(lit string) interface{} {
|
|||||||
return nil
|
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.
|
// isZeroConst reports whether the value of constant x is 0.
|
||||||
// x must be normalized.
|
// x must be normalized.
|
||||||
//
|
//
|
||||||
|
@ -427,25 +427,58 @@ func (check *checker) stmt(s ast.Stmt) {
|
|||||||
case *ast.SwitchStmt:
|
case *ast.SwitchStmt:
|
||||||
check.optionalStmt(s.Init)
|
check.optionalStmt(s.Init)
|
||||||
var x operand
|
var x operand
|
||||||
if s.Tag != nil {
|
tag := s.Tag
|
||||||
check.expr(&x, s.Tag, nil, -1)
|
if tag == nil {
|
||||||
} else {
|
// create true tag value and position it at the opening { of the switch
|
||||||
// TODO(gri) should provide a position (see IncDec) for good error messages
|
tag = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true", Obj: Universe.Lookup("true")}
|
||||||
x.mode = constant
|
|
||||||
x.typ = Typ[UntypedBool]
|
|
||||||
x.val = true
|
|
||||||
}
|
}
|
||||||
|
check.expr(&x, tag, nil, -1)
|
||||||
|
|
||||||
check.multipleDefaults(s.Body.List)
|
check.multipleDefaults(s.Body.List)
|
||||||
|
seen := make(map[interface{}]token.Pos)
|
||||||
for _, s := range s.Body.List {
|
for _, s := range s.Body.List {
|
||||||
clause, _ := s.(*ast.CaseClause)
|
clause, _ := s.(*ast.CaseClause)
|
||||||
if clause == nil {
|
if clause == nil {
|
||||||
continue // error reported before
|
continue // error reported before
|
||||||
}
|
}
|
||||||
|
if x.mode != invalid {
|
||||||
for _, expr := range clause.List {
|
for _, expr := range clause.List {
|
||||||
|
x := x // copy of x (don't modify original)
|
||||||
var y operand
|
var y operand
|
||||||
check.expr(&y, expr, nil, -1)
|
check.expr(&y, expr, nil, -1)
|
||||||
// TODO(gri) x and y must be comparable
|
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)
|
check.stmtList(clause.Body)
|
||||||
}
|
}
|
||||||
|
31
src/pkg/exp/types/testdata/builtins.src
vendored
31
src/pkg/exp/types/testdata/builtins.src
vendored
@ -46,10 +46,33 @@ func _close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func _complex() {
|
func _complex() {
|
||||||
_0 := complex /* ERROR "argument" */ ()
|
var i32 int32
|
||||||
_1 := complex /* ERROR "argument" */ (1)
|
var f32 float32
|
||||||
_2 := complex(1, 2)
|
var f64 float64
|
||||||
// TODO(gri) add tests checking types
|
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)
|
complex /* ERROR "not used" */ (1, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
26
src/pkg/exp/types/testdata/stmt0.src
vendored
26
src/pkg/exp/types/testdata/stmt0.src
vendored
@ -101,7 +101,31 @@ func _switches() {
|
|||||||
default /* ERROR "multiple defaults" */ :
|
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 {
|
type I interface {
|
||||||
|
Loading…
Reference in New Issue
Block a user