diff options
author | Robert Griesemer <gri@golang.org> | 2023-08-15 16:37:00 -0700 |
---|---|---|
committer | Carlos Amedee <carlos@golang.org> | 2023-08-24 21:12:30 +0000 |
commit | 2d4746f37b27ad30cf35cc55d2cdfdfb0309219b (patch) | |
tree | f373362b7c61e17fb8716ecc01b0ed8a4c8865df | |
parent | 2b8026f02535d45a23445ab0e70b27ac839d0e68 (diff) | |
download | go-2d4746f37b27ad30cf35cc55d2cdfdfb0309219b.tar.gz go-2d4746f37b27ad30cf35cc55d2cdfdfb0309219b.zip |
[release-branch.go1.21] go/types, types2: disable interface inference for versions before Go 1.21
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
-rw-r--r-- | src/cmd/compile/internal/types2/infer.go | 2 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/unify.go | 22 | ||||
-rw-r--r-- | src/go/types/generate_test.go | 8 | ||||
-rw-r--r-- | src/go/types/infer.go | 2 | ||||
-rw-r--r-- | src/go/types/unify.go | 22 | ||||
-rw-r--r-- | src/internal/types/testdata/fixedbugs/issue61903.go | 20 |
6 files changed, 48 insertions, 28 deletions
diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index 44d66eb516..5eb916c528 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -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 diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index eddd808cb7..4f04132353 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -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. diff --git a/src/go/types/generate_test.go b/src/go/types/generate_test.go index 75fda025ee..2578cbbd15 100644 --- a/src/go/types/generate_test.go +++ b/src/go/types/generate_test.go @@ -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 + } } } } diff --git a/src/go/types/infer.go b/src/go/types/infer.go index 7c7898435b..cb7634415b 100644 --- a/src/go/types/infer.go +++ b/src/go/types/infer.go @@ -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 diff --git a/src/go/types/unify.go b/src/go/types/unify.go index 56b258ae35..646eb3e339 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -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 index 0000000000..8a6fcd9529 --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue61903.go @@ -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" */) +} |