mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
go/types, types2: disable field accesses through type parameters
This is a feature that is not understood well enough and may have subtle repercussions impacting future changes. Disable for Go 1.18. The actual change is trivial: disable a branch through a flag. The remaining changes are adjustments to tests. Fixes #51576. Change-Id: Ib77b038b846711a808315a8889b3904e72367bce Reviewed-on: https://go-review.googlesource.com/c/go/+/391135 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
7026eeb8cf
commit
b8248fab89
@ -70,7 +70,8 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
|
|||||||
// see if there is a matching field (but not a method, those need to be declared
|
// see if there is a matching field (but not a method, those need to be declared
|
||||||
// explicitly in the constraint). If the constraint is a named pointer type (see
|
// explicitly in the constraint). If the constraint is a named pointer type (see
|
||||||
// above), we are ok here because only fields are accepted as results.
|
// above), we are ok here because only fields are accepted as results.
|
||||||
if obj == nil && isTypeParam(T) {
|
const enableTParamFieldLookup = false // see issue #51576
|
||||||
|
if enableTParamFieldLookup && obj == nil && isTypeParam(T) {
|
||||||
if t := coreType(T); t != nil {
|
if t := coreType(T); t != nil {
|
||||||
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false)
|
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false)
|
||||||
if _, ok := obj.(*Var); !ok {
|
if _, ok := obj.(*Var); !ok {
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Field accesses through type parameters are disabled
|
||||||
|
// until we have a more thorough understanding of the
|
||||||
|
// implications on the spec. See issue #51576.
|
||||||
|
|
||||||
package p
|
package p
|
||||||
|
|
||||||
type Sf struct {
|
type Sf struct {
|
||||||
@ -9,13 +13,13 @@ type Sf struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func f0[P Sf](p P) {
|
func f0[P Sf](p P) {
|
||||||
_ = p.f
|
_ = p.f // ERROR p\.f undefined
|
||||||
p.f = 0
|
p.f /* ERROR p\.f undefined */ = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func f0t[P ~struct{f int}](p P) {
|
func f0t[P ~struct{f int}](p P) {
|
||||||
_ = p.f
|
_ = p.f // ERROR p\.f undefined
|
||||||
p.f = 0
|
p.f /* ERROR p\.f undefined */ = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = f0[Sf]
|
var _ = f0[Sf]
|
||||||
@ -25,8 +29,8 @@ var _ = f0[Sm /* ERROR does not implement */ ]
|
|||||||
var _ = f0t[Sm /* ERROR does not implement */ ]
|
var _ = f0t[Sm /* ERROR does not implement */ ]
|
||||||
|
|
||||||
func f1[P interface{ Sf; m() }](p P) {
|
func f1[P interface{ Sf; m() }](p P) {
|
||||||
_ = p.f
|
_ = p.f // ERROR p\.f undefined
|
||||||
p.f = 0
|
p.f /* ERROR p\.f undefined */ = 0
|
||||||
p.m()
|
p.m()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,8 +48,8 @@ type Sfm struct {
|
|||||||
func (Sfm) m() {}
|
func (Sfm) m() {}
|
||||||
|
|
||||||
func f2[P interface{ Sfm; m() }](p P) {
|
func f2[P interface{ Sfm; m() }](p P) {
|
||||||
_ = p.f
|
_ = p.f // ERROR p\.f undefined
|
||||||
p.f = 0
|
p.f /* ERROR p\.f undefined */ = 0
|
||||||
p.m()
|
p.m()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +60,8 @@ var _ = f2[Sfm]
|
|||||||
type PSfm *Sfm
|
type PSfm *Sfm
|
||||||
|
|
||||||
func f3[P interface{ PSfm }](p P) {
|
func f3[P interface{ PSfm }](p P) {
|
||||||
_ = p.f
|
_ = p.f // ERROR p\.f undefined
|
||||||
p.f = 0
|
p.f /* ERROR p\.f undefined */ = 0
|
||||||
p.m /* ERROR type P has no field or method m */ ()
|
p.m /* ERROR type P has no field or method m */ ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Field accesses through type parameters are disabled
|
||||||
|
// until we have a more thorough understanding of the
|
||||||
|
// implications on the spec. See issue #51576.
|
||||||
|
|
||||||
package p
|
package p
|
||||||
|
|
||||||
// The first example from the issue.
|
// The first example from the issue.
|
||||||
@ -18,9 +22,12 @@ type numericAbs[T Numeric] interface {
|
|||||||
// AbsDifference computes the absolute value of the difference of
|
// AbsDifference computes the absolute value of the difference of
|
||||||
// a and b, where the absolute value is determined by the Abs method.
|
// a and b, where the absolute value is determined by the Abs method.
|
||||||
func absDifference[T numericAbs[T /* ERROR T does not implement Numeric */]](a, b T) T {
|
func absDifference[T numericAbs[T /* ERROR T does not implement Numeric */]](a, b T) T {
|
||||||
// TODO: the error below should probably be positioned on the '-'.
|
// Field accesses are not permitted for now. Keep an error so
|
||||||
d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value
|
// we can find and fix this code once the situation changes.
|
||||||
return d.Abs()
|
return a.Value // ERROR a\.Value undefined
|
||||||
|
// TODO: The error below should probably be positioned on the '-'.
|
||||||
|
// d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value
|
||||||
|
// return d.Abs()
|
||||||
}
|
}
|
||||||
|
|
||||||
// The second example from the issue.
|
// The second example from the issue.
|
||||||
|
@ -70,7 +70,8 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o
|
|||||||
// see if there is a matching field (but not a method, those need to be declared
|
// see if there is a matching field (but not a method, those need to be declared
|
||||||
// explicitly in the constraint). If the constraint is a named pointer type (see
|
// explicitly in the constraint). If the constraint is a named pointer type (see
|
||||||
// above), we are ok here because only fields are accepted as results.
|
// above), we are ok here because only fields are accepted as results.
|
||||||
if obj == nil && isTypeParam(T) {
|
const enableTParamFieldLookup = false // see issue #51576
|
||||||
|
if enableTParamFieldLookup && obj == nil && isTypeParam(T) {
|
||||||
if t := coreType(T); t != nil {
|
if t := coreType(T); t != nil {
|
||||||
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false)
|
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false)
|
||||||
if _, ok := obj.(*Var); !ok {
|
if _, ok := obj.(*Var); !ok {
|
||||||
|
24
src/go/types/testdata/fixedbugs/issue50417.go2
vendored
24
src/go/types/testdata/fixedbugs/issue50417.go2
vendored
@ -2,6 +2,10 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Field accesses through type parameters are disabled
|
||||||
|
// until we have a more thorough understanding of the
|
||||||
|
// implications on the spec. See issue #51576.
|
||||||
|
|
||||||
package p
|
package p
|
||||||
|
|
||||||
type Sf struct {
|
type Sf struct {
|
||||||
@ -9,13 +13,13 @@ type Sf struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func f0[P Sf](p P) {
|
func f0[P Sf](p P) {
|
||||||
_ = p.f
|
_ = p.f // ERROR p\.f undefined
|
||||||
p.f = 0
|
p.f /* ERROR p\.f undefined */ = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func f0t[P ~struct{f int}](p P) {
|
func f0t[P ~struct{f int}](p P) {
|
||||||
_ = p.f
|
_ = p.f // ERROR p\.f undefined
|
||||||
p.f = 0
|
p.f /* ERROR p\.f undefined */ = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = f0[Sf]
|
var _ = f0[Sf]
|
||||||
@ -25,8 +29,8 @@ var _ = f0[Sm /* ERROR does not implement */ ]
|
|||||||
var _ = f0t[Sm /* ERROR does not implement */ ]
|
var _ = f0t[Sm /* ERROR does not implement */ ]
|
||||||
|
|
||||||
func f1[P interface{ Sf; m() }](p P) {
|
func f1[P interface{ Sf; m() }](p P) {
|
||||||
_ = p.f
|
_ = p.f // ERROR p\.f undefined
|
||||||
p.f = 0
|
p.f /* ERROR p\.f undefined */ = 0
|
||||||
p.m()
|
p.m()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,8 +48,8 @@ type Sfm struct {
|
|||||||
func (Sfm) m() {}
|
func (Sfm) m() {}
|
||||||
|
|
||||||
func f2[P interface{ Sfm; m() }](p P) {
|
func f2[P interface{ Sfm; m() }](p P) {
|
||||||
_ = p.f
|
_ = p.f // ERROR p\.f undefined
|
||||||
p.f = 0
|
p.f /* ERROR p\.f undefined */ = 0
|
||||||
p.m()
|
p.m()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +60,8 @@ var _ = f2[Sfm]
|
|||||||
type PSfm *Sfm
|
type PSfm *Sfm
|
||||||
|
|
||||||
func f3[P interface{ PSfm }](p P) {
|
func f3[P interface{ PSfm }](p P) {
|
||||||
_ = p.f
|
_ = p.f // ERROR p\.f undefined
|
||||||
p.f = 0
|
p.f /* ERROR p\.f undefined */ = 0
|
||||||
p.m /* ERROR type P has no field or method m */ ()
|
p.m /* ERROR type P has no field or method m */ ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
src/go/types/testdata/fixedbugs/issue50782.go2
vendored
13
src/go/types/testdata/fixedbugs/issue50782.go2
vendored
@ -2,6 +2,10 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Field accesses through type parameters are disabled
|
||||||
|
// until we have a more thorough understanding of the
|
||||||
|
// implications on the spec. See issue #51576.
|
||||||
|
|
||||||
package p
|
package p
|
||||||
|
|
||||||
// The first example from the issue.
|
// The first example from the issue.
|
||||||
@ -18,9 +22,12 @@ type numericAbs[T Numeric] interface {
|
|||||||
// AbsDifference computes the absolute value of the difference of
|
// AbsDifference computes the absolute value of the difference of
|
||||||
// a and b, where the absolute value is determined by the Abs method.
|
// a and b, where the absolute value is determined by the Abs method.
|
||||||
func absDifference[T numericAbs[T /* ERROR T does not implement Numeric */]](a, b T) T {
|
func absDifference[T numericAbs[T /* ERROR T does not implement Numeric */]](a, b T) T {
|
||||||
// TODO: the error below should probably be positioned on the '-'.
|
// Field accesses are not permitted for now. Keep an error so
|
||||||
d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value
|
// we can find and fix this code once the situation changes.
|
||||||
return d.Abs()
|
return a.Value // ERROR a\.Value undefined
|
||||||
|
// TODO: The error below should probably be positioned on the '-'.
|
||||||
|
// d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value
|
||||||
|
// return d.Abs()
|
||||||
}
|
}
|
||||||
|
|
||||||
// The second example from the issue.
|
// The second example from the issue.
|
||||||
|
@ -23,15 +23,16 @@ type Numeric interface {
|
|||||||
|
|
||||||
// numericAbs matches a struct containing a numeric type that has an Abs method.
|
// numericAbs matches a struct containing a numeric type that has an Abs method.
|
||||||
type numericAbs[T Numeric] interface {
|
type numericAbs[T Numeric] interface {
|
||||||
~struct{ Value T }
|
~struct{ Value_ T }
|
||||||
Abs() T
|
Abs() T
|
||||||
|
Value() T
|
||||||
}
|
}
|
||||||
|
|
||||||
// absDifference computes the absolute value of the difference of
|
// absDifference computes the absolute value of the difference of
|
||||||
// a and b, where the absolute value is determined by the Abs method.
|
// a and b, where the absolute value is determined by the Abs method.
|
||||||
func absDifference[T Numeric, U numericAbs[T]](a, b U) T {
|
func absDifference[T Numeric, U numericAbs[T]](a, b U) T {
|
||||||
d := a.Value - b.Value
|
d := a.Value() - b.Value()
|
||||||
dt := U{Value: d}
|
dt := U{Value_: d}
|
||||||
return dt.Abs()
|
return dt.Abs()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,20 +51,29 @@ type Complex interface {
|
|||||||
// orderedAbs is a helper type that defines an Abs method for
|
// orderedAbs is a helper type that defines an Abs method for
|
||||||
// a struct containing an ordered numeric type.
|
// a struct containing an ordered numeric type.
|
||||||
type orderedAbs[T orderedNumeric] struct {
|
type orderedAbs[T orderedNumeric] struct {
|
||||||
Value T
|
Value_ T
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a orderedAbs[T]) Abs() T {
|
func (a orderedAbs[T]) Abs() T {
|
||||||
if a.Value < 0 {
|
if a.Value_ < 0 {
|
||||||
return -a.Value
|
return -a.Value_
|
||||||
}
|
}
|
||||||
return a.Value
|
return a.Value_
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field accesses through type parameters are disabled
|
||||||
|
// until we have a more thorough understanding of the
|
||||||
|
// implications on the spec. See issue #51576.
|
||||||
|
// Use accessor method instead.
|
||||||
|
|
||||||
|
func (a orderedAbs[T]) Value() T {
|
||||||
|
return a.Value_
|
||||||
}
|
}
|
||||||
|
|
||||||
// complexAbs is a helper type that defines an Abs method for
|
// complexAbs is a helper type that defines an Abs method for
|
||||||
// a struct containing a complex type.
|
// a struct containing a complex type.
|
||||||
type complexAbs[T Complex] struct {
|
type complexAbs[T Complex] struct {
|
||||||
Value T
|
Value_ T
|
||||||
}
|
}
|
||||||
|
|
||||||
func realimag(x any) (re, im float64) {
|
func realimag(x any) (re, im float64) {
|
||||||
@ -82,13 +92,17 @@ func realimag(x any) (re, im float64) {
|
|||||||
|
|
||||||
func (a complexAbs[T]) Abs() T {
|
func (a complexAbs[T]) Abs() T {
|
||||||
// TODO use direct conversion instead of realimag once #50937 is fixed
|
// TODO use direct conversion instead of realimag once #50937 is fixed
|
||||||
r, i := realimag(a.Value)
|
r, i := realimag(a.Value_)
|
||||||
// r := float64(real(a.Value))
|
// r := float64(real(a.Value))
|
||||||
// i := float64(imag(a.Value))
|
// i := float64(imag(a.Value))
|
||||||
d := math.Sqrt(r*r + i*i)
|
d := math.Sqrt(r*r + i*i)
|
||||||
return T(complex(d, 0))
|
return T(complex(d, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a complexAbs[T]) Value() T {
|
||||||
|
return a.Value_
|
||||||
|
}
|
||||||
|
|
||||||
// OrderedAbsDifference returns the absolute value of the difference
|
// OrderedAbsDifference returns the absolute value of the difference
|
||||||
// between a and b, where a and b are of an ordered type.
|
// between a and b, where a and b are of an ordered type.
|
||||||
func OrderedAbsDifference[T orderedNumeric](a, b T) T {
|
func OrderedAbsDifference[T orderedNumeric](a, b T) T {
|
||||||
|
@ -17,15 +17,16 @@ type Numeric interface {
|
|||||||
|
|
||||||
// numericAbs matches a struct containing a numeric type that has an Abs method.
|
// numericAbs matches a struct containing a numeric type that has an Abs method.
|
||||||
type numericAbs[T Numeric] interface {
|
type numericAbs[T Numeric] interface {
|
||||||
~struct{ Value T }
|
~struct{ Value_ T }
|
||||||
Abs() T
|
Abs() T
|
||||||
|
Value() T
|
||||||
}
|
}
|
||||||
|
|
||||||
// absDifference computes the absolute value of the difference of
|
// absDifference computes the absolute value of the difference of
|
||||||
// a and b, where the absolute value is determined by the Abs method.
|
// a and b, where the absolute value is determined by the Abs method.
|
||||||
func absDifference[T Numeric, U numericAbs[T]](a, b U) T {
|
func absDifference[T Numeric, U numericAbs[T]](a, b U) T {
|
||||||
d := a.Value - b.Value
|
d := a.Value() - b.Value()
|
||||||
dt := U{Value: d}
|
dt := U{Value_: d}
|
||||||
return dt.Abs()
|
return dt.Abs()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,20 +45,29 @@ type Complex interface {
|
|||||||
// orderedAbs is a helper type that defines an Abs method for
|
// orderedAbs is a helper type that defines an Abs method for
|
||||||
// a struct containing an ordered numeric type.
|
// a struct containing an ordered numeric type.
|
||||||
type orderedAbs[T orderedNumeric] struct {
|
type orderedAbs[T orderedNumeric] struct {
|
||||||
Value T
|
Value_ T
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a orderedAbs[T]) Abs() T {
|
func (a orderedAbs[T]) Abs() T {
|
||||||
if a.Value < 0 {
|
if a.Value_ < 0 {
|
||||||
return -a.Value
|
return -a.Value_
|
||||||
}
|
}
|
||||||
return a.Value
|
return a.Value_
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field accesses through type parameters are disabled
|
||||||
|
// until we have a more thorough understanding of the
|
||||||
|
// implications on the spec. See issue #51576.
|
||||||
|
// Use accessor method instead.
|
||||||
|
|
||||||
|
func (a orderedAbs[T]) Value() T {
|
||||||
|
return a.Value_
|
||||||
}
|
}
|
||||||
|
|
||||||
// complexAbs is a helper type that defines an Abs method for
|
// complexAbs is a helper type that defines an Abs method for
|
||||||
// a struct containing a complex type.
|
// a struct containing a complex type.
|
||||||
type complexAbs[T Complex] struct {
|
type complexAbs[T Complex] struct {
|
||||||
Value T
|
Value_ T
|
||||||
}
|
}
|
||||||
|
|
||||||
func realimag(x any) (re, im float64) {
|
func realimag(x any) (re, im float64) {
|
||||||
@ -76,13 +86,17 @@ func realimag(x any) (re, im float64) {
|
|||||||
|
|
||||||
func (a complexAbs[T]) Abs() T {
|
func (a complexAbs[T]) Abs() T {
|
||||||
// TODO use direct conversion instead of realimag once #50937 is fixed
|
// TODO use direct conversion instead of realimag once #50937 is fixed
|
||||||
r, i := realimag(a.Value)
|
r, i := realimag(a.Value_)
|
||||||
// r := float64(real(a.Value))
|
// r := float64(real(a.Value))
|
||||||
// i := float64(imag(a.Value))
|
// i := float64(imag(a.Value))
|
||||||
d := math.Sqrt(r*r + i*i)
|
d := math.Sqrt(r*r + i*i)
|
||||||
return T(complex(d, 0))
|
return T(complex(d, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a complexAbs[T]) Value() T {
|
||||||
|
return a.Value_
|
||||||
|
}
|
||||||
|
|
||||||
// OrderedAbsDifference returns the absolute value of the difference
|
// OrderedAbsDifference returns the absolute value of the difference
|
||||||
// between a and b, where a and b are of an ordered type.
|
// between a and b, where a and b are of an ordered type.
|
||||||
func OrderedAbsDifference[T orderedNumeric](a, b T) T {
|
func OrderedAbsDifference[T orderedNumeric](a, b T) T {
|
||||||
|
@ -8,6 +8,11 @@ package main
|
|||||||
|
|
||||||
func main() {}
|
func main() {}
|
||||||
|
|
||||||
|
// Field accesses through type parameters are disabled
|
||||||
|
// until we have a more thorough understanding of the
|
||||||
|
// implications on the spec. See issue #51576.
|
||||||
|
|
||||||
|
/*
|
||||||
type Sf struct {
|
type Sf struct {
|
||||||
f int
|
f int
|
||||||
}
|
}
|
||||||
@ -138,3 +143,4 @@ func f8[P Int4](p P) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var _ = f8[*Sf]
|
var _ = f8[*Sf]
|
||||||
|
*/
|
||||||
|
@ -6,6 +6,13 @@
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
func main() {}
|
||||||
|
|
||||||
|
// Field accesses through type parameters are disabled
|
||||||
|
// until we have a more thorough understanding of the
|
||||||
|
// implications on the spec. See issue #51576.
|
||||||
|
|
||||||
|
/*
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
type MyStruct struct {
|
type MyStruct struct {
|
||||||
@ -48,3 +55,4 @@ func main() {
|
|||||||
panic(fmt.Sprintf("got %d, want %d", got, want))
|
panic(fmt.Sprintf("got %d, want %d", got, want))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
@ -29,34 +29,47 @@ func Sum[T Numeric](args ...T) T {
|
|||||||
|
|
||||||
// Ledger is an identifiable, financial record.
|
// Ledger is an identifiable, financial record.
|
||||||
type Ledger[T ~string, K Numeric] struct {
|
type Ledger[T ~string, K Numeric] struct {
|
||||||
|
|
||||||
// ID identifies the ledger.
|
// ID identifies the ledger.
|
||||||
ID T
|
ID_ T
|
||||||
|
|
||||||
// Amounts is a list of monies associated with this ledger.
|
// Amounts is a list of monies associated with this ledger.
|
||||||
Amounts []K
|
Amounts_ []K
|
||||||
|
|
||||||
// SumFn is a function that can be used to sum the amounts
|
// SumFn is a function that can be used to sum the amounts
|
||||||
// in this ledger.
|
// in this ledger.
|
||||||
SumFn func(...K) K
|
SumFn_ func(...K) K
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Field accesses through type parameters are disabled
|
||||||
|
// until we have a more thorough understanding of the
|
||||||
|
// implications on the spec. See issue #51576.
|
||||||
|
// Use accessor methods instead.
|
||||||
|
|
||||||
|
func (l Ledger[T, _]) ID() T { return l.ID_ }
|
||||||
|
func (l Ledger[_, K]) Amounts() []K { return l.Amounts_ }
|
||||||
|
func (l Ledger[_, K]) SumFn() func(...K) K { return l.SumFn_ }
|
||||||
|
|
||||||
func PrintLedger[
|
func PrintLedger[
|
||||||
T ~string,
|
T ~string,
|
||||||
K Numeric,
|
K Numeric,
|
||||||
L ~struct {
|
L interface {
|
||||||
ID T
|
~struct {
|
||||||
Amounts []K
|
ID_ T
|
||||||
SumFn func(...K) K
|
Amounts_ []K
|
||||||
|
SumFn_ func(...K) K
|
||||||
|
}
|
||||||
|
ID() T
|
||||||
|
Amounts() []K
|
||||||
|
SumFn() func(...K) K
|
||||||
},
|
},
|
||||||
](l L) {
|
](l L) {
|
||||||
fmt.Printf("%s has a sum of %v\n", l.ID, l.SumFn(l.Amounts...))
|
fmt.Printf("%s has a sum of %v\n", l.ID(), l.SumFn()(l.Amounts()...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
PrintLedger(Ledger[string, int]{
|
PrintLedger(Ledger[string, int]{
|
||||||
ID: "fake",
|
ID_: "fake",
|
||||||
Amounts: []int{1, 2, 3},
|
Amounts_: []int{1, 2, 3},
|
||||||
SumFn: Sum[int],
|
SumFn_: Sum[int],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -18,24 +18,34 @@ func Print[T ~string](s T) {
|
|||||||
fmt.Println(s)
|
fmt.Println(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrintWithPrinter[T ~string, S ~struct {
|
func PrintWithPrinter[T ~string, S interface {
|
||||||
ID T
|
~struct {
|
||||||
PrintFn func(T)
|
ID T
|
||||||
|
PrintFn_ func(T)
|
||||||
|
}
|
||||||
|
PrintFn() func(T)
|
||||||
}](message T, obj S) {
|
}](message T, obj S) {
|
||||||
obj.PrintFn(message)
|
obj.PrintFn()(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrintShop[T ~string] struct {
|
type PrintShop[T ~string] struct {
|
||||||
ID T
|
ID T
|
||||||
PrintFn func(T)
|
PrintFn_ func(T)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Field accesses through type parameters are disabled
|
||||||
|
// until we have a more thorough understanding of the
|
||||||
|
// implications on the spec. See issue #51576.
|
||||||
|
// Use accessor method instead.
|
||||||
|
|
||||||
|
func (s PrintShop[T]) PrintFn() func(T) { return s.PrintFn_ }
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
PrintWithPrinter(
|
PrintWithPrinter(
|
||||||
"Hello, world.",
|
"Hello, world.",
|
||||||
PrintShop[string]{
|
PrintShop[string]{
|
||||||
ID: "fake",
|
ID: "fake",
|
||||||
PrintFn: Print[string],
|
PrintFn_: Print[string],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -18,19 +18,33 @@ func Print[T ~string](s T) {
|
|||||||
fmt.Println(s)
|
fmt.Println(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrintWithPrinter[T ~string, S struct {
|
func PrintWithPrinter[T ~string, S interface {
|
||||||
ID T
|
~struct {
|
||||||
PrintFn func(T)
|
ID T
|
||||||
|
PrintFn_ func(T)
|
||||||
|
}
|
||||||
|
PrintFn() func(T)
|
||||||
}](message T, obj S) {
|
}](message T, obj S) {
|
||||||
obj.PrintFn(message)
|
obj.PrintFn()(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
PrintWithPrinter(
|
PrintWithPrinter(
|
||||||
"Hello, world.",
|
"Hello, world.",
|
||||||
struct {
|
StructWithPrinter{ID: "fake", PrintFn_: Print[string]},
|
||||||
ID string
|
|
||||||
PrintFn func(string)
|
|
||||||
}{ID: "fake", PrintFn: Print[string]},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StructWithPrinter struct {
|
||||||
|
ID string
|
||||||
|
PrintFn_ func(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Field accesses through type parameters are disabled
|
||||||
|
// until we have a more thorough understanding of the
|
||||||
|
// implications on the spec. See issue #51576.
|
||||||
|
// Use accessor method instead.
|
||||||
|
|
||||||
|
func (s StructWithPrinter) PrintFn() func(string) {
|
||||||
|
return s.PrintFn_
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user