]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: control type inference in Checker.funcInst via infer argument
authorRobert Griesemer <gri@golang.org>
Tue, 9 May 2023 22:40:36 +0000 (15:40 -0700)
committerGopher Robot <gobot@golang.org>
Wed, 10 May 2023 15:42:07 +0000 (15:42 +0000)
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 <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/call.go
src/cmd/compile/internal/types2/expr.go
src/go/types/call.go
src/go/types/expr.go

index 23738e2aac9ddcb163d442766ddc8a3df67767f0..54f6c7ee48f96e131b5f5159fc78dae934666ecb 100644 (file)
@@ -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 {
index 0f473293bc755c4594676a6187c22d4f5b1b7862..e69f2e4c101a5842b5c8e762216923f3a5ddc6ca 100644 (file)
@@ -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
index f2ff4cf857b029fcaca376656012fa855aa7702f..5877a345df0b218fad245dd9997346628f2dd730 100644 (file)
@@ -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 {
index b0e1422b0161ac3776b7156ed8992b97180b75f7..898c5627857659b3fa9b5d2b5d774d45a5ae8291 100644 (file)
@@ -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