]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[release-branch.go1.21] go/types, types2: disable interface inference for versions...
authorRobert Griesemer <gri@golang.org>
Tue, 15 Aug 2023 23:37:00 +0000 (16:37 -0700)
committerCarlos Amedee <carlos@golang.org>
Thu, 24 Aug 2023 21:12:30 +0000 (21:12 +0000)
Change the internal constant enableInterfaceInference to a unifier
field that can be controlled dynamically and set it for Go 1.21
or later.

This restores Go 1.20 unification behavior for interfaces.

Fixes #61930.

Change-Id: Iefd6c0899811f8208a8be9cef2650a07787ae177
Reviewed-on: https://go-review.googlesource.com/c/go/+/519855
Reviewed-by: Robert Findley <rfindley@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/520601

src/cmd/compile/internal/types2/infer.go
src/cmd/compile/internal/types2/unify.go
src/go/types/generate_test.go
src/go/types/infer.go
src/go/types/unify.go
src/internal/types/testdata/fixedbugs/issue61903.go [new file with mode: 0644]

index 44d66eb516e94cacc6e9808f4ffe1cfe014e43e7..5eb916c528a4a720b67256e299c1749d0efa80f0 100644 (file)
@@ -96,7 +96,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
        // Unify parameter and argument types for generic parameters with typed arguments
        // and collect the indices of generic parameters with untyped arguments.
        // Terminology: generic parameter = function parameter with a type-parameterized type
