go/types, types2: better error when selecting field on type rather than value

Fixes #6814.

Change-Id: I659670998f8e89400d03d40189e8c54f7e705cdc
Reviewed-on: https://go-review.googlesource.com/c/go/+/738040
Reviewed-by: Alan Donovan <adonovan@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2026-01-21 14:40:04 -08:00 committed by Gopher Robot
parent 455282911a
commit 2d37c20778
5 changed files with 43 additions and 6 deletions

View file

@ -835,6 +835,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, wantType bool
check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (%s)", x.expr, sel, why)
goto Error
}
// obj != nil
// methods may not have a fully set up signature yet
if m, _ := obj.(*Func); m != nil {
@ -845,7 +846,7 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, wantType bool
// method expression
m, _ := obj.(*Func)
if m == nil {
check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (type %s has no method %s)", x.expr, sel, x.typ, sel)
check.errorf(e.X, MissingFieldOrMethod, "operand for field selector %s must be value of type %s", sel, x.typ)
goto Error
}

View file

@ -838,6 +838,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, wantType bool) {
check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (%s)", x.expr, sel, why)
goto Error
}
// obj != nil
// methods may not have a fully set up signature yet
if m, _ := obj.(*Func); m != nil {
@ -848,7 +849,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, wantType bool) {
// method expression
m, _ := obj.(*Func)
if m == nil {
check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (type %s has no method %s)", x.expr, sel, x.typ, sel)
check.errorf(e.X, MissingFieldOrMethod, "operand for field selector %s must be value of type %s", sel, x.typ)
goto Error
}

View file

@ -156,7 +156,7 @@ func (*T) m() {}
func method_expressions() {
_ = T.a /* ERROR "no field or method" */
_ = T.x /* ERROR "has no method" */
_ = T /* ERROR "operand for field selector x must be value of type T" */ .x
_ = T.m /* ERROR "invalid method expression T.m (needs pointer receiver (*T).m)" */
_ = (*T).m
@ -164,8 +164,8 @@ func method_expressions() {
var g func(*T) = (*T).m
_, _ = f, g
_ = T.y /* ERROR "has no method" */
_ = (*T).y /* ERROR "has no method" */
_ = T /* ERROR "operand for field selector y must be value of type T" */ .y
_ = ( /* ERROR "operand for field selector y must be value of type *T" */ *T).y
}
func struct_literals() {

View file

@ -351,7 +351,7 @@ func issue26234b(x T) {
}
func issue26234c() {
T.x /* ERROR "T.x undefined (type T has no method x)" */ ()
T /* ERROR "operand for field selector x must be value of type T" */ .x()
}
func issue35895() {

View file

@ -0,0 +1,35 @@
// Copyright 2026 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
type E struct {
e int
}
func (E) m() {}
type S struct {
E
x int
}
func (S) n() {}
func _() {
_ = S.X // ERROR "S.X undefined (type S has no field or method X, but does have field x)"
_ = S /* ERROR "operand for field selector E must be value of type S" */ .E
_ = S /* ERROR "operand for field selector x must be value of type S" */ .x
_ = S /* ERROR "operand for field selector e must be value of type S" */ .e
_ = S.m
_ = S.n
var s S
_ = s.X // ERROR "s.X undefined (type S has no field or method X, but does have field x)"
_ = s.E
_ = s.x
_ = s.e
_ = s.m
_ = s.n
}