Commit 0b2caf27 authored by Robert Griesemer's avatar Robert Griesemer

go/types: implement constant string(x) conversions

Fixes #4982.

R=adonovan, r
CC=golang-dev
https://golang.org/cl/7537043
parent b8db56ad
...@@ -30,12 +30,32 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota ...@@ -30,12 +30,32 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota
if x.mode == constant && isConstType(typ) { if x.mode == constant && isConstType(typ) {
// constant conversion // constant conversion
// TODO(gri) implement this typ := underlying(typ).(*Basic)
// For now just implement string(x) where x is an integer,
// as a temporary work-around for issue 4982, which is a
// common issue.
if typ.Kind == String {
switch {
case x.isInteger(check.ctxt):
codepoint, ok := x.val.(int64)
if !ok {
// absolute value too large (or unknown) for conversion;
// same as converting any other out-of-range value - let
// string(codepoint) do the work
codepoint = -1
}
x.val = string(codepoint)
case isString(x.typ):
// nothing to do
default:
goto ErrorMsg
}
}
// TODO(gri) verify the remaining conversions.
} else { } else {
// non-constant conversion // non-constant conversion
if !x.isConvertible(check.ctxt, typ) { if !x.isConvertible(check.ctxt, typ) {
check.invalidOp(conv.Pos(), "cannot convert %s to %s", x, typ) goto ErrorMsg
goto Error
} }
x.mode = value x.mode = value
} }
...@@ -45,8 +65,11 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota ...@@ -45,8 +65,11 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota
x.typ = typ x.typ = typ
return return
ErrorMsg:
check.invalidOp(conv.Pos(), "cannot convert %s to %s", x, typ)
Error: Error:
x.mode = invalid x.mode = invalid
x.expr = conv
} }
func (x *operand) isConvertible(ctxt *Context, T Type) bool { func (x *operand) isConvertible(ctxt *Context, T Type) bool {
......
...@@ -205,6 +205,7 @@ func (x *operand) isAssignable(ctxt *Context, T Type) bool { ...@@ -205,6 +205,7 @@ func (x *operand) isAssignable(ctxt *Context, T Type) bool {
} }
// isInteger reports whether x is a (typed or untyped) integer value. // isInteger reports whether x is a (typed or untyped) integer value.
// TODO(gri) remove ctxt argument - it is not required for UntypedInt.
func (x *operand) isInteger(ctxt *Context) bool { func (x *operand) isInteger(ctxt *Context) bool {
return x.mode == invalid || return x.mode == invalid ||
isInteger(x.typ) || isInteger(x.typ) ||
......
...@@ -8,11 +8,29 @@ package conversions ...@@ -8,11 +8,29 @@ package conversions
// argument count // argument count
var ( var (
_v0 = int /* ERROR "one argument" */ () _ = int /* ERROR "one argument" */ ()
_v1 = int /* ERROR "one argument" */ (1, 2) _ = int /* ERROR "one argument" */ (1, 2)
) )
func string_conversions() {
const A = string(65)
assert(A == "A")
const E = string(-1)
assert(E == "\uFFFD")
assert(E == string(1234567890))
type myint int
assert(A == string(myint(65)))
type mystring string
const _ mystring = mystring("foo")
const _ = string /* ERROR "cannot convert" */ (true)
const _ = string /* ERROR "cannot convert" */ (1.2)
const _ = string /* ERROR "cannot convert" */ (nil)
}
// //
var ( var (
_v2 = int8(0) _ = int8(0)
) )
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment