From: Robert Griesemer Date: Thu, 1 Jun 2023 22:02:54 +0000 (-0700) Subject: go/types, types2: report inference instead of assignment failure when types can't... X-Git-Tag: go1.21rc1~117 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=0cd9064cd734501738e20a902f942523df0a5a5a;p=gostls13.git go/types, types2: report inference instead of assignment failure when types can't match Interface inference must only be used if we don't require exact unification, otherwise we may infer types (that are reasonable) but then fail with an assignment error. Only checking if exact is set for defined (named) types is not sufficient, we must also check outside. Oversight. Fixes #60562. Change-Id: I208a74bf7ed80bcb976ba9cc172715c83f9e3d0a Reviewed-on: https://go-review.googlesource.com/c/go/+/499996 Auto-Submit: Robert Griesemer TryBot-Result: Gopher Robot Reviewed-by: Robert Findley Run-TryBot: Robert Griesemer Reviewed-by: Robert Griesemer --- diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 3f54a2c2f2..5c7d24aff6 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -387,12 +387,12 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { emode |= exact } - // If EnableInterfaceInference is set and both types are interfaces, one - // interface must have a subset of the methods of the other and corresponding - // method signatures must unify. + // If 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 { + if enableInterfaceInference && mode&exact == 0 { xi, _ := x.(*Interface) yi, _ := y.(*Interface) // If we have two interfaces, check the type terms for equivalence, @@ -565,7 +565,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { } case *Interface: - assert(!enableInterfaceInference) // handled before this switch + assert(!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/unify.go b/src/go/types/unify.go index 217356f13e..00373e01f2 100644 --- a/src/go/types/unify.go +++ b/src/go/types/unify.go @@ -389,12 +389,12 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { emode |= exact } - // If EnableInterfaceInference is set and both types are interfaces, one - // interface must have a subset of the methods of the other and corresponding - // method signatures must unify. + // If 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 { + if enableInterfaceInference && mode&exact == 0 { xi, _ := x.(*Interface) yi, _ := y.(*Interface) // If we have two interfaces, check the type terms for equivalence, @@ -567,7 +567,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { } case *Interface: - assert(!enableInterfaceInference) // handled before this switch + assert(!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/issue60562.go b/src/internal/types/testdata/fixedbugs/issue60562.go new file mode 100644 index 0000000000..b95fd9fa7f --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue60562.go @@ -0,0 +1,62 @@ +// 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 S[T any] struct{} + +func (S[T]) m(T) {} + +func f0[T any](chan S[T]) {} + +func _() { + var x chan interface{ m(int) } + f0(x /* ERROR "type chan interface{m(int)} of x does not match chan S[T] (cannot infer T)" */) +} + +// variants of the theme + +func f1[T any]([]S[T]) {} + +func _() { + var x []interface{ m(int) } + f1(x /* ERROR "type []interface{m(int)} of x does not match []S[T] (cannot infer T)" */) +} + +type I[T any] interface { + m(T) +} + +func f2[T any](func(I[T])) {} + +func _() { + var x func(interface{ m(int) }) + f2(x /* ERROR "type func(interface{m(int)}) of x does not match func(I[T]) (cannot infer T)" */) +} + +func f3[T any](func(I[T])) {} + +func _() { + var x func(I[int]) + f3(x) // but this is correct: I[T] and I[int] can be made identical with T == int +} + +func f4[T any]([10]I[T]) {} + +func _() { + var x [10]interface{ I[int] } + f4(x /* ERROR "type [10]interface{I[int]} of x does not match [10]I[T] (cannot infer T)" */) +} + +func f5[T any](I[T]) {} + +func _() { + var x interface { + m(int) + n() + } + // TODO(gri) this should not produce an error (go.dev/issues/60564) + f5(x /* ERROR "type interface{m(int); n()} of x does not match inferred type I[int] for I[T]" */) + f5[int](x) // ok +}