go.tools/go/types: type the append([]byte, string...) builtin more correctly

This builtin is a little weird in this form as it is (to my knowledge)
the only function that takes a variadic argument of non-slice
type. The language provides no syntax to express this, so we pick
a stringification for such arguments that does not appear in the
language. Specifically, use T... instead of ...T to distinguish it
from the normal case where the type is a slice.

This change lets the go/ssa package produce more efficient IR by
avoiding an extra conversion of the second argument.

LGTM=gri
R=gri
CC=adonovan, golang-codereviews
https://golang.org/cl/108230044
This commit is contained in:
Peter Collingbourne 2014-06-27 16:00:54 -07:00 committed by Robert Griesemer
parent 345b6437fc
commit 87301fe3a6
3 changed files with 12 additions and 8 deletions

View File

@ -100,7 +100,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
}
if isString(x.typ) {
if check.Types != nil {
sig := makeSig(S, S, NewSlice(UniverseByte))
sig := makeSig(S, S, x.typ)
sig.variadic = true
check.recordBuiltinType(call.Fun, sig)
}

View File

@ -21,11 +21,9 @@ var builtinCalls = []struct {
{"append", `var s []int; _ = append(s, 0)`, `func([]int, ...int) []int`},
{"append", `var s []int; _ = (append)(s, 0)`, `func([]int, ...int) []int`},
{"append", `var s []byte; _ = ((append))(s, 0)`, `func([]byte, ...byte) []byte`},
// Note that ...uint8 (instead of ..byte) appears below because that is the type
// that corresponds to Typ[byte] (an alias) - in the other cases, the type name
// is chosen by the source. Either way, byte and uint8 denote identical types.
{"append", `var s []byte; _ = append(s, "foo"...)`, `func([]byte, ...byte) []byte`},
{"append", `type T []byte; var s T; _ = append(s, "foo"...)`, `func(p.T, ...byte) p.T`},
{"append", `var s []byte; _ = append(s, "foo"...)`, `func([]byte, string...) []byte`},
{"append", `type T []byte; var s T; var str string; _ = append(s, str...)`, `func(p.T, string...) p.T`},
{"append", `type T []byte; type U string; var s T; var str U; _ = append(s, str...)`, `func(p.T, p.U...) p.T`},
{"cap", `var s [10]int; _ = cap(s)`, `invalid type`}, // constant
{"cap", `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant

View File

@ -217,8 +217,14 @@ func writeTuple(buf *bytes.Buffer, this *Package, tup *Tuple, variadic bool, vis
}
typ := v.typ
if variadic && i == len(tup.vars)-1 {
buf.WriteString("...")
typ = typ.(*Slice).elem
if s, ok := typ.(*Slice); ok {
buf.WriteString("...")
typ = s.elem
} else {
writeType(buf, this, typ, visited)
buf.WriteString("...")
continue
}
}
writeType(buf, this, typ, visited)
}