]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types, types2: flip message contents for reverse type inference errors
authorRobert Griesemer <gri@golang.org>
Tue, 12 Dec 2023 01:54:18 +0000 (17:54 -0800)
committerGopher Robot <gobot@golang.org>
Tue, 12 Dec 2023 18:44:59 +0000 (18:44 +0000)
Add a new flag 'reverse' to control the formatting of type inference
error messages.

This change only impacts error messages.

Fixes #60747.

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

src/cmd/compile/internal/types2/call.go
src/cmd/compile/internal/types2/infer.go
src/go/types/call.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

index 7d9b80f6611cef9d85ca0d6f96c32561c7a33607..db7d86e3d380f31e96170c018381def8b49edb41 100644 (file)
@@ -87,6 +87,7 @@ func (check *Checker) funcInst(T *target, pos syntax.Pos, x *operand, inst *synt
                //
                var args []*operand
                var params []*Var
+               var reverse bool
                if T != nil && sig.tparams != nil {
                        if !versionErr && !check.allowVersion(check.pkg, instErrPos, go1_21) {
                                if inst != nil {
@@ -102,13 +103,14 @@ func (check *Checker) funcInst(T *target, pos syntax.Pos, x *operand, inst *synt
                        // that makes sense when reported in error messages from infer, below.
                        expr := syntax.NewName(x.Pos(), T.desc)
                        args = []*operand{{mode: value, expr: expr, typ: T.sig}}
+                       reverse = true
                }
 
                // Rename type parameters to avoid problems with recursive instantiations.
                // Note that NewTuple(params...) below is (*Tuple)(nil) if len(params) == 0, as desired.
                tparams, params2 := check.renameTParams(pos, sig.TypeParams().list(), NewTuple(params...))
 
-               targs = check.infer(pos, tparams, targs, params2.(*Tuple), args)
+               targs = check.infer(pos, tparams, targs, params2.(*Tuple), args, reverse)
                if targs == nil {
                        // error was already reported
                        x.mode = invalid
@@ -608,7 +610,7 @@ func (check *Checker) arguments(call *syntax.CallExpr, sig *Signature, targs []T
 
        // infer missing type arguments of callee and function arguments
        if len(tparams) > 0 {
-               targs = check.infer(call.Pos(), tparams, targs, sigParams, args)
+               targs = check.infer(call.Pos(), tparams, targs, sigParams, args, false)
                if targs == nil {
                        // TODO(gri) If infer inferred the first targs[:n], consider instantiating
                        //           the call signature for better error messages/gopls behavior.
index 94f2de7b3ce88b3524c4345f114b7d0a2ca5d765..a520f7025343ba6744de7f98b510ac5000993aa7 100644 (file)
@@ -24,9 +24,11 @@ const enableReverseTypeInference = true // disable for debugging
 // based on the given type parameters tparams, type arguments targs, function parameters params, and
 // function arguments args, if any. There must be at least one type parameter, no more type arguments
 // than type parameters, and params and args must match in number (incl. zero).
+// If reverse is set, an error message's contents are reversed for a better error message for some
+// errors related to reverse type inference (where the function call is synthetic).
 // If successful, infer returns the complete list of given and inferred type arguments, one for each
 // type parameter. Otherwise the result is nil and appropriate errors will be reported.
-func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) (inferred []Type) {
+func (check *Checker) infer(pos syntax.Pos, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand, reverse bool) (inferred []Type) {
        // Don't verify result conditions if there's no error handler installed:
        // in that case, an error leads to an exit panic and the result value may
        // be incorrect. But in that case it doesn't matter because callers won't
@@ -137,7 +139,11 @@ 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, "type %s of %s does not match inferred type %s for %s", targ, arg.expr, inferred, tpar)
+                       if reverse {
+                               check.errorf(arg, CannotInferTypeArgs, "inferred type %s for %s does not match type %s of %s", inferred, tpar, targ, arg.expr)
+                       } else {
+                               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, "type %s of %s does not match %s", targ, arg.expr, tpar)
                }
index 5ac556c511afd4e3968a40ec1d409e2b36ce89e6..c7de3bdb9f3a440400915bcbe0748263c6e64406 100644 (file)
@@ -89,6 +89,7 @@ func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *typepar
                //
                var args []*operand
                var params []*Var
+               var reverse bool
                if T != nil && sig.tparams != nil {
                        if !versionErr && !check.allowVersion(check.pkg, instErrPos, go1_21) {
                                if ix != nil {
@@ -105,13 +106,14 @@ func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *typepar
                        expr := ast.NewIdent(T.desc)
                        expr.NamePos = x.Pos() // correct position
                        args = []*operand{{mode: value, expr: expr, typ: T.sig}}
+                       reverse = true
                }
 
                // Rename type parameters to avoid problems with recursive instantiations.
                // Note that NewTuple(params...) below is (*Tuple)(nil) if len(params) == 0, as desired.
                tparams, params2 := check.renameTParams(pos, sig.TypeParams().list(), NewTuple(params...))
 
-               targs = check.infer(atPos(pos), tparams, targs, params2.(*Tuple), args)
+               targs = check.infer(atPos(pos), tparams, targs, params2.(*Tuple), args, reverse)
                if targs == nil {
                        // error was already reported
                        x.mode = invalid
@@ -610,7 +612,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type
 
        // infer missing type arguments of callee and function arguments
        if len(tparams) > 0 {
-               targs = check.infer(call, tparams, targs, sigParams, args)
+               targs = check.infer(call, tparams, targs, sigParams, args, false)
                if targs == nil {
                        // TODO(gri) If infer inferred the first targs[:n], consider instantiating
                        //           the call signature for better error messages/gopls behavior.
index ed9841f06e6c2ba66a6d2f44d7db95bcab71b7db..889de000b0ca8fe36920259e5a77345e760623f0 100644 (file)
@@ -26,9 +26,11 @@ const enableReverseTypeInference = true // disable for debugging
 // based on the given type parameters tparams, type arguments targs, function parameters params, and
 // function arguments args, if any. There must be at least one type parameter, no more type arguments
 // than type parameters, and params and args must match in number (incl. zero).
+// If reverse is set, an error message's contents are reversed for a better error message for some
+// errors related to reverse type inference (where the function call is synthetic).
 // If successful, infer returns the complete list of given and inferred type arguments, one for each
 // type parameter. Otherwise the result is nil and appropriate errors will be reported.
-func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand) (inferred []Type) {
+func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand, reverse bool) (inferred []Type) {
        // Don't verify result conditions if there's no error handler installed:
        // in that case, an error leads to an exit panic and the result value may
        // be incorrect. But in that case it doesn't matter because callers won't
@@ -139,7 +141,11 @@ 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, "type %s of %s does not match inferred type %s for %s", targ, arg.expr, inferred, tpar)
+                       if reverse {
+                               check.errorf(arg, CannotInferTypeArgs, "inferred type %s for %s does not match type %s of %s", inferred, tpar, targ, arg.expr)
+                       } else {
+                               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, "type %s of %s does not match %s", targ, arg.expr, tpar)
                }
index a4cfa3b41364470b364759f5bd3b409f914bd843..91f9df1d840d0460846f9f98f47306f6ce5a6332 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 v7 does not match inferred type func(int, int) for func(P, P)"
+       v7 func(int, string)  = f4 // ERROR "inferred type func(int, int) for func(P, P) does not match type func(int, string) of v7"
        v8 func(int) []int    = f5
-       v9 func(string) []int = f5 // ERROR "type func(string) []int of v9 does not match inferred type func(string) []string for func(P) []P"
+       v9 func(string) []int = f5 // ERROR "inferred type func(string) []string for func(P) []P does not match type func(string) []int of v9"
 
        _, _ func(int) = f1, f1
        _, _ func(int) = f1, f2 // ERROR "cannot infer P"
@@ -49,13 +49,13 @@ func _() {
        v5 = f3[int]
 
        v6 = f4
-       v7 = f4 // ERROR "type func(int, string) of v7 does not match inferred type func(int, int) for func(P, P)"
+       v7 = f4 // ERROR "inferred type func(int, int) for func(P, P) does not match type func(int, string) of v7"
        v8 = f5
-       v9 = f5 // ERROR "type func(string) []int of v9 does not match inferred type func(string) []string for func(P) []P"
+       v9 = f5 // ERROR "inferred type func(string) []string for func(P) []P does not match type func(string) []int of v9"
 
        // 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"
+       a[0] = f5 // ERROR "inferred type func(string) []string for func(P) []P does not match type func(string) []int of a[0]"
 }
 
 // Return statements
@@ -66,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 result variable does not match inferred type func(int, int) for func(P, P)" */
+       return f4 /* ERROR "inferred type func(int, int) for func(P, P) does not match type func(int, string) of result variable" */
 }
 func _() func(int) []int { return f5 }
 func _() func(string) []int {
-       return f5 /* ERROR "type func(string) []int of result variable does not match inferred type func(string) []string for func(P) []P" */
+       return f5 /* ERROR "inferred type func(string) []string for func(P) []P does not match type func(string) []int of result variable" */
 }
 
 func _() (_, _ func(int)) { return f1, f1 }
index ba27f2885138079d82a913a6708ac86cfc443c06..61b9f915106db8bc09dde61d89d851a795f3515e 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 f does not match inferred type func(int, string) for func(P, string)"
+var f func(int, String) = g // ERROR "inferred type func(int, string) for func(P, string) does not match type func(int, String) of f"
index c76e3d008c4038777a1423a825ec56d9d00c547f..6587a4e55788e129a61fc1c93a5438f9981044b6 100644 (file)
@@ -6,8 +6,8 @@ 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"
+var v func(string) int = f // ERROR "inferred type func(string) string for func(P) P does not match type func(string) int of v"
 
 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"
+       return f // ERROR "inferred type func(string) string for func(P) P does not match type func(string) int of result variable"
 }