mirror of https://github.com/golang/go.git
go/types, types2: implement field access for struct structural constraints
This change implements field the access p.f where the type of p is a type parameter with a structural constraint that is a struct with a field f. This is only the fix for the type checker. The compiler will need a separate CL. This makes the behavior consistent with the fact that we can write struct composite literals for type parameters with a struct structural type. For #50417. For #50233. Change-Id: I87d07e016f97cbf19c45cde19165eae3ec0bad2b Reviewed-on: https://go-review.googlesource.com/c/go/+/375795 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
2bfa6ef63d
commit
61014f00f2
|
|
@ -43,7 +43,7 @@ import (
|
|||
// the method's formal receiver base type, nor was the receiver addressable.
|
||||
//
|
||||
func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
|
||||
// Methods cannot be associated to a named pointer type
|
||||
// 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
|
||||
// in the same package as the method.").
|
||||
|
|
@ -60,7 +60,21 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
|
|||
}
|
||||
}
|
||||
|
||||
return lookupFieldOrMethod(T, addressable, false, pkg, name)
|
||||
obj, index, indirect = lookupFieldOrMethod(T, addressable, false, pkg, name)
|
||||
|
||||
// If we didn't find anything and if we have a type parameter with a structural constraint,
|
||||
// see if there is a matching field (but not a method, those need to be declared explicitly
|
||||
// in the constraint). If the structural constraint is a named pointer type (see above), we
|
||||
// are ok here because only fields are accepted as results.
|
||||
if obj == nil && isTypeParam(T) {
|
||||
if t := structuralType(T); t != nil {
|
||||
obj, index, indirect = lookupFieldOrMethod(t, addressable, false, pkg, name)
|
||||
if _, ok := obj.(*Var); !ok {
|
||||
obj, index, indirect = nil, nil, false // accept fields (variables) only
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(gri) The named type consolidation and seen maps below must be
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
// 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 Sf struct {
|
||||
f int
|
||||
}
|
||||
|
||||
func f0[P Sf](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
}
|
||||
|
||||
func f0t[P ~struct{f int}](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
}
|
||||
|
||||
var _ = f0[Sf]
|
||||
var _ = f0t[Sf]
|
||||
|
||||
var _ = f0[Sm /* ERROR does not implement */ ]
|
||||
var _ = f0t[Sm /* ERROR does not implement */ ]
|
||||
|
||||
func f1[P interface{ Sf; m() }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
p.m()
|
||||
}
|
||||
|
||||
var _ = f1[Sf /* ERROR missing method m */ ]
|
||||
var _ = f1[Sm /* ERROR does not implement */ ]
|
||||
|
||||
type Sm struct {}
|
||||
|
||||
func (Sm) m() {}
|
||||
|
||||
type Sfm struct {
|
||||
f int
|
||||
}
|
||||
|
||||
func (Sfm) m() {}
|
||||
|
||||
func f2[P interface{ Sfm; m() }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
p.m()
|
||||
}
|
||||
|
||||
var _ = f2[Sfm]
|
||||
|
||||
// special case: structural type is a named pointer type
|
||||
|
||||
type PSfm *Sfm
|
||||
|
||||
func f3[P interface{ PSfm }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
p.m /* ERROR type bound for P has no method m */ ()
|
||||
}
|
||||
|
||||
var _ = f3[PSfm]
|
||||
|
|
@ -43,7 +43,7 @@ import (
|
|||
// the method's formal receiver base type, nor was the receiver addressable.
|
||||
//
|
||||
func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
|
||||
// Methods cannot be associated to a named pointer type
|
||||
// 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
|
||||
// in the same package as the method.").
|
||||
|
|
@ -60,7 +60,21 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
|
|||
}
|
||||
}
|
||||
|
||||
return lookupFieldOrMethod(T, addressable, pkg, name)
|
||||
obj, index, indirect = lookupFieldOrMethod(T, addressable, pkg, name)
|
||||
|
||||
// If we didn't find anything and if we have a type parameter with a structural constraint,
|
||||
// see if there is a matching field (but not a method, those need to be declared explicitly
|
||||
// in the constraint). If the structural constraint is a named pointer type (see above), we
|
||||
// are ok here because only fields are accepted as results.
|
||||
if obj == nil && isTypeParam(T) {
|
||||
if t := structuralType(T); t != nil {
|
||||
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name)
|
||||
if _, ok := obj.(*Var); !ok {
|
||||
obj, index, indirect = nil, nil, false // accept fields (variables) only
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(gri) The named type consolidation and seen maps below must be
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
// 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 Sf struct {
|
||||
f int
|
||||
}
|
||||
|
||||
func f0[P Sf](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
}
|
||||
|
||||
func f0t[P ~struct{f int}](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
}
|
||||
|
||||
var _ = f0[Sf]
|
||||
var _ = f0t[Sf]
|
||||
|
||||
var _ = f0[Sm /* ERROR does not implement */ ]
|
||||
var _ = f0t[Sm /* ERROR does not implement */ ]
|
||||
|
||||
func f1[P interface{ Sf; m() }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
p.m()
|
||||
}
|
||||
|
||||
var _ = f1[Sf /* ERROR missing method m */ ]
|
||||
var _ = f1[Sm /* ERROR does not implement */ ]
|
||||
|
||||
type Sm struct {}
|
||||
|
||||
func (Sm) m() {}
|
||||
|
||||
type Sfm struct {
|
||||
f int
|
||||
}
|
||||
|
||||
func (Sfm) m() {}
|
||||
|
||||
func f2[P interface{ Sfm; m() }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
p.m()
|
||||
}
|
||||
|
||||
var _ = f2[Sfm]
|
||||
|
||||
// special case: structural type is a named pointer type
|
||||
|
||||
type PSfm *Sfm
|
||||
|
||||
func f3[P interface{ PSfm }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
p.m /* ERROR type bound for P has no method m */ ()
|
||||
}
|
||||
|
||||
var _ = f3[PSfm]
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// run
|
||||
|
||||
// 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 main
|
||||
|
||||
func main() {}
|
||||
|
||||
type Sf struct {
|
||||
f int
|
||||
}
|
||||
|
||||
func f0[P Sf](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
}
|
||||
|
||||
func f0t[P ~struct{ f int }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
}
|
||||
|
||||
// TODO(danscales) enable once the compiler is fixed
|
||||
// var _ = f0[Sf]
|
||||
// var _ = f0t[Sf]
|
||||
|
||||
func f1[P interface {
|
||||
Sf
|
||||
m()
|
||||
}](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
p.m()
|
||||
}
|
||||
|
||||
type Sm struct{}
|
||||
|
||||
func (Sm) m() {}
|
||||
|
||||
type Sfm struct {
|
||||
f int
|
||||
}
|
||||
|
||||
func (Sfm) m() {}
|
||||
|
||||
func f2[P interface {
|
||||
Sfm
|
||||
m()
|
||||
}](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
p.m()
|
||||
}
|
||||
|
||||
// TODO(danscales) enable once the compiler is fixed
|
||||
// var _ = f2[Sfm]
|
||||
|
||||
// special case: structural type is a named pointer type
|
||||
|
||||
type PSfm *Sfm
|
||||
|
||||
func f3[P interface{ PSfm }](p P) {
|
||||
_ = p.f
|
||||
p.f = 0
|
||||
}
|
||||
|
||||
// TODO(danscales) enable once the compiler is fixed
|
||||
// var _ = f3[PSfm]
|
||||
Loading…
Reference in New Issue