From 1e235cd454b58f5ae26cac2a41e8ec131312ac6b Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Tue, 27 Apr 2021 22:52:56 -0400 Subject: [PATCH] go/types: use combined type and ordinary args for type inference This is a port of CL 308372 to go/types. The only meaningful change was to add TODOs to improve the positioning error messages. Change-Id: I8314615d0851a59c2b5fd30eb897d581652eacc3 Reviewed-on: https://go-review.googlesource.com/c/go/+/314435 Trust: Robert Findley Trust: Robert Griesemer Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- src/go/types/builtins.go | 2 +- src/go/types/call.go | 37 ++++++++++++++++++++++++--- src/go/types/fixedbugs/issue39754.go2 | 6 ++++- src/go/types/fixedbugs/issue44799.go2 | 20 +++++++++++++++ src/go/types/testdata/issues.go2 | 5 ++-- 5 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 src/go/types/fixedbugs/issue44799.go2 diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 9c5a0b5842..739051cc61 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -130,7 +130,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b arg(&x, i) xlist = append(xlist, &x) } - check.arguments(call, sig, xlist) // discard result (we know the result type) + check.arguments(call, sig, nil, xlist) // discard result (we know the result type) // ok to continue even if check.arguments reported errors x.mode = value diff --git a/src/go/types/call.go b/src/go/types/call.go index e23bdb830d..631ea426c6 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -72,9 +72,14 @@ func (check *Checker) funcInst(x *operand, inst *ast.IndexExpr) { } func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind { + var inst *ast.IndexExpr if iexpr, _ := call.Fun.(*ast.IndexExpr); iexpr != nil { if check.indexExpr(x, iexpr) { - check.funcInst(x, iexpr) + // Delay function instantiation to argument checking, + // where we combine type and value arguments for type + // inference. + assert(x.mode == value) + inst = iexpr } x.expr = iexpr check.record(x) @@ -142,9 +147,33 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind { return statement } + // evaluate type arguments, if any + var targs []Type + if inst != nil { + xlist := typeparams.UnpackExpr(inst.Index) + targs = check.typeList(xlist) + if targs == nil { + check.use(call.Args...) + x.mode = invalid + x.expr = call + return statement + } + assert(len(targs) == len(xlist)) + + // check number of type arguments (got) vs number of type parameters (want) + got, want := len(targs), len(sig.tparams) + if got > want { + check.errorf(xlist[want], _Todo, "got %d type arguments but want %d", got, want) + check.use(call.Args...) + x.mode = invalid + x.expr = call + return statement + } + } + // evaluate arguments args, _ := check.exprList(call.Args, false) - sig = check.arguments(call, sig, args) + sig = check.arguments(call, sig, targs, args) // determine result switch sig.results.Len() { @@ -217,7 +246,7 @@ func (check *Checker) exprList(elist []ast.Expr, allowCommaOk bool) (xlist []*op return } -func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, args []*operand) (rsig *Signature) { +func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type, args []*operand) (rsig *Signature) { rsig = sig // TODO(gri) try to eliminate this extra verification loop @@ -299,7 +328,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, args []*oper if len(sig.tparams) > 0 { // TODO(gri) provide position information for targs so we can feed // it to the instantiate call for better error reporting - targs := check.infer(call, sig.tparams, nil, sigParams, args, true) + targs := check.infer(call, sig.tparams, targs, sigParams, args, true) if targs == nil { return // error already reported } diff --git a/src/go/types/fixedbugs/issue39754.go2 b/src/go/types/fixedbugs/issue39754.go2 index 2ed84dc8ab..4b4420d997 100644 --- a/src/go/types/fixedbugs/issue39754.go2 +++ b/src/go/types/fixedbugs/issue39754.go2 @@ -16,5 +16,9 @@ func f[V interface{}, A, B Box[V]]() {} func _() { f[int, Optional[int], Optional[int]]() - // f[int, Optional[int], Optional /* ERROR does not satisfy Box */ [string]]() + _ = f[int, Optional[int], Optional /* ERROR does not satisfy Box */ [string]] + // TODO(gri) Provide better position information here. + // See TODO in call.go, Checker.arguments. + // TODO(rFindley) Reconcile this error position with types2. + f /* ERROR does not satisfy Box */ [int, Optional[int], Optional[string]]() } diff --git a/src/go/types/fixedbugs/issue44799.go2 b/src/go/types/fixedbugs/issue44799.go2 new file mode 100644 index 0000000000..33f2c9a25c --- /dev/null +++ b/src/go/types/fixedbugs/issue44799.go2 @@ -0,0 +1,20 @@ +// Copyright 2021 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 main + +func Map[F, T any](s []F, f func(F) T) []T { return nil } + +func Reduce[Elem1, Elem2 any](s []Elem1, initializer Elem2, f func(Elem2, Elem1) Elem2) Elem2 { var x Elem2; return x } + +func main() { + var s []int + var f1 func(int) float64 + var f2 func(float64, int) float64 + _ = Map[int](s, f1) + _ = Map(s, f1) + _ = Reduce[int](s, 0, f2) + _ = Reduce(s, 0, f2) +} + diff --git a/src/go/types/testdata/issues.go2 b/src/go/types/testdata/issues.go2 index 2d4bb32c4b..8994164eac 100644 --- a/src/go/types/testdata/issues.go2 +++ b/src/go/types/testdata/issues.go2 @@ -26,7 +26,7 @@ func _() { // If we have a receiver of pointer type (below: *T) we must ignore // the pointer in the implementation of the method lookup because -// the type bound of T is an interface an pointer to interface types +// the type bound of T is an interface and pointer to interface types // have no methods and then the lookup would fail. type C[T any] interface { m() @@ -55,7 +55,8 @@ func (T) m1() func (*T) m2() func _() { - f2[T /* ERROR wrong method signature */]() + // TODO(rFindley) this error should be positioned on the 'T'. + f2 /* ERROR wrong method signature */ [T]() f2[*T]() } -- 2.50.0