Skip to content

Commit

Permalink
go/types, types2: control type inference in Checker.funcInst via infe…
Browse files Browse the repository at this point in the history
…r argument

If the infer argument is true, funcInst behaves as before.
If infer is false and there are not enough type arguments,
rather then inferring the missing arguments and instantiating
the function, funcInst returns the found type arguments.

This permits the use of funcInst (and all the checks it does)
to collect the type arguments for partially instantiated
generic functions used as arguments to other functions.

For #59338.

Change-Id: I049034dfde52bd7ff4ae72964ff1708e154e5042
Reviewed-on: https://go-review.googlesource.com/c/go/+/494118
Reviewed-by: Robert Griesemer <[email protected]>
Run-TryBot: Robert Griesemer <[email protected]>
Auto-Submit: Robert Griesemer <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
Reviewed-by: Robert Findley <[email protected]>
  • Loading branch information
griesemer authored and gopherbot committed May 10, 2023
1 parent 93d9035 commit f30cd52
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 24 deletions.
38 changes: 28 additions & 10 deletions src/cmd/compile/internal/types2/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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))
}
Expand All @@ -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.
Expand Down Expand Up @@ -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)
}
Expand All @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/cmd/compile/internal/types2/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down Expand Up @@ -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
Expand Down
38 changes: 28 additions & 10 deletions src/go/types/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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))
}
Expand All @@ -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.
Expand Down Expand Up @@ -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)
}
Expand All @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions src/go/types/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit f30cd52

Please sign in to comment.