]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.18] go/types, types2: disable field accesses through type parameters
authorRobert Griesemer <gri@golang.org>
Wed, 9 Mar 2022 18:01:24 +0000 (10:01 -0800)
committerDmitri Shuralyov <dmitshur@golang.org>
Thu, 10 Mar 2022 23:59:19 +0000 (23:59 +0000)
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>
(cherry picked from commit b8248fab897da9bee2211a98df1656883ccecd6d)
Reviewed-on: https://go-review.googlesource.com/c/go/+/391355
Trust: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
13 files changed:
src/cmd/compile/internal/types2/lookup.go
src/cmd/compile/internal/types2/testdata/fixedbugs/issue50417.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue50782.go2
src/go/types/lookup.go
src/go/types/testdata/fixedbugs/issue50417.go2
src/go/types/testdata/fixedbugs/issue50782.go2
test/typeparam/absdiff2.go
test/typeparam/absdiffimp2.dir/a.go
test/typeparam/issue50417.go
test/typeparam/issue50417b.go
test/typeparam/issue50690a.go
test/typeparam/issue50690b.go
test/typeparam/issue50690c.go

index 0a2d2a579026a834ff770eefe9ac1fd2f8312d4a..08328772260fc308ec804e367fb51dcc525a04ea 100644 (file)
@@ -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
        // 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 {
index 50487fa2ffeeedc97a1344847e70b779d969955d..2caef1b9863e65fabccec6eeb9b8d6108599710e 100644 (file)
@@ -2,6 +2,10 @@
 // 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 {
@@ -9,13 +13,13 @@ 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]
@@ -25,8 +29,8 @@ 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.f // ERROR p\.f undefined
+        p.f /* ERROR p\.f undefined */ = 0
         p.m()
 }
 
@@ -44,8 +48,8 @@ type Sfm struct {
 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()
 }
 
@@ -56,8 +60,8 @@ var _ = f2[Sfm]
 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 */ ()
 }
 
index 8f41b84163056f4a173d9dd3ca143561da89d635..fd1ab11b8cf120ba3870b7add36b317a13064b69 100644 (file)
@@ -2,6 +2,10 @@
 // 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.
@@ -18,9 +22,12 @@ type numericAbs[T Numeric] interface {
 // 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.
index 501c230357b5014ea6b17a26b5985143d1daf77c..335fada7b764957cdf310177b2adaca082e902dc 100644 (file)
@@ -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
        // 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 {
index 50487fa2ffeeedc97a1344847e70b779d969955d..2caef1b9863e65fabccec6eeb9b8d6108599710e 100644 (file)
@@ -2,6 +2,10 @@
 // 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 {
@@ -9,13 +13,13 @@ 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]
@@ -25,8 +29,8 @@ 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.f // ERROR p\.f undefined
+        p.f /* ERROR p\.f undefined */ = 0
         p.m()
 }
 
@@ -44,8 +48,8 @@ type Sfm struct {
 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()
 }
 
@@ -56,8 +60,8 @@ var _ = f2[Sfm]
 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 */ ()
 }
 
index 8f41b84163056f4a173d9dd3ca143561da89d635..fd1ab11b8cf120ba3870b7add36b317a13064b69 100644 (file)
@@ -2,6 +2,10 @@
 // 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.
@@ -18,9 +22,12 @@ type numericAbs[T Numeric] interface {
 // 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.
index 36de8ff2c9ab3065ba55264a8aa33e30dc0ecb1c..443388e610d0e8512760d61cf11b89498b738b62 100644 (file)
@@ -23,15 +23,16 @@ type Numeric interface {
 
 // 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()
 }
 
@@ -50,20 +51,29 @@ type Complex interface {
 // 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) {
@@ -82,13 +92,17 @@ 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 {
index 43493e1430d4f23f81735833666428e12f5d5eb0..dc64f2dcbed7594b9b9d7999814ad5a10109448d 100644 (file)
@@ -17,15 +17,16 @@ type Numeric interface {
 
 // 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()
 }
 
@@ -44,20 +45,29 @@ type Complex interface {
 // 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) {
@@ -76,13 +86,17 @@ 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 {
index 12dbd0efb7454886081403c48a512f53020d6c11..e93583fc35a51381ead4eb28a325f271073348ee 100644 (file)
@@ -8,6 +8,11 @@ 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.
+
+/*
 type Sf struct {
        f int
 }
@@ -138,3 +143,4 @@ func f8[P Int4](p P) {
 }
 
 var _ = f8[*Sf]
+*/
index e6b205cb37394522ea39ba45d8f4e481e52350a0..86e1f8aa1468a605d8f8857ea6543b9ddf1cf712 100644 (file)
@@ -6,6 +6,13 @@
 
 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 {
@@ -48,3 +55,4 @@ func main() {
                panic(fmt.Sprintf("got %d, want %d", got, want))
        }
 }
+*/
index 5af3c9ead88421f06760870de90ffe82547eb98b..0f5f5e9bd1bbe5877b234546c5125867bb62f790 100644 (file)
@@ -29,34 +29,47 @@ func Sum[T Numeric](args ...T) T {
 
 // 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],
        })
 }
index 498b9d37e15be3d710dc97388d075d38ce0b534b..572d8eb0ff39c133dede21b0b2227a7552dd0c8f 100644 (file)
@@ -18,24 +18,34 @@ func Print[T ~string](s T) {
        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],
                },
        )
 }
index aa9258f932c0c353c22b7cf85cfc43a535418427..8b87c2f06ddbee050d940ce759758ffcc4f6073c 100644 (file)
@@ -18,19 +18,33 @@ func Print[T ~string](s T) {
        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_
+}