diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index 23738e2aac..54f6c7ee48 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -14,13 +14,26 @@ import ( "unicode" ) -// funcInst type-checks a function instantiation and returns the result in x. -// The incoming x must be an uninstantiated generic function. If inst != nil, -// it provides (some or all of) the type arguments (inst.Index) for the -// instantiation. If the target type tsig != nil, the signature's parameter -// types are used to infer additional missing type arguments of x, if any. -// At least one of tsig or inst must be provided. -func (check *Checker) funcInst(tsig *Signature, pos syntax.Pos, x *operand, inst *syntax.IndexExpr) { +// funcInst type-checks a function instantiation. +// The incoming x must be a generic function. +// If inst != nil, it provides some or all of the type arguments (inst.Index). +// If target type tsig != nil, the signature may be used to infer missing type +// arguments of x, if any. At least one of tsig or inst must be provided. +// +// There are two modes of operation: +// +// 1. If infer == true, funcInst infers missing type arguments as needed and +// instantiates the function x. The returned results are nil. +// +// 2. If infer == false and inst provides all type arguments, funcInst +// instantiates the function x. The returned results are nil. +// If inst doesn't provide enough type arguments, funcInst returns the +// available arguments and the corresponding expression list; x remains +// unchanged. +// +// If an error (other than a version error) occurs in any case, it is reported +// and x.mode is set to invalid. +func (check *Checker) funcInst(tsig *Signature, pos syntax.Pos, x *operand, inst *syntax.IndexExpr, infer bool) ([]Type, []syntax.Expr) { assert(tsig != nil || inst != nil) var instErrPos poser @@ -40,7 +53,7 @@ func (check *Checker) funcInst(tsig *Signature, pos syntax.Pos, x *operand, inst if targs == nil { x.mode = invalid x.expr = inst - return + return nil, nil } assert(len(targs) == len(xlist)) } @@ -55,10 +68,14 @@ func (check *Checker) funcInst(tsig *Signature, pos syntax.Pos, x *operand, inst check.errorf(xlist[got-1], WrongTypeArgCount, "got %d type arguments but want %d", got, want) x.mode = invalid x.expr = inst - return + return nil, nil } if got < want { + if !infer { + return targs, xlist + } + // If the uninstantiated or partially instantiated function x is used in an // assignment (tsig != nil), use the respective function parameter and result // types to infer additional type arguments. @@ -104,7 +121,7 @@ func (check *Checker) funcInst(tsig *Signature, pos syntax.Pos, x *operand, inst // error was already reported x.mode = invalid x.expr = inst - return + return nil, nil } got = len(targs) } @@ -121,6 +138,7 @@ func (check *Checker) funcInst(tsig *Signature, pos syntax.Pos, x *operand, inst x.expr = inst } check.recordInstance(x.expr, targs, sig) + return nil, nil } func paramName(name string, i int, kind string) string { diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index 0f473293bc..e69f2e4c10 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -995,7 +995,7 @@ func (check *Checker) nonGeneric(T Type, x *operand) { if t.tparams != nil { if enableReverseTypeInference && T != nil { if tsig, _ := under(T).(*Signature); tsig != nil { - check.funcInst(tsig, x.Pos(), x, nil) + check.funcInst(tsig, x.Pos(), x, nil, true) return } } @@ -1322,7 +1322,7 @@ func (check *Checker) exprInternal(T Type, x *operand, e syntax.Expr, hint Type) if enableReverseTypeInference && T != nil { tsig, _ = under(T).(*Signature) } - check.funcInst(tsig, e.Pos(), x, e) + check.funcInst(tsig, e.Pos(), x, e, true) } if x.mode == invalid { goto Error diff --git a/src/go/types/call.go b/src/go/types/call.go index f2ff4cf857..5877a345df 100644 --- a/src/go/types/call.go +++ b/src/go/types/call.go @@ -16,13 +16,26 @@ import ( "unicode" ) -// funcInst type-checks a function instantiation and returns the result in x. -// The incoming x must be an uninstantiated generic function. If ix != nil, -// it provides (some or all of) the type arguments (ix.Indices) for the -// instantiation. If the target type tsig != nil, the signature's parameter -// types are used to infer additional missing type arguments of x, if any. -// At least one of tsig or ix must be provided. -func (check *Checker) funcInst(tsig *Signature, pos token.Pos, x *operand, ix *typeparams.IndexExpr) { +// funcInst type-checks a function instantiation. +// The incoming x must be a generic function. +// If ix != nil, it provides some or all of the type arguments (ix.Indices). +// If target type tsig != nil, the signature may be used to infer missing type +// arguments of x, if any. At least one of tsig or inst must be provided. +// +// There are two modes of operation: +// +// 1. If infer == true, funcInst infers missing type arguments as needed and +// instantiates the function x. The returned results are nil. +// +// 2. If infer == false and inst provides all type arguments, funcInst +// instantiates the function x. The returned results are nil. +// If inst doesn't provide enough type arguments, funcInst returns the +// available arguments and the corresponding expression list; x remains +// unchanged. +// +// If an error (other than a version error) occurs in any case, it is reported +// and x.mode is set to invalid. +func (check *Checker) funcInst(tsig *Signature, pos token.Pos, x *operand, ix *typeparams.IndexExpr, infer bool) ([]Type, []ast.Expr) { assert(tsig != nil || ix != nil) var instErrPos positioner @@ -42,7 +55,7 @@ func (check *Checker) funcInst(tsig *Signature, pos token.Pos, x *operand, ix *t if targs == nil { x.mode = invalid x.expr = ix - return + return nil, nil } assert(len(targs) == len(xlist)) } @@ -57,10 +70,14 @@ func (check *Checker) funcInst(tsig *Signature, pos token.Pos, x *operand, ix *t check.errorf(ix.Indices[got-1], WrongTypeArgCount, "got %d type arguments but want %d", got, want) x.mode = invalid x.expr = ix.Orig - return + return nil, nil } if got < want { + if !infer { + return targs, xlist + } + // If the uninstantiated or partially instantiated function x is used in an // assignment (tsig != nil), use the respective function parameter and result // types to infer additional type arguments. @@ -108,7 +125,7 @@ func (check *Checker) funcInst(tsig *Signature, pos token.Pos, x *operand, ix *t // error was already reported x.mode = invalid x.expr = ix // TODO(gri) is this correct? - return + return nil, nil } got = len(targs) } @@ -125,6 +142,7 @@ func (check *Checker) funcInst(tsig *Signature, pos token.Pos, x *operand, ix *t x.expr = ix.Orig } check.recordInstance(x.expr, targs, sig) + return nil, nil } func paramName(name string, i int, kind string) string { diff --git a/src/go/types/expr.go b/src/go/types/expr.go index b0e1422b01..898c562785 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -980,7 +980,7 @@ func (check *Checker) nonGeneric(T Type, x *operand) { if t.tparams != nil { if enableReverseTypeInference && T != nil { if tsig, _ := under(T).(*Signature); tsig != nil { - check.funcInst(tsig, x.Pos(), x, nil) + check.funcInst(tsig, x.Pos(), x, nil, true) return } } @@ -1305,7 +1305,7 @@ func (check *Checker) exprInternal(T Type, x *operand, e ast.Expr, hint Type) ex if enableReverseTypeInference && T != nil { tsig, _ = under(T).(*Signature) } - check.funcInst(tsig, e.Pos(), x, ix) + check.funcInst(tsig, e.Pos(), x, ix, true) } if x.mode == invalid { goto Error