mirror of
https://github.com/golang/go
synced 2024-11-26 04:07:59 -07:00
[dev.typeparams] cmd/compile/internal/types2: use syntax printer to print expressions
The syntax package has a full-fledged node printer. Use that printer to create the expression strings needed in error messages, and remove the local (essentially) duplicate code for creating expression strings. Change-Id: I03673e5e79b3c1470f8073ebbe840a90fd9053ec Reviewed-on: https://go-review.googlesource.com/c/go/+/282553 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
934f9dc0ef
commit
0aede1205b
@ -379,7 +379,7 @@ func (init *Initializer) String() string {
|
||||
buf.WriteString(lhs.Name())
|
||||
}
|
||||
buf.WriteString(" = ")
|
||||
WriteExpr(&buf, init.Rhs)
|
||||
syntax.Fprint(&buf, init.Rhs, syntax.ShortForm)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ func TestValuesInfo(t *testing.T) {
|
||||
// look for expression
|
||||
var expr syntax.Expr
|
||||
for e := range info.Types {
|
||||
if ExprString(e) == test.expr {
|
||||
if syntax.ShortString(e) == test.expr {
|
||||
expr = e
|
||||
break
|
||||
}
|
||||
@ -306,7 +306,7 @@ func TestTypesInfo(t *testing.T) {
|
||||
// look for expression type
|
||||
var typ Type
|
||||
for e, tv := range info.Types {
|
||||
if ExprString(e) == test.expr {
|
||||
if syntax.ShortString(e) == test.expr {
|
||||
typ = tv.Type
|
||||
break
|
||||
}
|
||||
@ -454,7 +454,7 @@ func TestInferredInfo(t *testing.T) {
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected call expression type %T", call))
|
||||
}
|
||||
if ExprString(fun) == test.fun {
|
||||
if syntax.ShortString(fun) == test.fun {
|
||||
targs = inf.Targs
|
||||
sig = inf.Sig
|
||||
break
|
||||
@ -733,8 +733,8 @@ func TestPredicatesInfo(t *testing.T) {
|
||||
// look for expression predicates
|
||||
got := "<missing>"
|
||||
for e, tv := range info.Types {
|
||||
//println(name, ExprString(e))
|
||||
if ExprString(e) == test.expr {
|
||||
//println(name, syntax.ShortString(e))
|
||||
if syntax.ShortString(e) == test.expr {
|
||||
got = predString(tv)
|
||||
break
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ func (check *Checker) assignVar(lhs syntax.Expr, x *operand) Type {
|
||||
var op operand
|
||||
check.expr(&op, sel.X)
|
||||
if op.mode == mapindex {
|
||||
check.errorf(&z, "cannot assign to struct field %s in map", ExprString(z.expr))
|
||||
check.errorf(&z, "cannot assign to struct field %s in map", syntax.ShortString(z.expr))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ func testBuiltinSignature(t *testing.T, name, src0, want string) {
|
||||
// the recorded type for the built-in must match the wanted signature
|
||||
typ := types[fun].Type
|
||||
if typ == nil {
|
||||
t.Errorf("%s: no type recorded for %s", src0, ExprString(fun))
|
||||
t.Errorf("%s: no type recorded for %s", src0, syntax.ShortString(fun))
|
||||
return
|
||||
}
|
||||
if got := typ.String(); got != want {
|
||||
|
@ -53,7 +53,7 @@ func (check *Checker) sprintf(format string, args ...interface{}) string {
|
||||
case syntax.Pos:
|
||||
arg = a.String()
|
||||
case syntax.Expr:
|
||||
arg = ExprString(a)
|
||||
arg = syntax.ShortString(a)
|
||||
case Object:
|
||||
arg = ObjectString(a, check.qualifier)
|
||||
case Type:
|
||||
|
@ -1,293 +0,0 @@
|
||||
// UNREVIEWED
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file implements printing of expressions.
|
||||
|
||||
package types2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/compile/internal/syntax"
|
||||
)
|
||||
|
||||
// ExprString returns the (possibly shortened) string representation for x.
|
||||
// Shortened representations are suitable for user interfaces but may not
|
||||
// necessarily follow Go syntax.
|
||||
func ExprString(x syntax.Expr) string {
|
||||
var buf bytes.Buffer
|
||||
WriteExpr(&buf, x)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// WriteExpr writes the (possibly shortened) string representation for x to buf.
|
||||
// Shortened representations are suitable for user interfaces but may not
|
||||
// necessarily follow Go syntax.
|
||||
func WriteExpr(buf *bytes.Buffer, x syntax.Expr) {
|
||||
// The AST preserves source-level parentheses so there is
|
||||
// no need to introduce them here to correct for different
|
||||
// operator precedences. (This assumes that the AST was
|
||||
// generated by a Go parser.)
|
||||
|
||||
// TODO(gri): This assumption is not correct - we need to recreate
|
||||
// parentheses in expressions.
|
||||
|
||||
switch x := x.(type) {
|
||||
default:
|
||||
buf.WriteString("(ast: bad expr)") // nil, syntax.BadExpr, syntax.KeyValueExpr
|
||||
|
||||
case *syntax.Name:
|
||||
buf.WriteString(x.Value)
|
||||
|
||||
case *syntax.DotsType:
|
||||
buf.WriteString("...")
|
||||
if x.Elem != nil {
|
||||
WriteExpr(buf, x.Elem)
|
||||
}
|
||||
|
||||
case *syntax.BasicLit:
|
||||
buf.WriteString(x.Value)
|
||||
|
||||
case *syntax.FuncLit:
|
||||
WriteExpr(buf, x.Type)
|
||||
if x.Body != nil && len(x.Body.List) > 0 {
|
||||
buf.WriteString(" {…}") // shortened
|
||||
} else {
|
||||
buf.WriteString(" {}")
|
||||
}
|
||||
|
||||
case *syntax.CompositeLit:
|
||||
WriteExpr(buf, x.Type)
|
||||
if len(x.ElemList) > 0 {
|
||||
buf.WriteString("{…}") // shortened
|
||||
} else {
|
||||
buf.WriteString("{}")
|
||||
}
|
||||
|
||||
case *syntax.ParenExpr:
|
||||
buf.WriteByte('(')
|
||||
WriteExpr(buf, x.X)
|
||||
buf.WriteByte(')')
|
||||
|
||||
case *syntax.SelectorExpr:
|
||||
WriteExpr(buf, x.X)
|
||||
buf.WriteByte('.')
|
||||
buf.WriteString(x.Sel.Value)
|
||||
|
||||
case *syntax.IndexExpr:
|
||||
WriteExpr(buf, x.X)
|
||||
buf.WriteByte('[')
|
||||
WriteExpr(buf, x.Index) // x.Index may be a *ListExpr
|
||||
buf.WriteByte(']')
|
||||
|
||||
case *syntax.SliceExpr:
|
||||
WriteExpr(buf, x.X)
|
||||
buf.WriteByte('[')
|
||||
if x.Index[0] != nil {
|
||||
WriteExpr(buf, x.Index[0])
|
||||
}
|
||||
buf.WriteByte(':')
|
||||
if x.Index[1] != nil {
|
||||
WriteExpr(buf, x.Index[1])
|
||||
}
|
||||
if x.Full {
|
||||
buf.WriteByte(':')
|
||||
if x.Index[2] != nil {
|
||||
WriteExpr(buf, x.Index[2])
|
||||
}
|
||||
}
|
||||
buf.WriteByte(']')
|
||||
|
||||
case *syntax.AssertExpr:
|
||||
WriteExpr(buf, x.X)
|
||||
buf.WriteString(".(")
|
||||
WriteExpr(buf, x.Type)
|
||||
buf.WriteByte(')')
|
||||
|
||||
case *syntax.CallExpr:
|
||||
WriteExpr(buf, x.Fun)
|
||||
buf.WriteByte('(')
|
||||
writeExprList(buf, x.ArgList)
|
||||
if x.HasDots {
|
||||
buf.WriteString("...")
|
||||
}
|
||||
buf.WriteByte(')')
|
||||
|
||||
case *syntax.ListExpr:
|
||||
writeExprList(buf, x.ElemList)
|
||||
|
||||
case *syntax.Operation:
|
||||
// TODO(gri) This would be simpler if x.X == nil meant unary expression.
|
||||
if x.Y == nil {
|
||||
// unary expression
|
||||
buf.WriteString(x.Op.String())
|
||||
WriteExpr(buf, x.X)
|
||||
} else {
|
||||
// binary expression
|
||||
WriteExpr(buf, x.X)
|
||||
buf.WriteByte(' ')
|
||||
buf.WriteString(x.Op.String())
|
||||
buf.WriteByte(' ')
|
||||
WriteExpr(buf, x.Y)
|
||||
}
|
||||
|
||||
// case *ast.StarExpr:
|
||||
// buf.WriteByte('*')
|
||||
// WriteExpr(buf, x.X)
|
||||
|
||||
// case *ast.UnaryExpr:
|
||||
// buf.WriteString(x.Op.String())
|
||||
// WriteExpr(buf, x.X)
|
||||
|
||||
// case *ast.BinaryExpr:
|
||||
// WriteExpr(buf, x.X)
|
||||
// buf.WriteByte(' ')
|
||||
// buf.WriteString(x.Op.String())
|
||||
// buf.WriteByte(' ')
|
||||
// WriteExpr(buf, x.Y)
|
||||
|
||||
case *syntax.ArrayType:
|
||||
if x.Len == nil {
|
||||
buf.WriteString("[...]")
|
||||
} else {
|
||||
buf.WriteByte('[')
|
||||
WriteExpr(buf, x.Len)
|
||||
buf.WriteByte(']')
|
||||
}
|
||||
WriteExpr(buf, x.Elem)
|
||||
|
||||
case *syntax.SliceType:
|
||||
buf.WriteString("[]")
|
||||
WriteExpr(buf, x.Elem)
|
||||
|
||||
case *syntax.StructType:
|
||||
buf.WriteString("struct{")
|
||||
writeFieldList(buf, x.FieldList, "; ", false)
|
||||
buf.WriteByte('}')
|
||||
|
||||
case *syntax.FuncType:
|
||||
buf.WriteString("func")
|
||||
writeSigExpr(buf, x)
|
||||
|
||||
case *syntax.InterfaceType:
|
||||
// separate type list types from method list
|
||||
// TODO(gri) we can get rid of this extra code if writeExprList does the separation
|
||||
var types []syntax.Expr
|
||||
var methods []*syntax.Field
|
||||
for _, f := range x.MethodList {
|
||||
if f.Name != nil && f.Name.Value == "type" {
|
||||
// type list type
|
||||
types = append(types, f.Type)
|
||||
} else {
|
||||
// method or embedded interface
|
||||
methods = append(methods, f)
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString("interface{")
|
||||
writeFieldList(buf, methods, "; ", true)
|
||||
if len(types) > 0 {
|
||||
if len(methods) > 0 {
|
||||
buf.WriteString("; ")
|
||||
}
|
||||
buf.WriteString("type ")
|
||||
writeExprList(buf, types)
|
||||
}
|
||||
buf.WriteByte('}')
|
||||
|
||||
case *syntax.MapType:
|
||||
buf.WriteString("map[")
|
||||
WriteExpr(buf, x.Key)
|
||||
buf.WriteByte(']')
|
||||
WriteExpr(buf, x.Value)
|
||||
|
||||
case *syntax.ChanType:
|
||||
var s string
|
||||
switch x.Dir {
|
||||
case syntax.SendOnly:
|
||||
s = "chan<- "
|
||||
case syntax.RecvOnly:
|
||||
s = "<-chan "
|
||||
default:
|
||||
s = "chan "
|
||||
}
|
||||
buf.WriteString(s)
|
||||
if e, _ := x.Elem.(*syntax.ChanType); x.Dir != syntax.SendOnly && e != nil && e.Dir == syntax.RecvOnly {
|
||||
// don't print chan (<-chan T) as chan <-chan T (but chan<- <-chan T is ok)
|
||||
buf.WriteByte('(')
|
||||
WriteExpr(buf, x.Elem)
|
||||
buf.WriteByte(')')
|
||||
} else {
|
||||
WriteExpr(buf, x.Elem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func writeSigExpr(buf *bytes.Buffer, sig *syntax.FuncType) {
|
||||
buf.WriteByte('(')
|
||||
writeFieldList(buf, sig.ParamList, ", ", false)
|
||||
buf.WriteByte(')')
|
||||
|
||||
res := sig.ResultList
|
||||
n := len(res)
|
||||
if n == 0 {
|
||||
// no result
|
||||
return
|
||||
}
|
||||
|
||||
buf.WriteByte(' ')
|
||||
if n == 1 && res[0].Name == nil {
|
||||
// single unnamed result
|
||||
WriteExpr(buf, res[0].Type)
|
||||
return
|
||||
}
|
||||
|
||||
// multiple or named result(s)
|
||||
buf.WriteByte('(')
|
||||
writeFieldList(buf, res, ", ", false)
|
||||
buf.WriteByte(')')
|
||||
}
|
||||
|
||||
func writeFieldList(buf *bytes.Buffer, list []*syntax.Field, sep string, iface bool) {
|
||||
for i := 0; i < len(list); {
|
||||
f := list[i]
|
||||
if i > 0 {
|
||||
buf.WriteString(sep)
|
||||
}
|
||||
|
||||
// if we don't have a name, we have an embedded type
|
||||
if f.Name == nil {
|
||||
WriteExpr(buf, f.Type)
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// types of interface methods consist of signatures only
|
||||
if sig, _ := f.Type.(*syntax.FuncType); sig != nil && iface {
|
||||
buf.WriteString(f.Name.Value)
|
||||
writeSigExpr(buf, sig)
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
// write the type only once for a sequence of fields with the same type
|
||||
t := f.Type
|
||||
buf.WriteString(f.Name.Value)
|
||||
for i++; i < len(list) && list[i].Type == t; i++ {
|
||||
buf.WriteString(", ")
|
||||
buf.WriteString(list[i].Name.Value)
|
||||
}
|
||||
buf.WriteByte(' ')
|
||||
WriteExpr(buf, t)
|
||||
}
|
||||
}
|
||||
|
||||
func writeExprList(buf *bytes.Buffer, list []syntax.Expr) {
|
||||
for i, x := range list {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
WriteExpr(buf, x)
|
||||
}
|
||||
}
|
@ -9,9 +9,9 @@ import (
|
||||
"testing"
|
||||
|
||||
"cmd/compile/internal/syntax"
|
||||
. "cmd/compile/internal/types2"
|
||||
)
|
||||
|
||||
// TODO(gri) move these tests into syntax package
|
||||
var testExprs = []testEntry{
|
||||
// basic type literals
|
||||
dup("x"),
|
||||
@ -24,8 +24,9 @@ var testExprs = []testEntry{
|
||||
dup("`bar`"),
|
||||
|
||||
// func and composite literals
|
||||
{"func(){}", "func() {}"},
|
||||
{"func(x int) complex128 {}", "func(x int) complex128 {}"},
|
||||
dup("func() {}"),
|
||||
dup("[]int{}"),
|
||||
{"func(x int) complex128 { return 0 }", "func(x int) complex128 {…}"},
|
||||
{"[]int{1, 2, 3}", "[]int{…}"},
|
||||
|
||||
// non-type expressions
|
||||
@ -90,7 +91,7 @@ func TestExprString(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
x := f.DeclList[0].(*syntax.VarDecl).Values
|
||||
if got := ExprString(x); got != test.str {
|
||||
if got := syntax.ShortString(x); got != test.str {
|
||||
t.Errorf("%s: got %s, want %s", test.src, got, test.str)
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ func operandString(x *operand, qf Qualifier) string {
|
||||
|
||||
var expr string
|
||||
if x.expr != nil {
|
||||
expr = ExprString(x.expr)
|
||||
expr = syntax.ShortString(x.expr)
|
||||
} else {
|
||||
switch x.mode {
|
||||
case builtin:
|
||||
|
Loading…
Reference in New Issue
Block a user