]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types, types2: better error message for cases of reverse type inference
authorRobert Griesemer <gri@golang.org>
Mon, 11 Dec 2023 21:28:25 +0000 (13:28 -0800)
committerGopher Robot <gobot@golang.org>
Tue, 12 Dec 2023 18:44:28 +0000 (18:44 +0000)
Introduce a new type "target" to pass around target types together
with a suitable description (typically a variable name) for a better
error message.

As a side effect, using a specific type (target), rather than just Type
avoids accidental confusion with other types.

Use the target type description for a better error message in some
cases.

The error message can be further improved by flipping the order of
the sentence (for another CL to keep this one small and simple).

Also, and unrelated to this fix, remove the first argument to errorf
in infer.go: the argument is always "type" (there's only one call).

For #60747.

Change-Id: I2118d0fe9e2b4aac959371941064e0e9ca7b3b6e
Reviewed-on: https://go-review.googlesource.com/c/go/+/548995
Auto-Submit: Robert Griesemer <gri@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

13 files changed:
src/cmd/compile/internal/types2/assignments.go
src/cmd/compile/internal/types2/call.go
src/cmd/compile/internal/types2/decl.go
src/cmd/compile/internal/types2/expr.go
src/cmd/compile/internal/types2/infer.go
src/go/types/assignments.go
src/go/types/call.go
src/go/types/decl.go
src/go/types/expr.go
src/go/types/infer.go
src/internal/types/testdata/examples/inference2.go
src/internal/types/testdata/fixedbugs/issue60688.go
src/internal/types/testdata/fixedbugs/issue60747.go [new file with mode: 0644]

index 079802b0b056682fc6f2aa8a282aa156888dfaaa..338a114ff936c566cd25f88552810628390b5dc4 100644 (file)
@@ -244,8 +244,15 @@ func (check *Checker) assignVar(lhs, rhs syntax.Expr, x *operand) {
        }
 
        if x == nil {
+               var target *target
+               // avoid calling syntax.String if not needed
+               if T != nil {
+                       if _, ok := under(T).(*Signature); ok {
+                               target = newTarget(T, syntax.String(lhs))
+                       }
+               }
                x = new(operand)
-               check.expr(T, x, rhs)
+               check.expr(target, x, rhs)
        }
 
        context := "assignment"
@@ -369,7 +376,11 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []syntax.Expr, returnStmt sy
        if l == r && !isCall {
                var x operand
                for i, lhs := range lhs {
-                       check.expr(lhs.typ, &x, orig_rhs[i])
+                       desc := lhs.name
+                       if returnStmt != nil && desc == "" {
+                               desc = "result variable"
+                       }
+                       check.expr(newTarget(lhs.typ, desc), &x, orig_rhs[i])
                        check.initVar(lhs, &x, context)
                }
                return
index 439f51526577fc83c7c73f0e2f982b8f8cc7efb2..7d9b80f6611cef9d85ca0d6f96c32561c7a33607 100644 (file)
@@ -16,8 +16,8 @@ import (
 // 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.
+// If target != nil, it may be used to infer missing type arguments of x, if any.
+// At least one of T or inst must be provided.
 //
 // There are two modes of operation:
 //
@@ -32,8 +32,8 @@ import (
 //
 // 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)
+func (check *Checker) funcInst(T *target, pos syntax.Pos, x *operand, inst *syntax.IndexExpr, infer bool) ([]Type, []syntax.Expr) {
+       assert(T != nil || inst != nil)
 
        var instErrPos poser
        if inst != nil {
@@ -87,7 +87,7 @@ func (check *Checker) funcInst(tsig *Signature, pos syntax.Pos, x *operand, inst
                //
                var args []*operand
                var params []*Var
-               if tsig != nil && sig.tparams != nil {
+               if T != nil && sig.tparams != nil {
                        if !versionErr && !check.allowVersion(check.pkg, instErrPos, go1_21) {
                                if inst != nil {
                                        check.versionErrorf(instErrPos, go1_21, "partially instantiated function in assignment")
@@ -100,8 +100,8 @@ func (check *Checker) funcInst(tsig *Signature, pos syntax.Pos, x *operand, inst
                        // The type of the argument operand is tsig, which is the type of the LHS in an assignment
                        // or the result type in a return statement. Create a pseudo-expression for that operand
                        // that makes sense when reported in error messages from infer, below.
-                       expr := syntax.NewName(x.Pos(), "variable in assignment")
-                       args = []*operand{{mode: value, expr: expr, typ: tsig}}
+                       expr := syntax.NewName(x.Pos(), T.desc)
+                       args = []*operand{{mode: value, expr: expr, typ: T.sig}}
                }
 
                // Rename type parameters to avoid problems with recursive instantiations.
index 3ffa9431e4e1411afa97b10e618ccc510a710e84..f3e3418f4fd5f9ba7fb0268b49a0836e17789787 100644 (file)
@@ -449,7 +449,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
        if lhs == nil || len(lhs) == 1 {
                assert(lhs == nil || lhs[0] == obj)
                var x operand
-               check.expr(obj.typ, &x, init)
+               check.expr(newTarget(obj.typ, obj.name), &x, init)
                check.initVar(obj, &x, "variable declaration")
                return
        }
index e1c2c8ff2a6db5fc36384fde3fa73223be6b9d12..124d9701d60e9f59dbbe9e3c15673421d61b6721 100644 (file)
@@ -956,18 +956,32 @@ const (
        statement
 )
 
-// TODO(gri) In rawExpr below, consider using T instead of hint and
-//           some sort of "operation mode" instead of allowGeneric.
-//           May be clearer and less error-prone.
+// target represent the (signature) type and description of the LHS
+// variable of an assignment, or of a function result variable.
+type target struct {
+       sig  *Signature
+       desc string
+}
+
+// newTarget creates a new target for the given type and description.
+// The result is nil if typ is not a signature.
+func newTarget(typ Type, desc string) *target {
+       if typ != nil {
+               if sig, _ := under(typ).(*Signature); sig != nil {
+                       return &target{sig, desc}
+               }
+       }
+       return nil
+}
 
 // rawExpr typechecks expression e and initializes x with the expression
 // value or type. If an error occurred, x.mode is set to invalid.
-// If a non-nil target type T is given and e is a generic function
-// or function call, T is used to infer the type arguments for e.
+// If a non-nil target T is given and e is a generic function,
+// T is used to infer the type arguments for e.
 // If hint != nil, it is the type of a composite literal element.
 // If allowGeneric is set, the operand type may be an uninstantiated
 // parameterized type or function value.
-func (check *Checker) rawExpr(T Type, x *operand, e syntax.Expr, hint Type, allowGeneric bool) exprKind {
+func (check *Checker) rawExpr(T *target, x *operand, e syntax.Expr, hint Type, allowGeneric bool) exprKind {
        if check.conf.Trace {
                check.trace(e.Pos(), "-- expr %s", e)
                check.indent++
@@ -989,9 +1003,9 @@ func (check *Checker) rawExpr(T Type, x *operand, e syntax.Expr, hint Type, allo
 }
 
 // If x is a generic type, or a generic function whose type arguments cannot be inferred
-// from a non-nil target type T, nonGeneric reports an error and invalidates x.mode and x.typ.
+// from a non-nil target T, nonGeneric reports an error and invalidates x.mode and x.typ.
 // Otherwise it leaves x alone.
-func (check *Checker) nonGeneric(T Type, x *operand) {
+func (check *Checker) nonGeneric(T *target, x *operand) {
        if x.mode == invalid || x.mode == novalue {
                return
        }
@@ -1004,10 +1018,8 @@ func (check *Checker) nonGeneric(T Type, x *operand) {
        case *Signature:
                if t.tparams != nil {
                        if enableReverseTypeInference && T != nil {
-                               if tsig, _ := under(T).(*Signature); tsig != nil {
-                                       check.funcInst(tsig, x.Pos(), x, nil, true)
-                                       return
-                               }
+                               check.funcInst(T, x.Pos(), x, nil, true)
+                               return
                        }
                        what = "function"
                }
@@ -1022,7 +1034,7 @@ func (check *Checker) nonGeneric(T Type, x *operand) {
 // exprInternal contains the core of type checking of expressions.
 // Must only be called by rawExpr.
 // (See rawExpr for an explanation of the parameters.)
-func (check *Checker) exprInternal(T Type, x *operand, e syntax.Expr, hint Type) exprKind {
+func (check *Checker) exprInternal(T *target, x *operand, e syntax.Expr, hint Type) exprKind {
        // make sure x has a valid state in case of bailout
        // (was go.dev/issue/5770)
        x.mode = invalid
@@ -1332,11 +1344,10 @@ func (check *Checker) exprInternal(T Type, x *operand, e syntax.Expr, hint Type)
 
        case *syntax.IndexExpr:
                if check.indexExpr(x, e) {
-                       var tsig *Signature
-                       if enableReverseTypeInference && T != nil {
-                               tsig, _ = under(T).(*Signature)
+                       if !enableReverseTypeInference {
+                               T = nil
                        }
-                       check.funcInst(tsig, e.Pos(), x, e, true)
+                       check.funcInst(T, e.Pos(), x, e, true)
                }
                if x.mode == invalid {
                        goto Error
@@ -1547,11 +1558,11 @@ func (check *Checker) typeAssertion(e syntax.Expr, x *operand, T Type, typeSwitc
 }
 
 // expr typechecks expression e and initializes x with the expression value.
-// If a non-nil target type T is given and e is a generic function
-// or function call, T is used to infer the type arguments for e.
+// If a non-nil target T is given and e is a generic function or
+// a function call, T is used to infer the type arguments for e.
 // The result must be a single value.
 // If an error occurred, x.mode is set to invalid.
-func (check *Checker) expr(T Type, x *operand, e syntax.Expr) {
+func (check *Checker) expr(T *target, x *operand, e syntax.Expr) {
        check.rawExpr(T, x, e, nil, false)
        check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
        check.singleValue(x)
index 3a7c74dc82c30d0533504e8ee2b127430e407d5b..94f2de7b3ce88b3524c4345f114b7d0a2ca5d765 100644 (file)
@@ -110,7 +110,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
        // Terminology: generic parameter = function parameter with a type-parameterized type
        u := newUnifier(tparams, targs, check.allowVersion(check.pkg, pos, go1_21))
 
-       errorf := func(kind string, tpar, targ Type, arg *operand) {
+       errorf := func(tpar, targ Type, arg *operand) {
                // provide a better error message if we can
                targs := u.inferred(tparams)
                if targs[0] == nil {
@@ -125,7 +125,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
                                }
                        }
                        if allFailed {
-                               check.errorf(arg, CannotInferTypeArgs, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeParamsString(tparams))
+                               check.errorf(arg, CannotInferTypeArgs, "type %s of %s does not match %s (cannot infer %s)", targ, arg.expr, tpar, typeParamsString(tparams))
                                return
                        }
                }
@@ -137,9 +137,9 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
                // InvalidTypeArg). We can't differentiate these cases, so fall back on
                // the more general CannotInferTypeArgs.
                if inferred != tpar {
-                       check.errorf(arg, CannotInferTypeArgs, "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
+                       check.errorf(arg, CannotInferTypeArgs, "type %s of %s does not match inferred type %s for %s", targ, arg.expr, inferred, tpar)
                } else {
-                       check.errorf(arg, CannotInferTypeArgs, "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
+                       check.errorf(arg, CannotInferTypeArgs, "type %s of %s does not match %s", targ, arg.expr, tpar)
                }
        }
 
@@ -168,7 +168,7 @@ func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type,
                        // Collect the indices of untyped arguments and handle them later.
                        if isTyped(arg.typ) {
                                if !u.unify(par.typ, arg.typ, assign) {
-                                       errorf("type", par.typ, arg.typ, arg)
+                                       errorf(par.typ, arg.typ, arg)
                                        return nil
                                }
                        } else if _, ok := par.typ.(*TypeParam); ok && !arg.isNil() {
index f9f0e8f20add230dca271b00bb03578326eb7dc8..3ea45699b1be487b0e94a058233458d912a8800f 100644 (file)
@@ -243,8 +243,15 @@ func (check *Checker) assignVar(lhs, rhs ast.Expr, x *operand) {
        }
 
        if x == nil {
+               var target *target
+               // avoid calling ExprString if not needed
+               if T != nil {
+                       if _, ok := under(T).(*Signature); ok {
+                               target = newTarget(T, ExprString(lhs))
+                       }
+               }
                x = new(operand)
-               check.expr(T, x, rhs)
+               check.expr(target, x, rhs)
        }
 
        context := "assignment"
@@ -368,7 +375,11 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []ast.Expr, returnStmt ast.S
        if l == r && !isCall {
                var x operand
                for i, lhs := range lhs {
-                       check.expr(lhs.typ, &x, orig_rhs[i])
+                       desc := lhs.name
+                       if returnStmt != nil && desc == "" {
+                               desc = "result variable"
+                       }
+                       check.expr(newTarget(lhs.typ, desc), &x, orig_rhs[i])
                        check.initVar(lhs, &x, context)
                }
                return
index 12f547ea386a670b6e4c33397665087d561f9508..5ac556c511afd4e3968a40ec1d409e2b36ce89e6 100644 (file)
@@ -18,8 +18,8 @@ import (
 // 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.
+// If target != nil, it may be used to infer missing type arguments of x, if any.
+// At least one of T or ix must be provided.
 //
 // There are two modes of operation:
 //
@@ -34,8 +34,8 @@ import (
 //
 // 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)
+func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *typeparams.IndexExpr, infer bool) ([]Type, []ast.Expr) {
+       assert(T != nil || ix != nil)
 
        var instErrPos positioner
        if ix != nil {
@@ -89,7 +89,7 @@ func (check *Checker) funcInst(tsig *Signature, pos token.Pos, x *operand, ix *t
                //
                var args []*operand
                var params []*Var
-               if tsig != nil && sig.tparams != nil {
+               if T != nil && sig.tparams != nil {
                        if !versionErr && !check.allowVersion(check.pkg, instErrPos, go1_21) {
                                if ix != nil {
                                        check.versionErrorf(instErrPos, go1_21, "partially instantiated function in assignment")
@@ -102,9 +102,9 @@ func (check *Checker) funcInst(tsig *Signature, pos token.Pos, x *operand, ix *t
                        // The type of the argument operand is tsig, which is the type of the LHS in an assignment
                        // or the result type in a return statement. Create a pseudo-expression for that operand
                        // that makes sense when reported in error messages from infer, below.
-                       expr := ast.NewIdent("variable in assignment")
+                       expr := ast.NewIdent(T.desc)
                        expr.NamePos = x.Pos() // correct position
-                       args = []*operand{{mode: value, expr: expr, typ: tsig}}
+                       args = []*operand{{mode: value, expr: expr, typ: T.sig}}
                }
 
                // Rename type parameters to avoid problems with recursive instantiations.
index 0795cb5fceed9283334f52c7e242714100d033e5..9f8c44ab502e1822bb6b0f44a4435b16598e8a44 100644 (file)
@@ -518,7 +518,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
        if lhs == nil || len(lhs) == 1 {
                assert(lhs == nil || lhs[0] == obj)
                var x operand
-               check.expr(obj.typ, &x, init)
+               check.expr(newTarget(obj.typ, obj.name), &x, init)
                check.initVar(obj, &x, "variable declaration")
                return
        }
index ecd0d56908ff998d20194084cb7f621ddee4e6e3..8651ddad93a8142d70ff4b4468844d466c1196ee 100644 (file)
@@ -941,18 +941,32 @@ const (
        statement
 )
 
-// TODO(gri) In rawExpr below, consider using T instead of hint and
-//           some sort of "operation mode" instead of allowGeneric.
-//           May be clearer and less error-prone.
+// target represent the (signature) type and description of the LHS
+// variable of an assignment, or of a function result variable.
+type target struct {
+       sig  *Signature
+       desc string
+}
+
+// newTarget creates a new target for the given type and description.
+// The result is nil if typ is not a signature.
+func newTarget(typ Type, desc string) *target {
+       if typ != nil {
+               if sig, _ := under(typ).(*Signature); sig != nil {
+                       return &target{sig, desc}
+               }
+       }
+       return nil
+}
 
 // rawExpr typechecks expression e and initializes x with the expression
 // value or type. If an error occurred, x.mode is set to invalid.
-// If a non-nil target type T is given and e is a generic function
-// or function call, T is used to infer the type arguments for e.
+// If a non-nil target T is given and e is a generic function,
+// T is used to infer the type arguments for e.
 // If hint != nil, it is the type of a composite literal element.
 // If allowGeneric is set, the operand type may be an uninstantiated
 // parameterized type or function value.
-func (check *Checker) rawExpr(T Type, x *operand, e ast.Expr, hint Type, allowGeneric bool) exprKind {
+func (check *Checker) rawExpr(T *target, x *operand, e ast.Expr, hint Type, allowGeneric bool) exprKind {
        if check.conf._Trace {
                check.trace(e.Pos(), "-- expr %s", e)
                check.indent++
@@ -974,9 +988,9 @@ func (check *Checker) rawExpr(T Type, x *operand, e ast.Expr, hint Type, allowGe
 }
 
 // If x is a generic type, or a generic function whose type arguments cannot be inferred
-// from a non-nil target type T, nonGeneric reports an error and invalidates x.mode and x.typ.
+// from a non-nil target T, nonGeneric reports an error and invalidates x.mode and x.typ.
 // Otherwise it leaves x alone.
-func (check *Checker) nonGeneric(T Type, x *operand) {
+func (check *Checker) nonGeneric(T *target, x *operand) {
        if x.mode == invalid || x.mode == novalue {
                return
        }
@@ -989,10 +1003,8 @@ func (check *Checker) nonGeneric(T Type, x *operand) {
        case *Signature:
                if t.tparams != nil {
                        if enableReverseTypeInference && T != nil {
-                               if tsig, _ := under(T).(*Signature); tsig != nil {
-                                       check.funcInst(tsig, x.Pos(), x, nil, true)
-                                       return
-                               }
+                               check.funcInst(T, x.Pos(), x, nil, true)
+                               return
                        }
                        what = "function"
                }
@@ -1007,7 +1019,7 @@ func (check *Checker) nonGeneric(T Type, x *operand) {
 // exprInternal contains the core of type checking of expressions.
 // Must only be called by rawExpr.
 // (See rawExpr for an explanation of the parameters.)
-func (check *Checker) exprInternal(T Type, x *operand, e ast.Expr, hint Type) exprKind {
+func (check *Checker) exprInternal(T *target, x *operand, e ast.Expr, hint Type) exprKind {
        // make sure x has a valid state in case of bailout
        // (was go.dev/issue/5770)
        x.mode = invalid
@@ -1315,11 +1327,10 @@ func (check *Checker) exprInternal(T Type, x *operand, e ast.Expr, hint Type) ex
        case *ast.IndexExpr, *ast.IndexListExpr:
                ix := typeparams.UnpackIndexExpr(e)
                if check.indexExpr(x, ix) {
-                       var tsig *Signature
-                       if enableReverseTypeInference && T != nil {
-                               tsig, _ = under(T).(*Signature)
+                       if !enableReverseTypeInference {
+                               T = nil
                        }
-                       check.funcInst(tsig, e.Pos(), x, ix, true)
+                       check.funcInst(T, e.Pos(), x, ix, true)
                }
                if x.mode == invalid {
                        goto Error
@@ -1494,11 +1505,11 @@ func (check *Checker) typeAssertion(e ast.Expr, x *operand, T Type, typeSwitch b
 }
 
 // expr typechecks expression e and initializes x with the expression value.
-// If a non-nil target type T is given and e is a generic function
-// or function call, T is used to infer the type arguments for e.
+// If a non-nil target T is given and e is a generic function or
+// a function call, T is used to infer the type arguments for e.
 // The result must be a single value.
 // If an error occurred, x.mode is set to invalid.
-func (check *Checker) expr(T Type, x *operand, e ast.Expr) {
+func (check *Checker) expr(T *target, x *operand, e ast.Expr) {
        check.rawExpr(T, x, e, nil, false)
        check.exclude(x, 1<<novalue|1<<builtin|1<<typexpr)
        check.singleValue(x)
index 244f311281a46d2be54de0280fb4ef2673415a94..ed9841f06e6c2ba66a6d2f44d7db95bcab71b7db 100644 (file)
@@ -112,7 +112,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type,
        // Terminology: generic parameter = function parameter with a type-parameterized type
        u := newUnifier(tparams, targs, check.allowVersion(check.pkg, posn, go1_21))
 
-       errorf := func(kind string, tpar, targ Type, arg *operand) {
+       errorf := func(tpar, targ Type, arg *operand) {
                // provide a better error message if we can
                targs := u.inferred(tparams)
                if targs[0] == nil {
@@ -127,7 +127,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type,
                                }
                        }
                        if allFailed {
-                               check.errorf(arg, CannotInferTypeArgs, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeParamsString(tparams))
+                               check.errorf(arg, CannotInferTypeArgs, "type %s of %s does not match %s (cannot infer %s)", targ, arg.expr, tpar, typeParamsString(tparams))
                                return
                        }
                }
@@ -139,9 +139,9 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type,
                // InvalidTypeArg). We can't differentiate these cases, so fall back on
                // the more general CannotInferTypeArgs.
                if inferred != tpar {
-                       check.errorf(arg, CannotInferTypeArgs, "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
+                       check.errorf(arg, CannotInferTypeArgs, "type %s of %s does not match inferred type %s for %s", targ, arg.expr, inferred, tpar)
                } else {
-                       check.errorf(arg, CannotInferTypeArgs, "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
+                       check.errorf(arg, CannotInferTypeArgs, "type %s of %s does not match %s", targ, arg.expr, tpar)
                }
        }
 
@@ -170,7 +170,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type,
                        // Collect the indices of untyped arguments and handle them later.
                        if isTyped(arg.typ) {
                                if !u.unify(par.typ, arg.typ, assign) {
-                                       errorf("type", par.typ, arg.typ, arg)
+                                       errorf(par.typ, arg.typ, arg)
                                        return nil
                                }
                        } else if _, ok := par.typ.(*TypeParam); ok && !arg.isNil() {
index 6097c2b5ebf5de7e62a8f0e0324a513f38a06a59..a4cfa3b41364470b364759f5bd3b409f914bd843 100644 (file)
@@ -27,9 +27,9 @@ var (
        _  func(int) int = f3[int]
 
        v6 func(int, int)     = f4
-       v7 func(int, string)  = f4 // ERROR "type func(int, string) of variable in assignment does not match inferred type func(int, int) for func(P, P)"
+       v7 func(int, string)  = f4 // ERROR "type func(int, string) of v7 does not match inferred type func(int, int) for func(P, P)"
        v8 func(int) []int    = f5
-       v9 func(string) []int = f5 // ERROR "type func(string) []int of variable in assignment does not match inferred type func(string) []string for func(P) []P"
+       v9 func(string) []int = f5 // ERROR "type func(string) []int of v9 does not match inferred type func(string) []string for func(P) []P"
 
        _, _ func(int) = f1, f1
        _, _ func(int) = f1, f2 // ERROR "cannot infer P"
@@ -49,9 +49,13 @@ func _() {
        v5 = f3[int]
 
        v6 = f4
-       v7 = f4 // ERROR "type func(int, string) of variable in assignment does not match inferred type func(int, int) for func(P, P)"
+       v7 = f4 // ERROR "type func(int, string) of v7 does not match inferred type func(int, int) for func(P, P)"
        v8 = f5
-       v9 = f5 // ERROR "type func(string) []int of variable in assignment does not match inferred type func(string) []string for func(P) []P"
+       v9 = f5 // ERROR "type func(string) []int of v9 does not match inferred type func(string) []string for func(P) []P"
+
+       // non-trivial LHS
+       var a [2]func(string) []int
+       a[0] = f5 // ERROR "type func(string) []int of a[0] does not match inferred type func(string) []string for func(P) []P"
 }
 
 // Return statements
@@ -62,11 +66,11 @@ func _() func(int) int { return f3[int] }
 
 func _() func(int, int) { return f4 }
 func _() func(int, string) {
-       return f4 /* ERROR "type func(int, string) of variable in assignment does not match inferred type func(int, int) for func(P, P)" */
+       return f4 /* ERROR "type func(int, string) of result variable does not match inferred type func(int, int) for func(P, P)" */
 }
 func _() func(int) []int { return f5 }
 func _() func(string) []int {
-       return f5 /* ERROR "type func(string) []int of variable in assignment does not match inferred type func(string) []string for func(P) []P" */
+       return f5 /* ERROR "type func(string) []int of result variable does not match inferred type func(string) []string for func(P) []P" */
 }
 
 func _() (_, _ func(int)) { return f1, f1 }
index 38d90ee8cc45ba1761e9350e29d347c5f6bf6a4d..ba27f2885138079d82a913a6708ac86cfc443c06 100644 (file)
@@ -13,4 +13,4 @@ func g[P any](P, string) {}
 // be identical to match).
 // The result is an error from type inference, rather than an
 // error from an assignment mismatch.
-var f func(int, String) = g // ERROR "type func(int, String) of variable in assignment does not match inferred type func(int, string) for func(P, string)"
+var f func(int, String) = g // ERROR "type func(int, String) of f does not match inferred type func(int, string) for func(P, string)"
diff --git a/src/internal/types/testdata/fixedbugs/issue60747.go b/src/internal/types/testdata/fixedbugs/issue60747.go
new file mode 100644 (file)
index 0000000..c76e3d0
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2023 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 p
+
+func f[P any](P) P { panic(0) }
+
+var v func(string) int = f // ERROR "type func(string) int of v does not match inferred type func(string) string for func(P) P"
+
+func _() func(string) int {
+       return f // ERROR "type func(string) int of result variable does not match inferred type func(string) string for func(P) P"
+}