mirror of https://github.com/golang/go.git
go/types: make type inference work for self-recursive function calls
Cases such as
func f(type T)(x T) {
f(x)
}
can now be type-checked. For more examples see examples/functions.go2
in the go/types directory.
Change-Id: Id661c84f086cc8ee45ec372ac4af543e68bebe8a
This commit is contained in:
parent
67e62d261e
commit
399d59ee46
|
|
@ -71,4 +71,43 @@ func variadic(type A, B)(A, B, ...B) int { panic("unimplemented") }
|
|||
// var _ = variadic(1) // ERROR not enough arguments
|
||||
var _ = variadic(1, 2.3)
|
||||
var _ = variadic(1, 2.3, 3.4, 4.5)
|
||||
var _ = variadic(int, float64)(1, 2.3, 3.4, 4)
|
||||
var _ = variadic(int, float64)(1, 2.3, 3.4, 4)
|
||||
|
||||
// Type inference also works in recursive function calls where
|
||||
// the inferred type is the type parameter of the caller.
|
||||
func f1(type T)(x T) {
|
||||
f1(x)
|
||||
}
|
||||
|
||||
func f2a(type T)(x, y T) {
|
||||
f2a(x, y)
|
||||
}
|
||||
|
||||
func f2b(type T)(x, y T) {
|
||||
f2b(y, x)
|
||||
}
|
||||
|
||||
func g2a(type P, Q)(x P, y Q) {
|
||||
g2a(x, y)
|
||||
}
|
||||
|
||||
func g2b(type P, Q)(x P, y Q) {
|
||||
g2b(y, x)
|
||||
}
|
||||
|
||||
// Here's an example of a recursive function call with variadic
|
||||
// arguments and type inference inferring the type parameter of
|
||||
// the caller (i.e., itself).
|
||||
func max(type T interface{ type int })(x ...T) T {
|
||||
var x0 T
|
||||
if len(x) > 0 {
|
||||
x0 = x[0]
|
||||
}
|
||||
if len(x) > 1 {
|
||||
x1 := max(x[1:]...)
|
||||
if x1 > x0 {
|
||||
return x1
|
||||
}
|
||||
}
|
||||
return x0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,7 +129,15 @@ func (p *ifacePair) identical(q *ifacePair) bool {
|
|||
|
||||
// If a non-nil tparams is provided, type inference is done for type parameters in x.
|
||||
func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair, tparams []Type) bool {
|
||||
if x == y {
|
||||
// If we want type inference, do not shortcut for equal types. Instead
|
||||
// keep comparing them element-wise so we can infer the matching (and
|
||||
// equal type parameter types). A simple test case where this matters
|
||||
// is: func f(type T)(x T) { f(x) } .
|
||||
// (If we know that the types are equal, we could optimize this case by
|
||||
// simply extracting the type parameters used and then populate tparams
|
||||
// accordingly. Not clear it's worthwhile the parallel, if slightly more
|
||||
// efficient code structure.)
|
||||
if tparams == nil && x == y {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -324,7 +332,15 @@ func (check *Checker) identical0(x, y Type, cmpTags bool, p *ifacePair, tparams
|
|||
if tparams == nil {
|
||||
return false // x and y being equal is caught in the very beginning of this function
|
||||
}
|
||||
// tparams != nil
|
||||
if x := tparams[x.index]; x != nil {
|
||||
// If we have inferred a type x and it matches y, we're
|
||||
// done. check.identical0 won't do this check if we run
|
||||
// in inference mode (tparams != nil), so do it here to
|
||||
// avoid endless recursion.
|
||||
if x == y {
|
||||
return true
|
||||
}
|
||||
return check.identical0(x, y, cmpTags, p, tparams)
|
||||
}
|
||||
tparams[x.index] = y // infer type from y
|
||||
|
|
|
|||
|
|
@ -4,31 +4,45 @@
|
|||
|
||||
package main
|
||||
|
||||
contract C(T) {
|
||||
T m() T
|
||||
func f(type T)(x T) {
|
||||
f(x)
|
||||
}
|
||||
|
||||
// contract C(T₁) {T₁ C₀(type T₁ any) = interface{m() T₁}}
|
||||
|
||||
contract W(T) {
|
||||
C(T)
|
||||
func g(type T)(x, y T) {
|
||||
g(x, y)
|
||||
}
|
||||
|
||||
// contract W(T₂) {T₂ W₀(type T₂ main.C₀<T₂>) = interface{interface{m() T₂}}}
|
||||
|
||||
func _(type T W)(x T) {
|
||||
var _ T = x.m()
|
||||
func f2(type T1, T2)(x1 T1, x2 T2) {
|
||||
f2(x1, x2)
|
||||
}
|
||||
|
||||
contract compareTwo(A, B) {
|
||||
comparable(A)
|
||||
comparable(B)
|
||||
func f2p(type T1, T2)(x1 T1, x2 T2) {
|
||||
f2p(x2, x1)
|
||||
}
|
||||
|
||||
func _(type T1, T2 compareTwo)(x1, y1 T1) bool {
|
||||
return x1 == y1
|
||||
}
|
||||
/*
|
||||
func f(func(int))
|
||||
func g(type T)(T)
|
||||
|
||||
func _(type T comparable)(x, y T) bool {
|
||||
return x == y || x != y
|
||||
func _() {
|
||||
f(g)
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
func f(type T)(T, func(type T)(T))
|
||||
func g(type T)(T)
|
||||
func _() {
|
||||
var x int
|
||||
f(x, g)
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
func f(type T)(T, func(T))
|
||||
func g(type T)(T)
|
||||
func _() {
|
||||
var x int
|
||||
f(x, g)
|
||||
}
|
||||
*/
|
||||
Loading…
Reference in New Issue