Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[release-branch.go1.21] go/types, types2: remove order dependency in …
…inference involving channels In inexact unification, when a named type matches against an inferred unnamed type, we change the previously inferred type to the named type. This preserves the type name and assignability. We have to do the same thing when encountering a directional channel: a bidirectional channel can always be assigned to a directional channel but not the other way around. Thus, if we see a directional channel, we must choose the directional channel. This CL extends the previously existing logic for named types to directional channels and also makes the code conditional on inexact unification. The latter is an optimization - if unification is exact, type differences don't exist and updating an already inferred type has no effect. Fixes #62205. Change-Id: I807e3b9f9ab363f9ed848bdb18b2577b1d680ea7 Reviewed-on: https://go-review.googlesource.com/c/go/+/524256 Run-TryBot: Robert Griesemer <gri@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Robert Griesemer <gri@google.com> Reviewed-by: Robert Findley <rfindley@google.com>
- Loading branch information
Showing
3 changed files
with
194 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// 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 | ||
|
||
func f[T any](...T) T { var x T; return x } | ||
|
||
// Test case 1 | ||
|
||
func _() { | ||
var a chan string | ||
var b <-chan string | ||
f(a, b) | ||
f(b, a) | ||
} | ||
|
||
// Test case 2 | ||
|
||
type F[T any] func(T) bool | ||
|
||
func g[T any](T) F[<-chan T] { return nil } | ||
|
||
func f1[T any](T, F[T]) {} | ||
func f2[T any](F[T], T) {} | ||
|
||
func _() { | ||
var ch chan string | ||
f1(ch, g("")) | ||
f2(g(""), ch) | ||
} | ||
|
||
// Test case 3: named and directional types combined | ||
|
||
func _() { | ||
type namedA chan int | ||
type namedB chan<- int | ||
|
||
var a chan int | ||
var A namedA | ||
var b chan<- int | ||
var B namedB | ||
|
||
// Defined types win over channel types irrespective of channel direction. | ||
f(A, b /* ERROR "cannot use b (variable of type chan<- int) as namedA value in argument to f" */) | ||
f(b /* ERROR "cannot use b (variable of type chan<- int) as namedA value in argument to f" */, A) | ||
|
||
f(a, b /* ERROR "cannot use b (variable of type chan<- int) as namedA value in argument to f" */, A) | ||
f(a, A, b /* ERROR "cannot use b (variable of type chan<- int) as namedA value in argument to f" */) | ||
f(b /* ERROR "cannot use b (variable of type chan<- int) as namedA value in argument to f" */, A, a) | ||
f(b /* ERROR "cannot use b (variable of type chan<- int) as namedA value in argument to f" */, a, A) | ||
f(A, a, b /* ERROR "cannot use b (variable of type chan<- int) as namedA value in argument to f" */) | ||
f(A, b /* ERROR "cannot use b (variable of type chan<- int) as namedA value in argument to f" */, a) | ||
|
||
// Unnamed directed channels win over bidirectional channels. | ||
b = f(a, b) | ||
b = f(b, a) | ||
|
||
// Defined directed channels win over defined bidirectional channels. | ||
A = f(A, a) | ||
A = f(a, A) | ||
B = f(B, b) | ||
B = f(b, B) | ||
|
||
f(a, b, B) | ||
f(a, B, b) | ||
f(b, B, a) | ||
f(b, a, B) | ||
f(B, a, b) | ||
f(B, b, a) | ||
|
||
// Differently named channel types conflict irrespective of channel direction. | ||
f(A, B /* ERROR "type namedB of B does not match inferred type namedA for T" */) | ||
f(B, A /* ERROR "type namedA of A does not match inferred type namedB for T" */) | ||
|
||
// Ensure that all combinations of directional and | ||
// bidirectional channels with a named directional | ||
// channel lead to the correct (named) directional | ||
// channel. | ||
B = f(a, b) | ||
B = f(a, B) | ||
B = f(b, a) | ||
B = f(B, a) | ||
|
||
B = f(a, b, B) | ||
B = f(a, B, b) | ||
B = f(b, B, a) | ||
B = f(b, a, B) | ||
B = f(B, a, b) | ||
B = f(B, b, a) | ||
|
||
// verify type error | ||
A = f /* ERROR "cannot use f(B, b, a) (value of type namedB) as namedA value in assignment" */ (B, b, a) | ||
} | ||
|
||
// Test case 4: some more combinations | ||
|
||
func _() { | ||
type A chan int | ||
type B chan int | ||
type C = chan int | ||
type D = chan<- int | ||
|
||
var a A | ||
var b B | ||
var c C | ||
var d D | ||
|
||
f(a, b /* ERROR "type B of b does not match inferred type A for T" */, c) | ||
f(c, a, b /* ERROR "type B of b does not match inferred type A for T" */) | ||
f(a, b /* ERROR "type B of b does not match inferred type A for T" */, d) | ||
f(d, a, b /* ERROR "type B of b does not match inferred type A for T" */) | ||
} | ||
|
||
// Simplified test case from issue | ||
|
||
type Matcher[T any] func(T) bool | ||
|
||
func Produces[T any](T) Matcher[<-chan T] { return nil } | ||
|
||
func Assert1[T any](Matcher[T], T) {} | ||
func Assert2[T any](T, Matcher[T]) {} | ||
|
||
func _() { | ||
var ch chan string | ||
Assert1(Produces(""), ch) | ||
Assert2(ch, Produces("")) | ||
} |