]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: better error messages for certain type mismatches
authorRobert Griesemer <gri@google.com>
Wed, 18 Jun 2025 00:09:27 +0000 (17:09 -0700)
committerGopher Robot <gobot@golang.org>
Thu, 24 Jul 2025 16:04:33 +0000 (09:04 -0700)
When an untyped operand of a (typically binary) operation does not
match the type of the operand and an implicit conversion is not
possible, the error message should report a "type mismatch".

The type-checkers mostly did so, but not for untyped numeric types
to other types (e.g. an untyped int vs a function); in those cases
it reported that the (impossible) conversion failed.

Fix this for numeric types.
This also improves the position and messages for some incorrect
min/max built-in calls.

Fixes #73428.

Change-Id: I8af071918b73fcc72f16cc61858d7baca57fc259
Reviewed-on: https://go-review.googlesource.com/c/go/+/682495
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Mark Freeman <mark@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>

src/cmd/compile/internal/types2/expr.go
src/go/types/expr.go
src/internal/types/errors/codes.go
src/internal/types/testdata/check/builtins1.go
src/internal/types/testdata/check/expr2.go
src/internal/types/testdata/fixedbugs/issue60434.go
src/internal/types/testdata/fixedbugs/issue73428.go [new file with mode: 0644]
test/fixedbugs/issue46749.go

index eaa55e20c9aef41b3611a5cb265cf0e6530182b1..e5f9a1c6f7cb491985b33bbab2846313bdbefd55 100644 (file)
@@ -895,6 +895,10 @@ func (check *Checker) matchTypes(x, y *operand) {
                if isTyped(x.typ) && isTyped(y.typ) {
                        return false
                }
+               // A numeric type can only convert to another numeric type.
+               if allNumeric(x.typ) != allNumeric(y.typ) {
+                       return false
+               }
                // An untyped operand may convert to its default type when paired with an empty interface
                // TODO(gri) This should only matter for comparisons (the only binary operation that is
                //           valid with interfaces), but in that case the assignability check should take
index aa8543f081246c28c7757d6931496acfbcc73a09..97d8c42997863c377ab44c2dabe9076e45b942a6 100644 (file)
@@ -887,6 +887,10 @@ func (check *Checker) matchTypes(x, y *operand) {
                if isTyped(x.typ) && isTyped(y.typ) {
                        return false
                }
+               // A numeric type can only convert to another numeric type.
+               if allNumeric(x.typ) != allNumeric(y.typ) {
+                       return false
+               }
                // An untyped operand may convert to its default type when paired with an empty interface
                // TODO(gri) This should only matter for comparisons (the only binary operation that is
                //           valid with interfaces), but in that case the assignability check should take
index f8c9eb920f5840cc97a3e3630dd2e3fe445046dd..b0f7d2d446642981592ed2da760a209112b4b0fa 100644 (file)
@@ -881,7 +881,9 @@ const (
        // context in which it is used.
        //
        // Example:
-       //  var _ = 1 + []int{}
+       //  func f[T ~int8 | ~int16 | ~int32 | ~int64](x T) T {
+       //      return x + 1024
+       //  }
        InvalidUntypedConversion
 
        // BadOffsetofSyntax occurs when unsafe.Offsetof is called with an argument
index 422a5462d1c66b6fe06a96f0d281e59f5125e843..341723ccb07e179f36eac12131ce181ce0464674 100644 (file)
@@ -211,7 +211,7 @@ func _[
        var x2 P2
        _ = max(x2)
        _ = max(x2, x2)
-       _ = max(1, 2 /* ERROR "cannot convert 2 (untyped int constant) to type P2" */, x2) // error at 2 because max is 2
+       _ = max(1, 2, x2 /* ERROR "mismatched types untyped int (previous argument) and P2 (type of x2)" */ )
 
        _ = max(x1, x2 /* ERROR "mismatched types P1 (previous argument) and P2 (type of x2)" */ )
 }
@@ -232,7 +232,7 @@ func _[
        var x2 P2
        _ = min(x2)
        _ = min(x2, x2)
-       _ = min(1 /* ERROR "cannot convert 1 (untyped int constant) to type P2" */ , 2, x2) // error at 1 because min is 1
+       _ = min(1, 2, x2 /* ERROR "mismatched types untyped int (previous argument) and P2 (type of x2)" */ )
 
        _ = min(x1, x2 /* ERROR "mismatched types P1 (previous argument) and P2 (type of x2)" */ )
 }
index ebb85eb2339d5561893b4fd2523d5349111d0f48..603f5ae190734f7de548f0c1227eda0e1e60b8c9 100644 (file)
@@ -201,7 +201,7 @@ func interfaces() {
        var s11 S11
        var s2 S2
 
-       _ = i == 0 /* ERROR "cannot convert" */
+       _ = i == 0 /* ERROR "invalid operation: i == 0 (mismatched types interface{m() int} and untyped int)" */
        _ = i == s1 /* ERROR "mismatched types" */
        _ = i == &s1
        _ = i == &s11
index e1d76527f3db63f83affbe2951d6a9ebd62cdd44..68aa7c2fdfd11bc39161918af40b4a457f638547 100644 (file)
@@ -13,5 +13,5 @@ var s struct{ x int }
 
 func _() {
        f(s.y /* ERROR "s.y undefined" */)
-       f(1 /* ERROR "cannot convert 1" */ / s)
+       f(1 /* ERROR "invalid operation: 1 / s (mismatched types untyped int and struct{x int})" */ / s)
 }
diff --git a/src/internal/types/testdata/fixedbugs/issue73428.go b/src/internal/types/testdata/fixedbugs/issue73428.go
new file mode 100644 (file)
index 0000000..b452b90
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2025 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() {}
+
+const c = 0
+
+var v int
+var _ = f < c // ERROR "invalid operation: f < c (mismatched types func() and untyped int)"
+var _ = f < v // ERROR "invalid operation: f < v (mismatched types func() and int)"
index faf1f884a6b40cde9d83a606b77a25314091315f..86f57a6159d6f2ca9c435817da3fed6e652b07a0 100644 (file)
@@ -31,7 +31,7 @@ var (
 var (
        _ = b + 1         // ERROR "invalid operation.*mismatched types.*bool and untyped int"
        _ = i + false     // ERROR "invalid operation.*mismatched types.*int and untyped bool"
-       _ = iface + 1     // ERROR "invalid operation.*mismatched types.*interface *{} and int"
-       _ = iface + 1.0   // ERROR "invalid operation.*mismatched types.*interface *{} and float64"
+       _ = iface + 1     // ERROR "invalid operation.*mismatched types.*interface *{} and untyped int"
+       _ = iface + 1.0   // ERROR "invalid operation.*mismatched types.*interface *{} and untyped float"
        _ = iface + false // ERROR "invalid operation.*mismatched types.*interface *{} and bool"
 )