From cae45167b79ec3838f0cabb19394bcd99810f79a Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 17 Jun 2025 17:09:27 -0700 Subject: [PATCH] go/types, types2: better error messages for certain type mismatches 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 Reviewed-by: Mark Freeman Reviewed-by: Robert Griesemer Auto-Submit: Robert Griesemer --- src/cmd/compile/internal/types2/expr.go | 4 ++++ src/go/types/expr.go | 4 ++++ src/internal/types/errors/codes.go | 4 +++- src/internal/types/testdata/check/builtins1.go | 4 ++-- src/internal/types/testdata/check/expr2.go | 2 +- src/internal/types/testdata/fixedbugs/issue60434.go | 2 +- src/internal/types/testdata/fixedbugs/issue73428.go | 13 +++++++++++++ test/fixedbugs/issue46749.go | 4 ++-- 8 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 src/internal/types/testdata/fixedbugs/issue73428.go diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index eaa55e20c9..e5f9a1c6f7 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -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 diff --git a/src/go/types/expr.go b/src/go/types/expr.go index aa8543f081..97d8c42997 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -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 diff --git a/src/internal/types/errors/codes.go b/src/internal/types/errors/codes.go index f8c9eb920f..b0f7d2d446 100644 --- a/src/internal/types/errors/codes.go +++ b/src/internal/types/errors/codes.go @@ -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 diff --git a/src/internal/types/testdata/check/builtins1.go b/src/internal/types/testdata/check/builtins1.go index 422a5462d1..341723ccb0 100644 --- a/src/internal/types/testdata/check/builtins1.go +++ b/src/internal/types/testdata/check/builtins1.go @@ -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)" */ ) } diff --git a/src/internal/types/testdata/check/expr2.go b/src/internal/types/testdata/check/expr2.go index ebb85eb233..603f5ae190 100644 --- a/src/internal/types/testdata/check/expr2.go +++ b/src/internal/types/testdata/check/expr2.go @@ -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 diff --git a/src/internal/types/testdata/fixedbugs/issue60434.go b/src/internal/types/testdata/fixedbugs/issue60434.go index e1d76527f3..68aa7c2fdf 100644 --- a/src/internal/types/testdata/fixedbugs/issue60434.go +++ b/src/internal/types/testdata/fixedbugs/issue60434.go @@ -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 index 0000000000..b452b90fe3 --- /dev/null +++ b/src/internal/types/testdata/fixedbugs/issue73428.go @@ -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)" diff --git a/test/fixedbugs/issue46749.go b/test/fixedbugs/issue46749.go index faf1f884a6..86f57a6159 100644 --- a/test/fixedbugs/issue46749.go +++ b/test/fixedbugs/issue46749.go @@ -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" ) -- 2.51.0