package types2
import (
+ "bytes"
"cmd/compile/internal/syntax"
"fmt"
"runtime"
err.desc = append(err.desc, errorDesc{posFor(at), format, args})
}
-func sprintf(qf Qualifier, debug bool, format string, args ...interface{}) string {
+func sprintf(qf Qualifier, tpSubscripts bool, format string, args ...interface{}) string {
for i, arg := range args {
switch a := arg.(type) {
case nil:
case Object:
arg = ObjectString(a, qf)
case Type:
- arg = typeString(a, qf, debug)
+ var buf bytes.Buffer
+ w := newTypeWriter(&buf, qf)
+ w.tpSubscripts = tpSubscripts
+ w.typ(a)
+ arg = buf.String()
case []Type:
- var buf strings.Builder
+ var buf bytes.Buffer
+ w := newTypeWriter(&buf, qf)
+ w.tpSubscripts = tpSubscripts
buf.WriteByte('[')
for i, x := range a {
if i > 0 {
buf.WriteString(", ")
}
- buf.WriteString(typeString(x, qf, debug))
+ w.typ(x)
}
buf.WriteByte(']')
arg = buf.String()
case []*TypeParam:
- var buf strings.Builder
+ var buf bytes.Buffer
+ w := newTypeWriter(&buf, qf)
+ w.tpSubscripts = tpSubscripts
buf.WriteByte('[')
for i, x := range a {
if i > 0 {
buf.WriteString(", ")
}
- buf.WriteString(typeString(x, qf, debug)) // use typeString so we get subscripts when debugging
+ w.typ(x)
}
buf.WriteByte(']')
arg = buf.String()
if check != nil {
qf = check.qualifier
}
- WriteSignature(buf, f.typ.(*Signature), qf)
+ w := newTypeWriter(buf, qf)
+ w.paramNames = false
+ w.signature(f.typ.(*Signature))
return buf.String()
}
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func TypeString(typ Type, qf Qualifier) string {
- return typeString(typ, qf, false)
-}
-
-func typeString(typ Type, qf Qualifier, debug bool) string {
var buf bytes.Buffer
- w := newTypeWriter(&buf, qf)
- w.debug = debug
- w.typ(typ)
+ WriteType(&buf, typ, qf)
return buf.String()
}
}
type typeWriter struct {
- buf *bytes.Buffer
- seen map[Type]bool
- qf Qualifier
- ctxt *Context // if non-nil, we are type hashing
- tparams *TypeParamList // local type parameters
- debug bool // if true, write debug annotations
+ buf *bytes.Buffer
+ seen map[Type]bool
+ qf Qualifier
+ ctxt *Context // if non-nil, we are type hashing
+ tparams *TypeParamList // local type parameters
+ paramNames bool // if set, write function parameter names, otherwise, write types only
+ tpSubscripts bool // if set, write type parameter indices as subscripts
}
func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
- return &typeWriter{buf, make(map[Type]bool), qf, nil, nil, false}
+ return &typeWriter{buf, make(map[Type]bool), qf, nil, nil, true, false}
}
func newTypeHasher(buf *bytes.Buffer, ctxt *Context) *typeWriter {
assert(ctxt != nil)
- return &typeWriter{buf, make(map[Type]bool), nil, ctxt, nil, false}
+ return &typeWriter{buf, make(map[Type]bool), nil, ctxt, nil, false, false}
}
func (w *typeWriter) byte(b byte) {
w.string(fmt.Sprintf("$%d", i))
} else {
w.string(t.obj.name)
- if w.debug || w.ctxt != nil {
+ if w.tpSubscripts || w.ctxt != nil {
w.string(subscript(t.id))
}
}
w.byte(',')
}
// parameter names are ignored for type identity and thus type hashes
- if w.ctxt == nil && v.name != "" {
+ if w.ctxt == nil && v.name != "" && w.paramNames {
w.string(v.name)
w.byte(' ')
}
return sprintf(fset, qf, false, format, args...)
}
-func sprintf(fset *token.FileSet, qf Qualifier, debug bool, format string, args ...any) string {
+func sprintf(fset *token.FileSet, qf Qualifier, tpSubscripts bool, format string, args ...any) string {
for i, arg := range args {
switch a := arg.(type) {
case nil:
case Object:
arg = ObjectString(a, qf)
case Type:
- arg = typeString(a, qf, debug)
+ var buf bytes.Buffer
+ w := newTypeWriter(&buf, qf)
+ w.tpSubscripts = tpSubscripts
+ w.typ(a)
+ arg = buf.String()
case []Type:
- var buf strings.Builder
+ var buf bytes.Buffer
+ w := newTypeWriter(&buf, qf)
+ w.tpSubscripts = tpSubscripts
buf.WriteByte('[')
for i, x := range a {
if i > 0 {
buf.WriteString(", ")
}
- buf.WriteString(typeString(x, qf, debug))
+ w.typ(x)
}
buf.WriteByte(']')
arg = buf.String()
case []*TypeParam:
- var buf strings.Builder
+ var buf bytes.Buffer
+ w := newTypeWriter(&buf, qf)
+ w.tpSubscripts = tpSubscripts
buf.WriteByte('[')
for i, x := range a {
if i > 0 {
buf.WriteString(", ")
}
- buf.WriteString(typeString(x, qf, debug)) // use typeString so we get subscripts when debugging
+ w.typ(x)
}
buf.WriteByte(']')
arg = buf.String()
if check != nil {
qf = check.qualifier
}
- WriteSignature(buf, f.typ.(*Signature), qf)
+ w := newTypeWriter(buf, qf)
+ w.paramNames = false
+ w.signature(f.typ.(*Signature))
return buf.String()
}
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func TypeString(typ Type, qf Qualifier) string {
- return typeString(typ, qf, false)
-}
-
-func typeString(typ Type, qf Qualifier, debug bool) string {
var buf bytes.Buffer
- w := newTypeWriter(&buf, qf)
- w.debug = debug
- w.typ(typ)
+ WriteType(&buf, typ, qf)
return buf.String()
}
}
type typeWriter struct {
- buf *bytes.Buffer
- seen map[Type]bool
- qf Qualifier
- ctxt *Context // if non-nil, we are type hashing
- tparams *TypeParamList // local type parameters
- debug bool // if true, write debug annotations
+ buf *bytes.Buffer
+ seen map[Type]bool
+ qf Qualifier
+ ctxt *Context // if non-nil, we are type hashing
+ tparams *TypeParamList // local type parameters
+ paramNames bool // if set, write function parameter names, otherwise, write types only
+ tpSubscripts bool // if set, write type parameter indices as subscripts
}
func newTypeWriter(buf *bytes.Buffer, qf Qualifier) *typeWriter {
- return &typeWriter{buf, make(map[Type]bool), qf, nil, nil, false}
+ return &typeWriter{buf, make(map[Type]bool), qf, nil, nil, true, false}
}
func newTypeHasher(buf *bytes.Buffer, ctxt *Context) *typeWriter {
assert(ctxt != nil)
- return &typeWriter{buf, make(map[Type]bool), nil, ctxt, nil, false}
+ return &typeWriter{buf, make(map[Type]bool), nil, ctxt, nil, false, false}
}
func (w *typeWriter) byte(b byte) {
w.string(fmt.Sprintf("$%d", i))
} else {
w.string(t.obj.name)
- if w.debug || w.ctxt != nil {
+ if w.tpSubscripts || w.ctxt != nil {
w.string(subscript(t.id))
}
}
w.byte(',')
}
// parameter names are ignored for type identity and thus type hashes
- if w.ctxt == nil && v.name != "" {
+ if w.ctxt == nil && v.name != "" && w.paramNames {
w.string(v.name)
w.byte(' ')
}
T1{}.foo /* ERROR cannot call pointer method foo on T1 */ ()
x.Foo /* ERROR "x.Foo undefined \(type I1 has no field or method Foo, but does have foo\)" */ ()
- _ = i2 /* ERROR impossible type assertion: i2\.\(\*T1\)\n\t\*T1 does not implement I2 \(wrong type for method foo\)\n\t\thave foo\(\)\n\t\twant foo\(x int\) */ .(*T1)
+ _ = i2 /* ERROR impossible type assertion: i2\.\(\*T1\)\n\t\*T1 does not implement I2 \(wrong type for method foo\)\n\t\thave foo\(\)\n\t\twant foo\(int\) */ .(*T1)
i1 = i0 /* ERROR cannot use i0 .* as I1 value in assignment: I0 does not implement I1 \(missing method foo\) */
i1 = t0 /* ERROR .* t0 .* as I1 .*: \*T0 does not implement I1 \(missing method foo\) */
- i1 = i2 /* ERROR .* i2 .* as I1 .*: I2 does not implement I1 \(wrong type for method foo\)\n\t\thave foo\(x int\)\n\t\twant foo\(\) */
- i1 = t2 /* ERROR .* t2 .* as I1 .*: \*T2 does not implement I1 \(wrong type for method foo\)\n\t\thave foo\(x int\)\n\t\twant foo\(\) */
- i2 = i1 /* ERROR .* i1 .* as I2 .*: I1 does not implement I2 \(wrong type for method foo\)\n\t\thave foo\(\)\n\t\twant foo\(x int\) */
- i2 = t1 /* ERROR .* t1 .* as I2 .*: \*T1 does not implement I2 \(wrong type for method foo\)\n\t\thave foo\(\)\n\t\twant foo\(x int\) */
+ i1 = i2 /* ERROR .* i2 .* as I1 .*: I2 does not implement I1 \(wrong type for method foo\)\n\t\thave foo\(int\)\n\t\twant foo\(\) */
+ i1 = t2 /* ERROR .* t2 .* as I1 .*: \*T2 does not implement I1 \(wrong type for method foo\)\n\t\thave foo\(int\)\n\t\twant foo\(\) */
+ i2 = i1 /* ERROR .* i1 .* as I2 .*: I1 does not implement I2 \(wrong type for method foo\)\n\t\thave foo\(\)\n\t\twant foo\(int\) */
+ i2 = t1 /* ERROR .* t1 .* as I2 .*: \*T1 does not implement I2 \(wrong type for method foo\)\n\t\thave foo\(\)\n\t\twant foo\(int\) */
_ = func() I1 { return i0 /* ERROR cannot use i0 .* as I1 value in return statement: I0 does not implement I1 \(missing method foo\) */ }
_ = func() I1 { return t0 /* ERROR .* t0 .* as I1 .*: \*T0 does not implement I1 \(missing method foo\) */ }
- _ = func() I1 { return i2 /* ERROR .* i2 .* as I1 .*: I2 does not implement I1 \(wrong type for method foo\)\n\t\thave foo\(x int\)\n\t\twant foo\(\) */ }
- _ = func() I1 { return t2 /* ERROR .* t2 .* as I1 .*: \*T2 does not implement I1 \(wrong type for method foo\)\n\t\thave foo\(x int\)\n\t\twant foo\(\) */ }
- _ = func() I2 { return i1 /* ERROR .* i1 .* as I2 .*: I1 does not implement I2 \(wrong type for method foo\)\n\t\thave foo\(\)\n\t\twant foo\(x int\) */ }
- _ = func() I2 { return t1 /* ERROR .* t1 .* as I2 .*: \*T1 does not implement I2 \(wrong type for method foo\)\n\t\thave foo\(\)\n\t\twant foo\(x int\) */ }
+ _ = func() I1 { return i2 /* ERROR .* i2 .* as I1 .*: I2 does not implement I1 \(wrong type for method foo\)\n\t\thave foo\(int\)\n\t\twant foo\(\) */ }
+ _ = func() I1 { return t2 /* ERROR .* t2 .* as I1 .*: \*T2 does not implement I1 \(wrong type for method foo\)\n\t\thave foo\(int\)\n\t\twant foo\(\) */ }
+ _ = func() I2 { return i1 /* ERROR .* i1 .* as I2 .*: I1 does not implement I2 \(wrong type for method foo\)\n\t\thave foo\(\)\n\t\twant foo\(int\) */ }
+ _ = func() I2 { return t1 /* ERROR .* t1 .* as I2 .*: \*T1 does not implement I2 \(wrong type for method foo\)\n\t\thave foo\(\)\n\t\twant foo\(int\) */ }
// a few more - less exhaustive now
f(i0 /* ERROR missing method foo */ , i1 /* ERROR wrong type for method foo */ )
_ = [...]I1{i0 /* ERROR cannot use i0 .* as I1 value in array or slice literal: I0 does not implement I1 \(missing method foo\) */ }
- _ = [...]I1{i2 /* ERROR cannot use i2 .* as I1 value in array or slice literal: I2 does not implement I1 \(wrong type for method foo\)\n\t\thave foo\(x int\)\n\t\twant foo\(\) */ }
+ _ = [...]I1{i2 /* ERROR cannot use i2 .* as I1 value in array or slice literal: I2 does not implement I1 \(wrong type for method foo\)\n\t\thave foo\(int\)\n\t\twant foo\(\) */ }
_ = []I1{i0 /* ERROR missing method foo */ }
_ = []I1{i2 /* ERROR wrong type for method foo */ }
_ = map[int]I1{0: i0 /* ERROR missing method foo */ }
--- /dev/null
+// Copyright 2022 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.
+
+package p
+
+import (
+ "context"
+ "database/sql"
+)
+
+type I interface {
+ m(int, int, *int, int)
+}
+
+type T struct{}
+
+func (_ *T) m(a, b, c, d int) {}
+
+var _ I = new /* ERROR have m\(int, int, int, int\)\n\t\twant m\(int, int, \*int, int\) */ (T)
+
+// (slightly modified) test case from issue
+
+type Result struct {
+ Value string
+}
+
+type Executor interface {
+ Execute(context.Context, sql.Stmt, int, []sql.NamedArg, int) (Result, error)
+}
+
+type myExecutor struct{}
+
+func (_ *myExecutor) Execute(ctx context.Context, stmt sql.Stmt, maxrows int, args []sql.NamedArg, urgency int) (*Result, error) {
+ return &Result{}, nil
+}
+
+var ex Executor = new /* ERROR have Execute\(context\.Context, sql\.Stmt, int, \[\]sql\.NamedArg, int\) \(\*Result, error\)\n\t\twant Execute\(context\.Context, sql\.Stmt, int, \[\]sql\.NamedArg, int\) \(Result, error\) */ (myExecutor)