-       u := newUnifier(tparams, targs)
+       u := newUnifier(tparams, targs, check.allowVersion(check.pkg, pos, go1_21))
 
        errorf := func(kind string, tpar, targ Type, arg *operand) {
                // provide a better error message if we can
index eddd808cb77b56771555e5c9a2cb08fe2d68163c..4f041323532a0508343abceba09b0b75ae0ba3c7 100644 (file)
@@ -53,11 +53,6 @@ const (
        // the core types, if any, of non-local (unbound) type parameters.
        enableCoreTypeUnification = true
 
-       // If enableInterfaceInference is set, type inference uses
-       // shared methods for improved type inference involving
-       // interfaces.
-       enableInterfaceInference = true
-
        // If traceInference is set, unification will print a trace of its operation.
        // Interpretation of trace:
        //   x ≡ y    attempt to unify types x and y
@@ -81,15 +76,16 @@ type unifier struct {
        // that inferring the type for a given type parameter P will
        // automatically infer the same type for all other parameters
        // unified (joined) with P.
-       handles map[*TypeParam]*Type
-       depth   int // recursion depth during unification
+       handles                  map[*TypeParam]*Type
+       depth                    int  // recursion depth during unification
+       enableInterfaceInference bool // use shared methods for better inference
 }
 
 // newUnifier returns a new unifier initialized with the given type parameter
 // and corresponding type argument lists. The type argument list may be shorter
 // than the type parameter list, and it may contain nil types. Matching type
 // parameters and arguments must have the same index.
-func newUnifier(tparams []*TypeParam, targs []Type) *unifier {
+func newUnifier(tparams []*TypeParam, targs []Type, enableInterfaceInference bool) *unifier {
        assert(len(tparams) >= len(targs))
        handles := make(map[*TypeParam]*Type, len(tparams))
        // Allocate all handles up-front: in a correct program, all type parameters
@@ -103,7 +99,7 @@ func newUnifier(tparams []*TypeParam, targs []Type) *unifier {
                }
                handles[x] = &t
        }
-       return &unifier{handles, 0}
+       return &unifier{handles, 0, enableInterfaceInference}
 }
 
 // unifyMode controls the behavior of the unifier.
@@ -339,7 +335,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
        // we will fail at function instantiation or argument assignment time.
        //
        // If we have at least one defined type, there is one in y.
-       if ny, _ := y.(*Named); mode&exact == 0 && ny != nil && isTypeLit(x) && !(enableInterfaceInference && IsInterface(x)) {
+       if ny, _ := y.(*Named); mode&exact == 0 && ny != nil && isTypeLit(x) && !(u.enableInterfaceInference && IsInterface(x)) {
                if traceInference {
                        u.tracef("%s ≡ under %s", x, ny)
                }
@@ -437,12 +433,12 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
                emode |= exact
        }
 
-       // If EnableInterfaceInference is set and we don't require exact unification,
+       // If u.EnableInterfaceInference is set and we don't require exact unification,
        // if both types are interfaces, one interface must have a subset of the
        // methods of the other and corresponding method signatures must unify.
        // If only one type is an interface, all its methods must be present in the
        // other type and corresponding method signatures must unify.
-       if enableInterfaceInference && mode&exact == 0 {
+       if u.enableInterfaceInference && mode&exact == 0 {
                // One or both interfaces may be defined types.
                // Look under the name, but not under type parameters (go.dev/issue/60564).
                xi := asInterface(x)
@@ -632,7 +628,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
                }
 
        case *Interface:
-               assert(!enableInterfaceInference || mode&exact != 0) // handled before this switch
+               assert(!u.enableInterfaceInference || mode&exact != 0) // handled before this switch
 
                // Two interface types unify if they have the same set of methods with
                // the same names, and corresponding function types unify.
index 75fda025ee1e31f216e96a2f664f6a518a8568f6..2578cbbd156e4ad8ed64b6b2a3ec142bad1530c0 100644 (file)
@@ -242,6 +242,14 @@ func fixInferSig(f *ast.File) {
                                                n.Args[0] = arg
                                                return false
                                        }
+                               case "allowVersion":
+                                       // rewrite check.allowVersion(..., pos, ...) to check.allowVersion(..., posn, ...)
+                                       if ident, _ := n.Args[1].(*ast.Ident); ident != nil && ident.Name == "pos" {
+                                               pos := n.Args[1].Pos()
+                                               arg := newIdent(pos, "posn")
+                                               n.Args[1] = arg
+                                               return false
+                                       }
                                }
                        }
                }
index 7c7898435ba6b1f72295095e2aa958214b954cf3..cb7634415bf54cfc195ecae362f3125bacfb0f4e 100644 (file)
@@ -98,7 +98,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type,
        // Unify parameter and argument types for generic parameters with typed arguments
        // and collect the indices of generic parameters with untyped arguments.
        // Terminology: generic parameter = function parameter with a type-parameterized type
-       u := newUnifier(tparams, targs)
+       u := newUnifier(tparams, targs, check.allowVersion(check.pkg, posn, go1_21))
 
        errorf := func(kind string, tpar, targ Type, arg *operand) {
                // provide a better error message if we can
index 56b258ae35a74abdae72bad3462c72131c6b4ca5..646eb3e3390796c28ced4122960c81243b33d175 100644 (file)
@@ -55,11 +55,6 @@ const (
        // the core types, if any, of non-local (unbound) type parameters.
        enableCoreTypeUnification = true
 
-       // If enableInterfaceInference is set, type inference uses
-       // shared methods for improved type inference involving
-       // interfaces.
-       enableInterfaceInference = true
-
        // If traceInference is set, unification will print a trace of its operation.
        // Interpretation of trace:
        //   x ≡ y    attempt to unify types x and y
@@ -83,15 +78,16 @@ type unifier struct {
        // that inferring the type for a given type parameter P will
        // automatically infer the same type for all other parameters
        // unified (joined) with P.
-       handles map[*TypeParam]*Type
-       depth   int // recursion depth during unification
+       handles                  map[*TypeParam]*Type
+       depth                    int  // recursion depth during unification
+       enableInterfaceInference bool // use shared methods for better inference
 }
 
 // newUnifier returns a new unifier initialized with the given type parameter
 // and corresponding type argument lists. The type argument list may be shorter
 // than the type parameter list, and it may contain nil types. Matching type
 // parameters and arguments must have the same index.
-func newUnifier(tparams []*TypeParam, targs []Type) *unifier {
+func newUnifier(tparams []*TypeParam, targs []Type, enableInterfaceInference bool) *unifier {
        assert(len(tparams) >= len(targs))
        handles := make(map[*TypeParam]*Type, len(tparams))
        // Allocate all handles up-front: in a correct program, all type parameters
@@ -105,7 +101,7 @@ func newUnifier(tparams []*TypeParam, targs []Type) *unifier {
                }
                handles[x] = &t
        }
-       return &unifier{handles, 0}
+       return &unifier{handles, 0, enableInterfaceInference}
 }
 
 // unifyMode controls the behavior of the unifier.
@@ -341,7 +337,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
        // we will fail at function instantiation or argument assignment time.
        //
        // If we have at least one defined type, there is one in y.
-       if ny, _ := y.(*Named); mode&exact == 0 && ny != nil && isTypeLit(x) && !(enableInterfaceInference && IsInterface(x)) {
+       if ny, _ := y.(*Named); mode&exact == 0 && ny != nil && isTypeLit(x) && !(u.enableInterfaceInference && IsInterface(x)) {
                if traceInference {
                        u.tracef("%s ≡ under %s", x, ny)
                }
@@ -439,12 +435,12 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
                emode |= exact
        }
 
-       // If EnableInterfaceInference is set and we don't require exact unification,
+       // If u.EnableInterfaceInference is set and we don't require exact unification,
        // if both types are interfaces, one interface must have a subset of the
        // methods of the other and corresponding method signatures must unify.
        // If only one type is an interface, all its methods must be present in the
        // other type and corresponding method signatures must unify.
-       if enableInterfaceInference && mode&exact == 0 {
+       if u.enableInterfaceInference && mode&exact == 0 {
                // One or both interfaces may be defined types.
                // Look under the name, but not under type parameters (go.dev/issue/60564).
                xi := asInterface(x)
@@ -634,7 +630,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
                }
 
        case *Interface:
-               assert(!enableInterfaceInference || mode&exact != 0) // handled before this switch
+               assert(!u.enableInterfaceInference || mode&exact != 0) // handled before this switch
 
                // Two interface types unify if they have the same set of methods with
                // the same names, and corresponding function types unify.
diff --git a/src/internal/types/testdata/fixedbugs/issue61903.go b/src/internal/types/testdata/fixedbugs/issue61903.go
new file mode 100644 (file)
index 0000000..8a6fcd9
--- /dev/null
@@ -0,0 +1,20 @@
+// -lang=go1.20
+
+// Copyright 2023 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 T[P any] interface{}
+
+func f1[P any](T[P])    {}
+func f2[P any](T[P], P) {}
+
+func _() {
+       var t T[int]
+       f1(t)
+
+       var s string
+       f2(t, s /* ERROR "type string of s does not match inferred type int for P" */)
+}