Skip to content

Commit 2d4746f

Browse files
griesemercagedmantis
authored andcommitted
[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 <[email protected]> Auto-Submit: Robert Griesemer <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> Reviewed-on: https://go-review.googlesource.com/c/go/+/520601
1 parent 2b8026f commit 2d4746f

File tree

6 files changed

+48
-28
lines changed

6 files changed

+48
-28
lines changed

src/cmd/compile/internal/types2/infer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
9696
// Unify parameter and argument types for generic parameters with typed arguments
9797
// and collect the indices of generic parameters with untyped arguments.
9898
// Terminology: generic parameter = function parameter with a type-parameterized type
99-
u := newUnifier(tparams, targs)
99+
u := newUnifier(tparams, targs, check.allowVersion(check.pkg, pos, go1_21))
100100

101101
errorf := func(kind string, tpar, targ Type, arg *operand) {
102102
// provide a better error message if we can

src/cmd/compile/internal/types2/unify.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,6 @@ const (
5353
// the core types, if any, of non-local (unbound) type parameters.
5454
enableCoreTypeUnification = true
5555

56-
// If enableInterfaceInference is set, type inference uses
57-
// shared methods for improved type inference involving
58-
// interfaces.
59-
enableInterfaceInference = true
60-
6156
// If traceInference is set, unification will print a trace of its operation.
6257
// Interpretation of trace:
6358
// x ≡ y attempt to unify types x and y
@@ -81,15 +76,16 @@ type unifier struct {
8176
// that inferring the type for a given type parameter P will
8277
// automatically infer the same type for all other parameters
8378
// unified (joined) with P.
84-
handles map[*TypeParam]*Type
85-
depth int // recursion depth during unification
79+
handles map[*TypeParam]*Type
80+
depth int // recursion depth during unification
81+
enableInterfaceInference bool // use shared methods for better inference
8682
}
8783

8884
// newUnifier returns a new unifier initialized with the given type parameter
8985
// and corresponding type argument lists. The type argument list may be shorter
9086
// than the type parameter list, and it may contain nil types. Matching type
9187
// parameters and arguments must have the same index.
92-
func newUnifier(tparams []*TypeParam, targs []Type) *unifier {
88+
func newUnifier(tparams []*TypeParam, targs []Type, enableInterfaceInference bool) *unifier {
9389
assert(len(tparams) >= len(targs))
9490
handles := make(map[*TypeParam]*Type, len(tparams))
9591
// Allocate all handles up-front: in a correct program, all type parameters
@@ -103,7 +99,7 @@ func newUnifier(tparams []*TypeParam, targs []Type) *unifier {
10399
}
104100
handles[x] = &t
105101
}
106-
return &unifier{handles, 0}
102+
return &unifier{handles, 0, enableInterfaceInference}
107103
}
108104

109105
// unifyMode controls the behavior of the unifier.
@@ -339,7 +335,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
339335
// we will fail at function instantiation or argument assignment time.
340336
//
341337
// If we have at least one defined type, there is one in y.
342-
if ny, _ := y.(*Named); mode&exact == 0 && ny != nil && isTypeLit(x) && !(enableInterfaceInference && IsInterface(x)) {
338+
if ny, _ := y.(*Named); mode&exact == 0 && ny != nil && isTypeLit(x) && !(u.enableInterfaceInference && IsInterface(x)) {
343339
if traceInference {
344340
u.tracef("%s ≡ under %s", x, ny)
345341
}
@@ -437,12 +433,12 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
437433
emode |= exact
438434
}
439435

440-
// If EnableInterfaceInference is set and we don't require exact unification,
436+
// If u.EnableInterfaceInference is set and we don't require exact unification,
441437
// if both types are interfaces, one interface must have a subset of the
442438
// methods of the other and corresponding method signatures must unify.
443439
// If only one type is an interface, all its methods must be present in the
444440
// other type and corresponding method signatures must unify.
445-
if enableInterfaceInference && mode&exact == 0 {
441+
if u.enableInterfaceInference && mode&exact == 0 {
446442
// One or both interfaces may be defined types.
447443
// Look under the name, but not under type parameters (go.dev/issue/60564).
448444
xi := asInterface(x)
@@ -632,7 +628,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
632628
}
633629

634630
case *Interface:
635-
assert(!enableInterfaceInference || mode&exact != 0) // handled before this switch
631+
assert(!u.enableInterfaceInference || mode&exact != 0) // handled before this switch
636632

637633
// Two interface types unify if they have the same set of methods with
638634
// the same names, and corresponding function types unify.

src/go/types/generate_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,14 @@ func fixInferSig(f *ast.File) {
242242
n.Args[0] = arg
243243
return false
244244
}
245+
case "allowVersion":
246+
// rewrite check.allowVersion(..., pos, ...) to check.allowVersion(..., posn, ...)
247+
if ident, _ := n.Args[1].(*ast.Ident); ident != nil && ident.Name == "pos" {
248+
pos := n.Args[1].Pos()
249+
arg := newIdent(pos, "posn")
250+
n.Args[1] = arg
251+
return false
252+
}
245253
}
246254
}
247255
}

src/go/types/infer.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/go/types/unify.go

Lines changed: 9 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// -lang=go1.20
2+
3+
// Copyright 2023 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package p
8+
9+
type T[P any] interface{}
10+
11+
func f1[P any](T[P]) {}
12+
func f2[P any](T[P], P) {}
13+
14+
func _() {
15+
var t T[int]
16+
f1(t)
17+
18+
var s string
19+
f2(t, s /* ERROR "type string of s does not match inferred type int for P" */)
20+
}

0 commit comments

Comments
 (0)