From 4ceb5a94d83b823fe7c3e4d25541854759651933 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 10 Jan 2022 10:33:16 -0800 Subject: [PATCH] go/types, types2: refer to type parameter if so for interface pointer errors Follow-up on comment in CL 376914. Also: - add missing check != nil test in assignableTo - use check.sprintf rather than fmt.Sprintf in missingMethodReason For #48312. Change-Id: Ie209b4101a7f2c279e42a59987d0068079c8b69f Reviewed-on: https://go-review.googlesource.com/c/go/+/377375 Trust: Robert Griesemer Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/call.go | 2 +- src/cmd/compile/internal/types2/lookup.go | 23 ++++++++++++------- src/cmd/compile/internal/types2/operand.go | 2 +- .../types2/testdata/fixedbugs/issue47747.go2 | 2 +- .../types2/testdata/fixedbugs/issue48312.go2 | 2 +- src/go/types/call.go | 2 +- src/go/types/lookup.go | 23 ++++++++++++------- src/go/types/operand.go | 2 +- .../types/testdata/fixedbugs/issue47747.go2 | 2 +- .../types/testdata/fixedbugs/issue48312.go2 | 2 +- 10 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 1c3bf48b08..ea1c27aa2b 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -544,7 +544,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { var why string if isInterfacePtr(x.typ) { - why = check.sprintf("type %s is pointer to interface, not interface", x.typ) + why = check.interfacePtrError(x.typ) } else { why = check.sprintf("type %s has no field or method %s", x.typ, sel) // Check if capitalization of sel matters and provide better error message in that case. diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index aa1ab8ac98..5428b667a5 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -7,7 +7,6 @@ package types2 import ( - "fmt" "strings" ) @@ -429,17 +428,17 @@ func (check *Checker) missingMethodReason(V, T Type, m, wrongType *Func) string if wrongType != nil { if Identical(m.typ, wrongType.typ) { if m.Name() == wrongType.Name() { - r = fmt.Sprintf("(%s has pointer receiver)", mname) + r = check.sprintf("(%s has pointer receiver)", mname) } else { - r = fmt.Sprintf("(missing %s)\n\t\thave %s^^%s\n\t\twant %s^^%s", + r = check.sprintf("(missing %s)\n\t\thave %s^^%s\n\t\twant %s^^%s", mname, wrongType.Name(), wrongType.typ, m.Name(), m.typ) } } else { if check.conf.CompilerErrorMessages { - r = fmt.Sprintf("(wrong type for %s)\n\t\thave %s^^%s\n\t\twant %s^^%s", + r = check.sprintf("(wrong type for %s)\n\t\thave %s^^%s\n\t\twant %s^^%s", mname, wrongType.Name(), wrongType.typ, m.Name(), m.typ) } else { - r = fmt.Sprintf("(wrong type for %s: have %s, want %s)", + r = check.sprintf("(wrong type for %s: have %s, want %s)", mname, wrongType.typ, m.typ) } } @@ -450,13 +449,13 @@ func (check *Checker) missingMethodReason(V, T Type, m, wrongType *Func) string r = strings.Replace(r, "^^func", "", -1) } else if IsInterface(T) { if isInterfacePtr(V) { - r = fmt.Sprintf("(type %s is pointer to interface, not interface)", V) + r = "(" + check.interfacePtrError(V) + ")" } } else if isInterfacePtr(T) { - r = fmt.Sprintf("(type %s is pointer to interface, not interface)", T) + r = "(" + check.interfacePtrError(T) + ")" } if r == "" { - r = fmt.Sprintf("(missing %s)", mname) + r = check.sprintf("(missing %s)", mname) } return r } @@ -466,6 +465,14 @@ func isInterfacePtr(T Type) bool { return p != nil && IsInterface(p.base) } +func (check *Checker) interfacePtrError(T Type) string { + assert(isInterfacePtr(T)) + if p, _ := under(T).(*Pointer); isTypeParam(p.base) { + return check.sprintf("type %s is pointer to type parameter, not type parameter", T) + } + return check.sprintf("type %s is pointer to interface, not interface", T) +} + // assertableTo reports whether a value of type V can be asserted to have type T. // It returns (nil, false) as affirmative answer. Otherwise it returns a missing // method required by V and whether it is missing or just has the wrong type. diff --git a/src/cmd/compile/internal/types2/operand.go b/src/cmd/compile/internal/types2/operand.go index 69e3a0a832..1eb24d136b 100644 --- a/src/cmd/compile/internal/types2/operand.go +++ b/src/cmd/compile/internal/types2/operand.go @@ -292,7 +292,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er if Ti, ok := Tu.(*Interface); ok && Tp == nil { if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* !Implements(V, Ti) */ { if reason != nil { - if check.conf.CompilerErrorMessages { + if check != nil && check.conf.CompilerErrorMessages { *reason = check.sprintf("%s does not implement %s %s", x.typ, T, check.missingMethodReason(x.typ, T, m, wrongType)) } else { diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47747.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47747.go2 index edde497f5a..6f09fc2f57 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47747.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47747.go2 @@ -20,7 +20,7 @@ func _[P interface{ m() }](x P) { x.m() // (&x).m doesn't exist because &x is of type *P // and pointers to type parameters don't have methods - (&x).m /* ERROR type \*P is pointer to interface, not interface */ () + (&x).m /* ERROR type \*P is pointer to type parameter, not type parameter */ () } diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48312.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48312.go2 index 6e5911d0aa..2fdb7cad94 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48312.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48312.go2 @@ -16,5 +16,5 @@ func _(p P) { } func _[P T](p *P) { - p.m /* ERROR type \*P is pointer to interface, not interface */ () + p.m /* ERROR type \*P is pointer to type parameter, not type parameter */ () } diff --git a/src/go/types/call.go b/src/go/types/call.go index 4a31ec2586..d5b83451c4 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -546,7 +546,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { var why string if isInterfacePtr(x.typ) { - why = check.sprintf("type %s is pointer to interface, not interface", x.typ) + why = check.interfacePtrError(x.typ) } else { why = check.sprintf("type %s has no field or method %s", x.typ, sel) // Check if capitalization of sel matters and provide better error message in that case. diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 1b820d5403..598f615247 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -7,7 +7,6 @@ package types import ( - "fmt" "strings" ) @@ -403,17 +402,17 @@ func (check *Checker) missingMethodReason(V, T Type, m, wrongType *Func) string if wrongType != nil { if Identical(m.typ, wrongType.typ) { if m.Name() == wrongType.Name() { - r = fmt.Sprintf("(%s has pointer receiver)", mname) + r = check.sprintf("(%s has pointer receiver)", mname) } else { - r = fmt.Sprintf("(missing %s)\n\t\thave %s^^%s\n\t\twant %s^^%s", + r = check.sprintf("(missing %s)\n\t\thave %s^^%s\n\t\twant %s^^%s", mname, wrongType.Name(), wrongType.typ, m.Name(), m.typ) } } else { if compilerErrorMessages { - r = fmt.Sprintf("(wrong type for %s)\n\t\thave %s^^%s\n\t\twant %s^^%s", + r = check.sprintf("(wrong type for %s)\n\t\thave %s^^%s\n\t\twant %s^^%s", mname, wrongType.Name(), wrongType.typ, m.Name(), m.typ) } else { - r = fmt.Sprintf("(wrong type for %s: have %s, want %s)", + r = check.sprintf("(wrong type for %s: have %s, want %s)", mname, wrongType.typ, m.typ) } } @@ -424,13 +423,13 @@ func (check *Checker) missingMethodReason(V, T Type, m, wrongType *Func) string r = strings.Replace(r, "^^func", "", -1) } else if IsInterface(T) { if isInterfacePtr(V) { - r = fmt.Sprintf("(type %s is pointer to interface, not interface)", V) + r = "(" + check.interfacePtrError(V) + ")" } } else if isInterfacePtr(T) { - r = fmt.Sprintf("(type %s is pointer to interface, not interface)", T) + r = "(" + check.interfacePtrError(T) + ")" } if r == "" { - r = fmt.Sprintf("(missing %s)", mname) + r = check.sprintf("(missing %s)", mname) } return r } @@ -440,6 +439,14 @@ func isInterfacePtr(T Type) bool { return p != nil && IsInterface(p.base) } +func (check *Checker) interfacePtrError(T Type) string { + assert(isInterfacePtr(T)) + if p, _ := under(T).(*Pointer); isTypeParam(p.base) { + return check.sprintf("type %s is pointer to type parameter, not type parameter", T) + } + return check.sprintf("type %s is pointer to interface, not interface", T) +} + // assertableTo reports whether a value of type V can be asserted to have type T. // It returns (nil, false) as affirmative answer. Otherwise it returns a missing // method required by V and whether it is missing or just has the wrong type. diff --git a/src/go/types/operand.go b/src/go/types/operand.go index d669981cf2..d119b5ee7b 100644 --- a/src/go/types/operand.go +++ b/src/go/types/operand.go @@ -282,7 +282,7 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er if Ti, ok := Tu.(*Interface); ok && Tp == nil { if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ { if reason != nil { - if compilerErrorMessages { + if check != nil && compilerErrorMessages { *reason = check.sprintf("%s does not implement %s %s", x.typ, T, check.missingMethodReason(x.typ, T, m, wrongType)) } else { diff --git a/src/go/types/testdata/fixedbugs/issue47747.go2 b/src/go/types/testdata/fixedbugs/issue47747.go2 index edde497f5a..6f09fc2f57 100644 --- a/src/go/types/testdata/fixedbugs/issue47747.go2 +++ b/src/go/types/testdata/fixedbugs/issue47747.go2 @@ -20,7 +20,7 @@ func _[P interface{ m() }](x P) { x.m() // (&x).m doesn't exist because &x is of type *P // and pointers to type parameters don't have methods - (&x).m /* ERROR type \*P is pointer to interface, not interface */ () + (&x).m /* ERROR type \*P is pointer to type parameter, not type parameter */ () } diff --git a/src/go/types/testdata/fixedbugs/issue48312.go2 b/src/go/types/testdata/fixedbugs/issue48312.go2 index 6e5911d0aa..2fdb7cad94 100644 --- a/src/go/types/testdata/fixedbugs/issue48312.go2 +++ b/src/go/types/testdata/fixedbugs/issue48312.go2 @@ -16,5 +16,5 @@ func _(p P) { } func _[P T](p *P) { - p.m /* ERROR type \*P is pointer to interface, not interface */ () + p.m /* ERROR type \*P is pointer to type parameter, not type parameter */ () } -- 2.50.0