// 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
// 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 {
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false)
if _, ok := obj.(*Var); !ok {
// Use of this source code is governed by a BSD-style
// 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
type Sf struct {
}
func f0[P Sf](p P) {
- _ = p.f
- p.f = 0
+ _ = p.f // ERROR p\.f undefined
+ p.f /* ERROR p\.f undefined */ = 0
}
func f0t[P ~struct{f int}](p P) {
- _ = p.f
- p.f = 0
+ _ = p.f // ERROR p\.f undefined
+ p.f /* ERROR p\.f undefined */ = 0
}
var _ = f0[Sf]
var _ = f0t[Sm /* ERROR does not implement */ ]
func f1[P interface{ Sf; m() }](p P) {
- _ = p.f
- p.f = 0
+ _ = p.f // ERROR p\.f undefined
+ p.f /* ERROR p\.f undefined */ = 0
p.m()
}
func (Sfm) m() {}
func f2[P interface{ Sfm; m() }](p P) {
- _ = p.f
- p.f = 0
+ _ = p.f // ERROR p\.f undefined
+ p.f /* ERROR p\.f undefined */ = 0
p.m()
}
type PSfm *Sfm
func f3[P interface{ PSfm }](p P) {
- _ = p.f
- p.f = 0
+ _ = p.f // ERROR p\.f undefined
+ p.f /* ERROR p\.f undefined */ = 0
p.m /* ERROR type P has no field or method m */ ()
}
// Use of this source code is governed by a BSD-style
// 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
// The first example from the issue.
// AbsDifference computes the absolute value of the difference of
// 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 {
- // TODO: the error below should probably be positioned on the '-'.
- d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value
- return d.Abs()
+ // Field accesses are not permitted for now. Keep an error so
+ // we can find and fix this code once the situation changes.
+ 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.
// 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
// 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 {
obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false)
if _, ok := obj.(*Var); !ok {
// Use of this source code is governed by a BSD-style
// 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
type Sf struct {
}
func f0[P Sf](p P) {
- _ = p.f
- p.f = 0
+ _ = p.f // ERROR p\.f undefined
+ p.f /* ERROR p\.f undefined */ = 0
}
func f0t[P ~struct{f int}](p P) {
- _ = p.f
- p.f = 0
+ _ = p.f // ERROR p\.f undefined
+ p.f /* ERROR p\.f undefined */ = 0
}
var _ = f0[Sf]
var _ = f0t[Sm /* ERROR does not implement */ ]
func f1[P interface{ Sf; m() }](p P) {
- _ = p.f
- p.f = 0
+ _ = p.f // ERROR p\.f undefined
+ p.f /* ERROR p\.f undefined */ = 0
p.m()
}
func (Sfm) m() {}
func f2[P interface{ Sfm; m() }](p P) {
- _ = p.f
- p.f = 0
+ _ = p.f // ERROR p\.f undefined
+ p.f /* ERROR p\.f undefined */ = 0
p.m()
}
type PSfm *Sfm
func f3[P interface{ PSfm }](p P) {
- _ = p.f
- p.f = 0
+ _ = p.f // ERROR p\.f undefined
+ p.f /* ERROR p\.f undefined */ = 0
p.m /* ERROR type P has no field or method m */ ()
}
// Use of this source code is governed by a BSD-style
// 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
// The first example from the issue.
// AbsDifference computes the absolute value of the difference of
// 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 {
- // TODO: the error below should probably be positioned on the '-'.
- d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value
- return d.Abs()
+ // Field accesses are not permitted for now. Keep an error so
+ // we can find and fix this code once the situation changes.
+ 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.
// numericAbs matches a struct containing a numeric type that has an Abs method.
type numericAbs[T Numeric] interface {
- ~struct{ Value T }
+ ~struct{ Value_ T }
Abs() T
+ Value() T
}
// absDifference computes the absolute value of the difference of
// a and b, where the absolute value is determined by the Abs method.
func absDifference[T Numeric, U numericAbs[T]](a, b U) T {
- d := a.Value - b.Value
- dt := U{Value: d}
+ d := a.Value() - b.Value()
+ dt := U{Value_: d}
return dt.Abs()
}
// orderedAbs is a helper type that defines an Abs method for
// a struct containing an ordered numeric type.
type orderedAbs[T orderedNumeric] struct {
- Value T
+ Value_ T
}
func (a orderedAbs[T]) Abs() T {
- if a.Value < 0 {
- return -a.Value
+ if a.Value_ < 0 {
+ 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
// a struct containing a complex type.
type complexAbs[T Complex] struct {
- Value T
+ Value_ T
}
func realimag(x any) (re, im float64) {
func (a complexAbs[T]) Abs() T {
// 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))
// i := float64(imag(a.Value))
d := math.Sqrt(r*r + i*i)
return T(complex(d, 0))
}
+func (a complexAbs[T]) Value() T {
+ return a.Value_
+}
+
// OrderedAbsDifference returns the absolute value of the difference
// between a and b, where a and b are of an ordered type.
func OrderedAbsDifference[T orderedNumeric](a, b T) T {
// numericAbs matches a struct containing a numeric type that has an Abs method.
type numericAbs[T Numeric] interface {
- ~struct{ Value T }
+ ~struct{ Value_ T }
Abs() T
+ Value() T
}
// absDifference computes the absolute value of the difference of
// a and b, where the absolute value is determined by the Abs method.
func absDifference[T Numeric, U numericAbs[T]](a, b U) T {
- d := a.Value - b.Value
- dt := U{Value: d}
+ d := a.Value() - b.Value()
+ dt := U{Value_: d}
return dt.Abs()
}
// orderedAbs is a helper type that defines an Abs method for
// a struct containing an ordered numeric type.
type orderedAbs[T orderedNumeric] struct {
- Value T
+ Value_ T
}
func (a orderedAbs[T]) Abs() T {
- if a.Value < 0 {
- return -a.Value
+ if a.Value_ < 0 {
+ 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
// a struct containing a complex type.
type complexAbs[T Complex] struct {
- Value T
+ Value_ T
}
func realimag(x any) (re, im float64) {
func (a complexAbs[T]) Abs() T {
// 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))
// i := float64(imag(a.Value))
d := math.Sqrt(r*r + i*i)
return T(complex(d, 0))
}
+func (a complexAbs[T]) Value() T {
+ return a.Value_
+}
+
// OrderedAbsDifference returns the absolute value of the difference
// between a and b, where a and b are of an ordered type.
func OrderedAbsDifference[T orderedNumeric](a, b T) T {
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 {
f int
}
}
var _ = f8[*Sf]
+*/
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"
type MyStruct struct {
panic(fmt.Sprintf("got %d, want %d", got, want))
}
}
+*/
// Ledger is an identifiable, financial record.
type Ledger[T ~string, K Numeric] struct {
-
// ID identifies the ledger.
- ID T
+ ID_ T
// 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
// 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[
T ~string,
K Numeric,
- L ~struct {
- ID T
- Amounts []K
- SumFn func(...K) K
+ L interface {
+ ~struct {
+ ID_ T
+ Amounts_ []K
+ SumFn_ func(...K) K
+ }
+ ID() T
+ Amounts() []K
+ SumFn() func(...K) K
},
](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() {
PrintLedger(Ledger[string, int]{
- ID: "fake",
- Amounts: []int{1, 2, 3},
- SumFn: Sum[int],
+ ID_: "fake",
+ Amounts_: []int{1, 2, 3},
+ SumFn_: Sum[int],
})
}
fmt.Println(s)
}
-func PrintWithPrinter[T ~string, S ~struct {
- ID T
- PrintFn func(T)
+func PrintWithPrinter[T ~string, S interface {
+ ~struct {
+ ID T
+ PrintFn_ func(T)
+ }
+ PrintFn() func(T)
}](message T, obj S) {
- obj.PrintFn(message)
+ obj.PrintFn()(message)
}
type PrintShop[T ~string] struct {
- ID T
- PrintFn func(T)
+ ID 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() {
PrintWithPrinter(
"Hello, world.",
PrintShop[string]{
- ID: "fake",
- PrintFn: Print[string],
+ ID: "fake",
+ PrintFn_: Print[string],
},
)
}
fmt.Println(s)
}
-func PrintWithPrinter[T ~string, S struct {
- ID T
- PrintFn func(T)
+func PrintWithPrinter[T ~string, S interface {
+ ~struct {
+ ID T
+ PrintFn_ func(T)
+ }
+ PrintFn() func(T)
}](message T, obj S) {
- obj.PrintFn(message)
+ obj.PrintFn()(message)
}
func main() {
PrintWithPrinter(
"Hello, world.",
- struct {
- ID string
- PrintFn func(string)
- }{ID: "fake", PrintFn: Print[string]},
+ StructWithPrinter{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_
+}