Skip to content

Commit 0b2caf2

Browse files
committed
go/types: implement constant string(x) conversions
Fixes #4982. R=adonovan, r CC=golang-dev https://golang.org/cl/7537043
1 parent b8db56a commit 0b2caf2

File tree

3 files changed

+49
-7
lines changed

3 files changed

+49
-7
lines changed

src/pkg/go/types/conversions.go

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,32 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota
3030

3131
if x.mode == constant && isConstType(typ) {
3232
// constant conversion
33-
// TODO(gri) implement this
33+
typ := underlying(typ).(*Basic)
34+
// For now just implement string(x) where x is an integer,
35+
// as a temporary work-around for issue 4982, which is a
36+
// common issue.
37+
if typ.Kind == String {
38+
switch {
39+
case x.isInteger(check.ctxt):
40+
codepoint, ok := x.val.(int64)
41+
if !ok {
42+
// absolute value too large (or unknown) for conversion;
43+
// same as converting any other out-of-range value - let
44+
// string(codepoint) do the work
45+
codepoint = -1
46+
}
47+
x.val = string(codepoint)
48+
case isString(x.typ):
49+
// nothing to do
50+
default:
51+
goto ErrorMsg
52+
}
53+
}
54+
// TODO(gri) verify the remaining conversions.
3455
} else {
3556
// non-constant conversion
3657
if !x.isConvertible(check.ctxt, typ) {
37-
check.invalidOp(conv.Pos(), "cannot convert %s to %s", x, typ)
38-
goto Error
58+
goto ErrorMsg
3959
}
4060
x.mode = value
4161
}
@@ -45,8 +65,11 @@ func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota
4565
x.typ = typ
4666
return
4767

68+
ErrorMsg:
69+
check.invalidOp(conv.Pos(), "cannot convert %s to %s", x, typ)
4870
Error:
4971
x.mode = invalid
72+
x.expr = conv
5073
}
5174

5275
func (x *operand) isConvertible(ctxt *Context, T Type) bool {

src/pkg/go/types/operand.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ func (x *operand) isAssignable(ctxt *Context, T Type) bool {
205205
}
206206

207207
// isInteger reports whether x is a (typed or untyped) integer value.
208+
// TODO(gri) remove ctxt argument - it is not required for UntypedInt.
208209
func (x *operand) isInteger(ctxt *Context) bool {
209210
return x.mode == invalid ||
210211
isInteger(x.typ) ||

src/pkg/go/types/testdata/conversions.src

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,29 @@ package conversions
88

99
// argument count
1010
var (
11-
_v0 = int /* ERROR "one argument" */ ()
12-
_v1 = int /* ERROR "one argument" */ (1, 2)
11+
_ = int /* ERROR "one argument" */ ()
12+
_ = int /* ERROR "one argument" */ (1, 2)
1313
)
1414

15-
//
15+
func string_conversions() {
16+
const A = string(65)
17+
assert(A == "A")
18+
const E = string(-1)
19+
assert(E == "\uFFFD")
20+
assert(E == string(1234567890))
21+
22+
type myint int
23+
assert(A == string(myint(65)))
24+
25+
type mystring string
26+
const _ mystring = mystring("foo")
27+
28+
const _ = string /* ERROR "cannot convert" */ (true)
29+
const _ = string /* ERROR "cannot convert" */ (1.2)
30+
const _ = string /* ERROR "cannot convert" */ (nil)
31+
}
32+
33+
//
1634
var (
17-
_v2 = int8(0)
35+
_ = int8(0)
1836
)

0 commit comments

Comments
 (0)