base := derefStructPtr(x.typ)
sel := selx.Sel.Value
- obj, index, indirect := LookupFieldOrMethod(base, false, check.pkg, sel)
+ obj, index, indirect := lookupFieldOrMethod(base, false, check.pkg, sel, false)
switch obj.(type) {
case nil:
check.errorf(x, MissingFieldOrMethod, invalidArg+"%s has no single field %s", base, sel)
"cmd/compile/internal/syntax"
. "internal/types/errors"
"strings"
- "unicode"
)
// funcInst type-checks a function instantiation.
goto Error
}
- obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
+ obj, index, indirect = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, false)
if obj == nil {
// Don't report another error if the underlying type was invalid (go.dev/issue/49541).
if !isValid(under(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.
- // TODO(gri) This code only looks at the first character but LookupFieldOrMethod has an
- // (internal) mechanism for case-insensitive lookup. Should use that instead.
- if len(sel) > 0 {
- var changeCase string
- if r := rune(sel[0]); unicode.IsUpper(r) {
- changeCase = string(unicode.ToLower(r)) + sel[1:]
- } else {
- changeCase = string(unicode.ToUpper(r)) + sel[1:]
+ // check if there's a field or method with different capitalization
+ if obj, _, _ = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, true); obj != nil {
+ var what string // empty or description with trailing space " " (default case, should never be reached)
+ switch obj.(type) {
+ case *Var:
+ what = "field "
+ case *Func:
+ what = "method "
}
- if obj, _, _ = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil {
- why += ", but does have " + changeCase
+ if samePkg(obj.Pkg(), check.pkg) || obj.Exported() {
+ why = check.sprintf("%s, but does have %s%s", why, what, obj.Name())
+ } else if obj.Name() == sel {
+ why = check.sprintf("%s%s is not exported", what, obj.Name())
}
}
}
// method expression
m, _ := obj.(*Func)
if m == nil {
- // TODO(gri) should check if capitalization of sel matters and provide better error message in that case
check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (type %s has no method %s)", x.expr, sel, x.typ, sel)
goto Error
}
check.errorf(kv, InvalidLitField, "invalid field name %s in struct literal", kv.Key)
continue
}
- i := fieldIndex(utyp.fields, check.pkg, key.Value)
+ i := fieldIndex(utyp.fields, check.pkg, key.Value, false)
if i < 0 {
check.errorf(kv.Key, MissingLitField, "unknown field %s in struct literal of type %s", key.Value, base)
continue
import (
"bytes"
"cmd/compile/internal/syntax"
- "strings"
)
// Internal use of LookupFieldOrMethod: If the obj result is a method
if T == nil {
panic("LookupFieldOrMethod on nil type")
}
+ return lookupFieldOrMethod(T, addressable, pkg, name, false)
+}
+// lookupFieldOrMethod is like LookupFieldOrMethod but with the additional foldCase parameter
+// (see Object.sameId for the meaning of foldCase).
+func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string, foldCase bool) (obj Object, index []int, indirect bool) {
// Methods cannot be associated to a named pointer type.
// (spec: "The type denoted by T is called the receiver base type;
// it must not be a pointer or interface type and it must be declared
// not have found it for T (see also go.dev/issue/8590).
if t := asNamed(T); t != nil {
if p, _ := t.Underlying().(*Pointer); p != nil {
- obj, index, indirect = lookupFieldOrMethodImpl(p, false, pkg, name, false)
+ obj, index, indirect = lookupFieldOrMethodImpl(p, false, pkg, name, foldCase)
if _, ok := obj.(*Func); ok {
return nil, nil, false
}
}
}
- obj, index, indirect = lookupFieldOrMethodImpl(T, addressable, pkg, name, false)
+ obj, index, indirect = lookupFieldOrMethodImpl(T, addressable, pkg, name, foldCase)
// If we didn't find anything and if we have a type parameter with a core type,
// see if there is a matching field (but not a method, those need to be declared
const enableTParamFieldLookup = false // see go.dev/issue/51576
if enableTParamFieldLookup && obj == nil && isTypeParam(T) {
if t := coreType(T); t != nil {
- obj, index, indirect = lookupFieldOrMethodImpl(t, addressable, pkg, name, false)
+ obj, index, indirect = lookupFieldOrMethodImpl(t, addressable, pkg, name, foldCase)
if _, ok := obj.(*Var); !ok {
obj, index, indirect = nil, nil, false // accept fields (variables) only
}
return
}
-// lookupFieldOrMethodImpl is the implementation of LookupFieldOrMethod.
-// Notably, in contrast to LookupFieldOrMethod, it won't find struct fields
+// lookupFieldOrMethodImpl is the implementation of lookupFieldOrMethod.
+// Notably, in contrast to lookupFieldOrMethod, it won't find struct fields
// in base types of defined (*Named) pointer types T. For instance, given
// the declaration:
//
// lookupFieldOrMethodImpl won't find the field f in the defined (*Named) type T
// (methods on T are not permitted in the first place).
//
-// Thus, lookupFieldOrMethodImpl should only be called by LookupFieldOrMethod
+// Thus, lookupFieldOrMethodImpl should only be called by lookupFieldOrMethod
// and missingMethod (the latter doesn't care about struct fields).
//
-// If foldCase is true, method names are considered equal if they are equal
-// with case folding, irrespective of which package they are in.
-//
// The resulting object may not be fully type-checked.
func lookupFieldOrMethodImpl(T Type, addressable bool, pkg *Package, name string, foldCase bool) (obj Object, index []int, indirect bool) {
// WARNING: The code in this function is extremely subtle - do not modify casually!
case *Struct:
// look for a matching field and collect embedded types
for i, f := range t.fields {
- if f.sameId(pkg, name) {
+ if f.sameId(pkg, name, foldCase) {
assert(f.typ != nil)
index = concat(e.index, i)
if obj != nil || e.multiples {
}
// fieldIndex returns the index for the field with matching package and name, or a value < 0.
-func fieldIndex(fields []*Var, pkg *Package, name string) int {
+// See Object.sameId for the meaning of foldCase.
+func fieldIndex(fields []*Var, pkg *Package, name string, foldCase bool) int {
if name != "_" {
for i, f := range fields {
- if f.sameId(pkg, name) {
+ if f.sameId(pkg, name, foldCase) {
return i
}
}
}
// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
-// If foldCase is true, method names are considered equal if they are equal with case folding
-// and their packages are ignored (e.g., pkg1.m, pkg1.M, pkg2.m, and pkg2.M are all equal).
+// See Object.sameId for the meaning of foldCase.
func lookupMethod(methods []*Func, pkg *Package, name string, foldCase bool) (int, *Func) {
if name != "_" {
for i, m := range methods {
- if m.sameId(pkg, name) || foldCase && strings.EqualFold(m.name, name) {
+ if m.sameId(pkg, name, foldCase) {
return i, m
}
}
"cmd/compile/internal/syntax"
"fmt"
"go/constant"
+ "strings"
"unicode"
"unicode/utf8"
)
setParent(*Scope)
// sameId reports whether obj.Id() and Id(pkg, name) are the same.
- sameId(pkg *Package, name string) bool
+ // If foldCase is true, names are considered equal if they are equal with case folding
+ // and their packages are ignored (e.g., pkg1.m, pkg1.M, pkg2.m, and pkg2.M are all equal).
+ sameId(pkg *Package, name string, foldCase bool) bool
// scopePos returns the start position of the scope of this Object
scopePos() syntax.Pos
func (obj *object) setColor(color color) { assert(color != white); obj.color_ = color }
func (obj *object) setScopePos(pos syntax.Pos) { obj.scopePos_ = pos }
-func (obj *object) sameId(pkg *Package, name string) bool {
+func (obj *object) sameId(pkg *Package, name string, foldCase bool) bool {
+ // If we don't care about capitalization, we also ignore packages.
+ if foldCase && strings.EqualFold(obj.name, name) {
+ return true
+ }
// spec:
// "Two identifiers are different if they are spelled differently,
// or if they appear in different packages and are not exported.
// Otherwise, they are the same."
- if name != obj.name {
+ if obj.name != name {
return false
}
// obj.Name == name
if obj.Exported() {
return true
}
- // not exported, so packages must be the same (pkg == nil for
- // fields in Universe scope; this can only happen for types
- // introduced via Eval)
- if pkg == nil || obj.pkg == nil {
- return pkg == obj.pkg
- }
- // pkg != nil && obj.pkg != nil
- return pkg.path == obj.pkg.path
+ // not exported, so packages must be the same
+ return samePkg(obj.pkg, pkg)
}
// less reports whether object a is ordered before object b.
return false
}
+// samePkg reports whether packages a and b are the same.
+func samePkg(a, b *Package) bool {
+ // package is nil for objects in universe scope
+ if a == nil || b == nil {
+ return a == b
+ }
+ // a != nil && b != nil
+ return a.path == b.path
+}
+
// An ifacePair is a node in a stack of interface type pairs compared for identity.
type ifacePair struct {
x, y *Interface
g := y.fields[i]
if f.embedded != g.embedded ||
!c.ignoreTags && x.Tag(i) != y.Tag(i) ||
- !f.sameId(g.pkg, g.name) ||
+ !f.sameId(g.pkg, g.name, false) ||
!c.identical(f.typ, g.typ, p) {
return false
}
// stub implementations so *lazyObject implements Object and we can
// store them directly into Scope.elems.
-func (*lazyObject) Parent() *Scope { panic("unreachable") }
-func (*lazyObject) Pos() syntax.Pos { panic("unreachable") }
-func (*lazyObject) Pkg() *Package { panic("unreachable") }
-func (*lazyObject) Name() string { panic("unreachable") }
-func (*lazyObject) Type() Type { panic("unreachable") }
-func (*lazyObject) Exported() bool { panic("unreachable") }
-func (*lazyObject) Id() string { panic("unreachable") }
-func (*lazyObject) String() string { panic("unreachable") }
-func (*lazyObject) order() uint32 { panic("unreachable") }
-func (*lazyObject) color() color { panic("unreachable") }
-func (*lazyObject) setType(Type) { panic("unreachable") }
-func (*lazyObject) setOrder(uint32) { panic("unreachable") }
-func (*lazyObject) setColor(color color) { panic("unreachable") }
-func (*lazyObject) setParent(*Scope) { panic("unreachable") }
-func (*lazyObject) sameId(pkg *Package, name string) bool { panic("unreachable") }
-func (*lazyObject) scopePos() syntax.Pos { panic("unreachable") }
-func (*lazyObject) setScopePos(pos syntax.Pos) { panic("unreachable") }
+func (*lazyObject) Parent() *Scope { panic("unreachable") }
+func (*lazyObject) Pos() syntax.Pos { panic("unreachable") }
+func (*lazyObject) Pkg() *Package { panic("unreachable") }
+func (*lazyObject) Name() string { panic("unreachable") }
+func (*lazyObject) Type() Type { panic("unreachable") }
+func (*lazyObject) Exported() bool { panic("unreachable") }
+func (*lazyObject) Id() string { panic("unreachable") }
+func (*lazyObject) String() string { panic("unreachable") }
+func (*lazyObject) order() uint32 { panic("unreachable") }
+func (*lazyObject) color() color { panic("unreachable") }
+func (*lazyObject) setType(Type) { panic("unreachable") }
+func (*lazyObject) setOrder(uint32) { panic("unreachable") }
+func (*lazyObject) setColor(color color) { panic("unreachable") }
+func (*lazyObject) setParent(*Scope) { panic("unreachable") }
+func (*lazyObject) sameId(*Package, string, bool) bool { panic("unreachable") }
+func (*lazyObject) scopePos() syntax.Pos { panic("unreachable") }
+func (*lazyObject) setScopePos(syntax.Pos) { panic("unreachable") }
g := y.fields[i]
if f.embedded != g.embedded ||
x.Tag(i) != y.Tag(i) ||
- !f.sameId(g.pkg, g.name) ||
+ !f.sameId(g.pkg, g.name, false) ||
!u.nify(f.typ, g.typ, emode, p) {
return false
}
base := derefStructPtr(x.typ)
sel := selx.Sel.Name
- obj, index, indirect := LookupFieldOrMethod(base, false, check.pkg, sel)
+ obj, index, indirect := lookupFieldOrMethod(base, false, check.pkg, sel, false)
switch obj.(type) {
case nil:
check.errorf(x, MissingFieldOrMethod, invalidArg+"%s has no single field %s", base, sel)
"go/token"
. "internal/types/errors"
"strings"
- "unicode"
)
// funcInst type-checks a function instantiation.
goto Error
}
- obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
+ obj, index, indirect = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, false)
if obj == nil {
// Don't report another error if the underlying type was invalid (go.dev/issue/49541).
if !isValid(under(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.
- // TODO(gri) This code only looks at the first character but LookupFieldOrMethod should
- // have an (internal) mechanism for case-insensitive lookup that we should use
- // instead (see types2).
- if len(sel) > 0 {
- var changeCase string
- if r := rune(sel[0]); unicode.IsUpper(r) {
- changeCase = string(unicode.ToLower(r)) + sel[1:]
- } else {
- changeCase = string(unicode.ToUpper(r)) + sel[1:]
+ // check if there's a field or method with different capitalization
+ if obj, _, _ = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, true); obj != nil {
+ var what string // empty or description with trailing space " " (default case, should never be reached)
+ switch obj.(type) {
+ case *Var:
+ what = "field "
+ case *Func:
+ what = "method "
}
- if obj, _, _ = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil {
- why += ", but does have " + changeCase
+ if samePkg(obj.Pkg(), check.pkg) || obj.Exported() {
+ why = check.sprintf("%s, but does have %s%s", why, what, obj.Name())
+ } else if obj.Name() == sel {
+ why = check.sprintf("%s%s is not exported", what, obj.Name())
}
}
}
// method expression
m, _ := obj.(*Func)
if m == nil {
- // TODO(gri) should check if capitalization of sel matters and provide better error message in that case
check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (type %s has no method %s)", x.expr, sel, x.typ, sel)
goto Error
}
check.errorf(kv, InvalidLitField, "invalid field name %s in struct literal", kv.Key)
continue
}
- i := fieldIndex(utyp.fields, check.pkg, key.Name)
+ i := fieldIndex(utyp.fields, check.pkg, key.Name, false)
if i < 0 {
check.errorf(kv, MissingLitField, "unknown field %s in struct literal of type %s", key.Name, base)
continue
import (
"bytes"
"go/token"
- "strings"
)
// Internal use of LookupFieldOrMethod: If the obj result is a method
if T == nil {
panic("LookupFieldOrMethod on nil type")
}
+ return lookupFieldOrMethod(T, addressable, pkg, name, false)
+}
+// lookupFieldOrMethod is like LookupFieldOrMethod but with the additional foldCase parameter
+// (see Object.sameId for the meaning of foldCase).
+func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string, foldCase bool) (obj Object, index []int, indirect bool) {
// Methods cannot be associated to a named pointer type.
// (spec: "The type denoted by T is called the receiver base type;
// it must not be a pointer or interface type and it must be declared
// not have found it for T (see also go.dev/issue/8590).
if t := asNamed(T); t != nil {
if p, _ := t.Underlying().(*Pointer); p != nil {
- obj, index, indirect = lookupFieldOrMethodImpl(p, false, pkg, name, false)
+ obj, index, indirect = lookupFieldOrMethodImpl(p, false, pkg, name, foldCase)
if _, ok := obj.(*Func); ok {
return nil, nil, false
}
}
}
- obj, index, indirect = lookupFieldOrMethodImpl(T, addressable, pkg, name, false)
+ obj, index, indirect = lookupFieldOrMethodImpl(T, addressable, pkg, name, foldCase)
// If we didn't find anything and if we have a type parameter with a core type,
// see if there is a matching field (but not a method, those need to be declared
const enableTParamFieldLookup = false // see go.dev/issue/51576
if enableTParamFieldLookup && obj == nil && isTypeParam(T) {
if t := coreType(T); t != nil {
- obj, index, indirect = lookupFieldOrMethodImpl(t, addressable, pkg, name, false)
+ obj, index, indirect = lookupFieldOrMethodImpl(t, addressable, pkg, name, foldCase)
if _, ok := obj.(*Var); !ok {
obj, index, indirect = nil, nil, false // accept fields (variables) only
}
return
}
-// lookupFieldOrMethodImpl is the implementation of LookupFieldOrMethod.
-// Notably, in contrast to LookupFieldOrMethod, it won't find struct fields
+// lookupFieldOrMethodImpl is the implementation of lookupFieldOrMethod.
+// Notably, in contrast to lookupFieldOrMethod, it won't find struct fields
// in base types of defined (*Named) pointer types T. For instance, given
// the declaration:
//
// lookupFieldOrMethodImpl won't find the field f in the defined (*Named) type T
// (methods on T are not permitted in the first place).
//
-// Thus, lookupFieldOrMethodImpl should only be called by LookupFieldOrMethod
+// Thus, lookupFieldOrMethodImpl should only be called by lookupFieldOrMethod
// and missingMethod (the latter doesn't care about struct fields).
//
-// If foldCase is true, method names are considered equal if they are equal
-// with case folding, irrespective of which package they are in.
-//
// The resulting object may not be fully type-checked.
func lookupFieldOrMethodImpl(T Type, addressable bool, pkg *Package, name string, foldCase bool) (obj Object, index []int, indirect bool) {
// WARNING: The code in this function is extremely subtle - do not modify casually!
case *Struct:
// look for a matching field and collect embedded types
for i, f := range t.fields {
- if f.sameId(pkg, name) {
+ if f.sameId(pkg, name, foldCase) {
assert(f.typ != nil)
index = concat(e.index, i)
if obj != nil || e.multiples {
}
// fieldIndex returns the index for the field with matching package and name, or a value < 0.
-func fieldIndex(fields []*Var, pkg *Package, name string) int {
+// See Object.sameId for the meaning of foldCase.
+func fieldIndex(fields []*Var, pkg *Package, name string, foldCase bool) int {
if name != "_" {
for i, f := range fields {
- if f.sameId(pkg, name) {
+ if f.sameId(pkg, name, foldCase) {
return i
}
}
}
// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
-// If foldCase is true, method names are considered equal if they are equal with case folding
-// and their packages are ignored (e.g., pkg1.m, pkg1.M, pkg2.m, and pkg2.M are all equal).
+// See Object.sameId for the meaning of foldCase.
func lookupMethod(methods []*Func, pkg *Package, name string, foldCase bool) (int, *Func) {
if name != "_" {
for i, m := range methods {
- if m.sameId(pkg, name) || foldCase && strings.EqualFold(m.name, name) {
+ if m.sameId(pkg, name, foldCase) {
return i, m
}
}
"fmt"
"go/constant"
"go/token"
+ "strings"
"unicode"
"unicode/utf8"
)
setParent(*Scope)
// sameId reports whether obj.Id() and Id(pkg, name) are the same.
- sameId(pkg *Package, name string) bool
+ // If foldCase is true, names are considered equal if they are equal with case folding
+ // and their packages are ignored (e.g., pkg1.m, pkg1.M, pkg2.m, and pkg2.M are all equal).
+ sameId(pkg *Package, name string, foldCase bool) bool
// scopePos returns the start position of the scope of this Object
scopePos() token.Pos
func (obj *object) setColor(color color) { assert(color != white); obj.color_ = color }
func (obj *object) setScopePos(pos token.Pos) { obj.scopePos_ = pos }
-func (obj *object) sameId(pkg *Package, name string) bool {
+func (obj *object) sameId(pkg *Package, name string, foldCase bool) bool {
+ // If we don't care about capitalization, we also ignore packages.
+ if foldCase && strings.EqualFold(obj.name, name) {
+ return true
+ }
// spec:
// "Two identifiers are different if they are spelled differently,
// or if they appear in different packages and are not exported.
// Otherwise, they are the same."
- if name != obj.name {
+ if obj.name != name {
return false
}
// obj.Name == name
if obj.Exported() {
return true
}
- // not exported, so packages must be the same (pkg == nil for
- // fields in Universe scope; this can only happen for types
- // introduced via Eval)
- if pkg == nil || obj.pkg == nil {
- return pkg == obj.pkg
- }
- // pkg != nil && obj.pkg != nil
- return pkg.path == obj.pkg.path
+ // not exported, so packages must be the same
+ return samePkg(obj.pkg, pkg)
}
// less reports whether object a is ordered before object b.
return false
}
+// samePkg reports whether packages a and b are the same.
+func samePkg(a, b *Package) bool {
+ // package is nil for objects in universe scope
+ if a == nil || b == nil {
+ return a == b
+ }
+ // a != nil && b != nil
+ return a.path == b.path
+}
+
// An ifacePair is a node in a stack of interface type pairs compared for identity.
type ifacePair struct {
x, y *Interface
g := y.fields[i]
if f.embedded != g.embedded ||
!c.ignoreTags && x.Tag(i) != y.Tag(i) ||
- !f.sameId(g.pkg, g.name) ||
+ !f.sameId(g.pkg, g.name, false) ||
!c.identical(f.typ, g.typ, p) {
return false
}
// stub implementations so *lazyObject implements Object and we can
// store them directly into Scope.elems.
-func (*lazyObject) Parent() *Scope { panic("unreachable") }
-func (*lazyObject) Pos() token.Pos { panic("unreachable") }
-func (*lazyObject) Pkg() *Package { panic("unreachable") }
-func (*lazyObject) Name() string { panic("unreachable") }
-func (*lazyObject) Type() Type { panic("unreachable") }
-func (*lazyObject) Exported() bool { panic("unreachable") }
-func (*lazyObject) Id() string { panic("unreachable") }
-func (*lazyObject) String() string { panic("unreachable") }
-func (*lazyObject) order() uint32 { panic("unreachable") }
-func (*lazyObject) color() color { panic("unreachable") }
-func (*lazyObject) setType(Type) { panic("unreachable") }
-func (*lazyObject) setOrder(uint32) { panic("unreachable") }
-func (*lazyObject) setColor(color color) { panic("unreachable") }
-func (*lazyObject) setParent(*Scope) { panic("unreachable") }
-func (*lazyObject) sameId(pkg *Package, name string) bool { panic("unreachable") }
-func (*lazyObject) scopePos() token.Pos { panic("unreachable") }
-func (*lazyObject) setScopePos(pos token.Pos) { panic("unreachable") }
+func (*lazyObject) Parent() *Scope { panic("unreachable") }
+func (*lazyObject) Pos() token.Pos { panic("unreachable") }
+func (*lazyObject) Pkg() *Package { panic("unreachable") }
+func (*lazyObject) Name() string { panic("unreachable") }
+func (*lazyObject) Type() Type { panic("unreachable") }
+func (*lazyObject) Exported() bool { panic("unreachable") }
+func (*lazyObject) Id() string { panic("unreachable") }
+func (*lazyObject) String() string { panic("unreachable") }
+func (*lazyObject) order() uint32 { panic("unreachable") }
+func (*lazyObject) color() color { panic("unreachable") }
+func (*lazyObject) setType(Type) { panic("unreachable") }
+func (*lazyObject) setOrder(uint32) { panic("unreachable") }
+func (*lazyObject) setColor(color color) { panic("unreachable") }
+func (*lazyObject) setParent(*Scope) { panic("unreachable") }
+func (*lazyObject) sameId(*Package, string, bool) bool { panic("unreachable") }
+func (*lazyObject) scopePos() token.Pos { panic("unreachable") }
+func (*lazyObject) setScopePos(token.Pos) { panic("unreachable") }
g := y.fields[i]
if f.embedded != g.embedded ||
x.Tag(i) != y.Tag(i) ||
- !f.sameId(g.pkg, g.name) ||
+ !f.sameId(g.pkg, g.name, false) ||
!u.nify(f.typ, g.typ, emode, p) {
return false
}
_ = x /* ERROR "impossible type assertion: x.(T1)\n\tT1 does not implement I1 (method foo has pointer receiver)" */ .(T1)
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)" */ ()
+ x.Foo /* ERROR "x.Foo undefined (type I1 has no field or method Foo, but does have method 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(int)" */ .(*T1)
--- /dev/null
+// Copyright 2024 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 lookup
+
+import "math/big" // provides big.Float struct with unexported fields and methods
+
+func _() {
+ var s struct {
+ x, aBc int
+ }
+ _ = s.x
+ _ = s /* ERROR "invalid operation: cannot call non-function s.x (variable of type int)" */ .x()
+ _ = s.X // ERROR "s.X undefined (type struct{x int; aBc int} has no field or method X, but does have field x)"
+ _ = s.X /* ERROR "s.X undefined (type struct{x int; aBc int} has no field or method X, but does have field x)" */ ()
+
+ _ = s.aBc
+ _ = s.abc // ERROR "s.abc undefined (type struct{x int; aBc int} has no field or method abc, but does have field aBc)"
+ _ = s.ABC // ERROR "s.ABC undefined (type struct{x int; aBc int} has no field or method ABC, but does have field aBc)"
+}
+
+func _() {
+ type S struct {
+ x int
+ }
+ var s S
+ _ = s.x
+ _ = s /* ERROR "invalid operation: cannot call non-function s.x (variable of type int)" */ .x()
+ _ = s.X // ERROR "s.X undefined (type S has no field or method X, but does have field x)"
+ _ = s.X /* ERROR "s.X undefined (type S has no field or method X, but does have field x)" */ ()
+}
+
+type S struct {
+ x int
+}
+
+func (S) m() {}
+func (S) aBc() {}
+
+func _() {
+ var s S
+ _ = s.m
+ s.m()
+ _ = s.M // ERROR "s.M undefined (type S has no field or method M, but does have method m)"
+ s.M /* ERROR "s.M undefined (type S has no field or method M, but does have method m)" */ ()
+
+ _ = s.aBc
+ _ = s.abc // ERROR "s.abc undefined (type S has no field or method abc, but does have method aBc)"
+ _ = s.ABC // ERROR "s.ABC undefined (type S has no field or method ABC, but does have method aBc)"
+}
+
+func _() {
+ type P *S
+ var s P
+ _ = s.m // ERROR "s.m undefined (type P has no field or method m)"
+ _ = s.M // ERROR "s.M undefined (type P has no field or method M)"
+ _ = s.x
+ _ = s.X // ERROR "s.X undefined (type P has no field or method X, but does have field x)"
+}
+
+func _() {
+ var x big.Float
+ _ = x.neg // ERROR "x.neg undefined (type big.Float has no field or method neg, but does have method Neg)"
+ _ = x.nEg // ERROR "x.nEg undefined (type big.Float has no field or method nEg, but does have method Neg)"
+ _ = x.Neg
+ _ = x.NEg // ERROR "x.NEg undefined (type big.Float has no field or method NEg, but does have method Neg)"
+
+ _ = x.form // ERROR "x.form undefined (field form is not exported)"
+ _ = x.fOrm // ERROR "x.fOrm undefined (type big.Float has no field or method fOrm)"
+ _ = x.Form // ERROR "x.Form undefined (type big.Float has no field or method Form)"
+ _ = x.FOrm // ERROR "x.FOrm undefined (type big.Float has no field or method FOrm)"
+}
func main() {
i1 := it{Floats: true}
- if i1.floats { // ERROR "(type it .* field or method floats, but does have Floats)|undefined field or method"
+ if i1.floats { // ERROR "(type it .* field or method floats, but does have field Floats)|undefined field or method"
}
- i2 := &it{floats: false} // ERROR "(but does have Floats)|unknown field|declared and not used"
- _ = &it{InneR: "foo"} // ERROR "(but does have inner)|unknown field"
+ i2 := &it{floats: false} // ERROR "(but does have field Floats)|unknown field|declared and not used"
+ _ = &it{InneR: "foo"} // ERROR "(but does have field inner)|unknown field"
_ = i2
}