base, _ := obj.typ.(*Named) // shouldn't fail but be conservative
if base != nil {
assert(base.targs.Len() == 0) // collectMethods should not be called on an instantiated type
- u := base.under()
- if t, _ := u.(*Struct); t != nil {
- for _, fld := range t.fields {
- if fld.name != "_" {
- assert(mset.insert(fld) == nil)
- }
- }
- }
+
+ // See issue #52529: we must delay the expansion of underlying here, as
+ // base may not be fully set-up.
+ check.later(func() {
+ check.checkFieldUniqueness(base)
+ }).describef(obj, "verifying field uniqueness for %v", base)
// Checker.Files may be called multiple times; additional package files
// may add methods to already type-checked types. Add pre-existing methods
assert(m.name != "_")
if alt := mset.insert(m); alt != nil {
var err error_
- switch alt.(type) {
- case *Var:
- err.errorf(m.pos, "field and method with the same name %s", m.name)
- case *Func:
- if check.conf.CompilerErrorMessages {
- err.errorf(m.pos, "%s.%s redeclared in this block", obj.Name(), m.name)
- } else {
- err.errorf(m.pos, "method %s already declared for %s", m.name, obj)
- }
- default:
- unreachable()
+ if check.conf.CompilerErrorMessages {
+ err.errorf(m.pos, "%s.%s redeclared in this block", obj.Name(), m.name)
+ } else {
+ err.errorf(m.pos, "method %s already declared for %s", m.name, obj)
}
err.recordAltDecl(alt)
check.report(&err)
}
}
+func (check *Checker) checkFieldUniqueness(base *Named) {
+ if t, _ := base.under().(*Struct); t != nil {
+ var mset objset
+ for i := 0; i < base.methods.Len(); i++ {
+ m := base.methods.At(i, nil)
+ assert(m.name != "_")
+ assert(mset.insert(m) == nil)
+ }
+
+ // Check that any non-blank field names of base are distinct from its
+ // method names.
+ for _, fld := range t.fields {
+ if fld.name != "_" {
+ if alt := mset.insert(fld); alt != nil {
+ // Struct fields should already be unique, so we should only
+ // encounter an alternate via collision with a method name.
+ _ = alt.(*Func)
+
+ // For historical consistency, we report the primary error on the
+ // method, and the alt decl on the field.
+ var err error_
+ err.errorf(alt, "field and method with the same name %s", fld.name)
+ err.recordAltDecl(fld)
+ check.report(&err)
+ }
+ }
+ }
+ }
+}
+
func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
assert(obj.typ == nil)
--- /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
+
+type Foo[P any] struct {
+ _ *Bar[P]
+}
+
+type Bar[Q any] Foo[Q]
+
+func (v *Bar[R]) M() {
+ _ = (*Foo[R])(v)
+}
base, _ := obj.typ.(*Named) // shouldn't fail but be conservative
if base != nil {
assert(base.targs.Len() == 0) // collectMethods should not be called on an instantiated type
- u := base.under()
- if t, _ := u.(*Struct); t != nil {
- for _, fld := range t.fields {
- if fld.name != "_" {
- assert(mset.insert(fld) == nil)
- }
- }
- }
+
+ // See issue #52529: we must delay the expansion of underlying here, as
+ // base may not be fully set-up.
+ check.later(func() {
+ check.checkFieldUniqueness(base)
+ }).describef(obj, "verifying field uniqueness for %v", base)
// Checker.Files may be called multiple times; additional package files
// may add methods to already type-checked types. Add pre-existing methods
// to it must be unique."
assert(m.name != "_")
if alt := mset.insert(m); alt != nil {
- switch alt.(type) {
- case *Var:
- check.errorf(m, _DuplicateFieldAndMethod, "field and method with the same name %s", m.name)
- case *Func:
- check.errorf(m, _DuplicateMethod, "method %s already declared for %s", m.name, obj)
- default:
- unreachable()
- }
+ check.errorf(m, _DuplicateMethod, "method %s already declared for %s", m.name, obj)
check.reportAltDecl(alt)
continue
}
}
}
+func (check *Checker) checkFieldUniqueness(base *Named) {
+ if t, _ := base.under().(*Struct); t != nil {
+ var mset objset
+ for i := 0; i < base.methods.Len(); i++ {
+ m := base.methods.At(i, nil)
+ assert(m.name != "_")
+ assert(mset.insert(m) == nil)
+ }
+
+ // Check that any non-blank field names of base are distinct from its
+ // method names.
+ for _, fld := range t.fields {
+ if fld.name != "_" {
+ if alt := mset.insert(fld); alt != nil {
+ // Struct fields should already be unique, so we should only
+ // encounter an alternate via collision with a method name.
+ _ = alt.(*Func)
+
+ // For historical consistency, we report the primary error on the
+ // method, and the alt decl on the field.
+ check.errorf(alt, _DuplicateFieldAndMethod, "field and method with the same name %s", fld.name)
+ check.reportAltDecl(fld)
+ }
+ }
+ }
+ }
+}
+
func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
assert(obj.typ == nil)
--- /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
+
+type Foo[P any] struct {
+ _ *Bar[P]
+}
+
+type Bar[Q any] Foo[Q]
+
+func (v *Bar[R]) M() {
+ _ = (*Foo[R])(v)
+}
"fixedbugs/issue18419.go", // types2 reports no field or method member, but should say unexported
"fixedbugs/issue20233.go", // types2 reports two instead of one error (preference: 1.17 compiler)
"fixedbugs/issue20245.go", // types2 reports two instead of one error (preference: 1.17 compiler)
- "fixedbugs/issue28268.go", // types2 reports follow-on errors (preference: 1.17 compiler)
"fixedbugs/issue31053.go", // types2 reports "unknown field" instead of "cannot refer to unexported field"
)
//
// For example, the following string:
//
-// a b:"c d" 'e''f' "g\""
+// a b:"c d" 'e''f' "g\""
//
// Would be parsed as:
//
-// []string{"a", "b:c d", "ef", `g"`}
+// []string{"a", "b:c d", "ef", `g"`}
//
// [copied from src/go/build/build.go]
func splitQuoted(s string) (r []string, err error) {