For #59488.
Change-Id: I4553ab11af9179a4786dede44877f88286c168dc
Reviewed-on: https://go-review.googlesource.com/c/go/+/496038
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
check.recordBuiltinType(call.Fun, makeSig(x.typ, types...))
}
+ case _Max, _Min:
+ // max(x, ...)
+ // min(x, ...)
+ if !check.verifyVersionf(check.pkg, call.Fun, go1_21, bin.name) {
+ return
+ }
+
+ op := token.LSS
+ if id == _Max {
+ op = token.GTR
+ }
+
+ for i, a := range args {
+ if a.mode == invalid {
+ return
+ }
+
+ if !allOrdered(a.typ) {
+ check.errorf(a, InvalidMinMaxOperand, invalidArg+"%s cannot be ordered", a)
+ return
+ }
+
+ // The first argument is already in x and there's nothing left to do.
+ if i > 0 {
+ check.matchTypes(x, a)
+ if x.mode == invalid {
+ return
+ }
+
+ if !Identical(x.typ, a.typ) {
+ check.errorf(a, MismatchedTypes, invalidArg+"mismatched types %s (previous argument) and %s (type of %s)", x.typ, a.typ, a.expr)
+ return
+ }
+
+ if x.mode == constant_ && a.mode == constant_ {
+ if constant.Compare(a.val, op, x.val) {
+ *x = *a
+ }
+ } else {
+ x.mode = value
+ }
+ }
+ }
+
+ // If nargs == 1, make sure x.mode is either a value or a constant.
+ if x.mode != constant_ {
+ x.mode = value
+ }
+
+ if check.recordTypes() && x.mode != constant_ {
+ types := make([]Type, nargs)
+ for i := range types {
+ types[i] = x.typ
+ }
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, types...))
+ }
+
case _New:
// new(T)
// (no argument evaluated yet)
// go.dev/issue/45667
{"make", `const l uint = 1; _ = make([]int, l)`, `func([]int, uint) []int`},
+ {"max", ` _ = max(0 )`, `invalid type`}, // constant
+ {"max", `var x int ; _ = max(x )`, `func(int) int`},
+ {"max", `var x int ; _ = max(0, x )`, `func(int, int) int`},
+ {"max", `var x string ; _ = max("a", x )`, `func(string, string) string`},
+ {"max", `var x float32; _ = max(0, 1.0, x)`, `func(float32, float32, float32) float32`},
+
+ {"min", ` _ = min(0 )`, `invalid type`}, // constant
+ {"min", `var x int ; _ = min(x )`, `func(int) int`},
+ {"min", `var x int ; _ = min(0, x )`, `func(int, int) int`},
+ {"min", `var x string ; _ = min("a", x )`, `func(string, string) string`},
+ {"min", `var x float32; _ = min(0, 1.0, x)`, `func(float32, float32, float32) float32`},
+
{"new", `_ = new(int)`, `func(int) *int`},
{"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`},
_Imag
_Len
_Make
+ _Max
+ _Min
_New
_Panic
_Print
_Imag: {"imag", 1, false, expression},
_Len: {"len", 1, false, expression},
_Make: {"make", 1, true, expression},
+ // To disable max/min, remove the next two lines.
+ _Max: {"max", 1, true, expression},
+ _Min: {"min", 1, true, expression},
_New: {"new", 1, false, expression},
_Panic: {"panic", 1, false, statement},
_Print: {"print", 0, true, statement},
check.recordBuiltinType(call.Fun, makeSig(x.typ, types...))
}
+ case _Max, _Min:
+ // max(x, ...)
+ // min(x, ...)
+ if !check.verifyVersionf(check.pkg, call.Fun, go1_21, bin.name) {
+ return
+ }
+
+ op := token.LSS
+ if id == _Max {
+ op = token.GTR
+ }
+
+ for i, a := range args {
+ if a.mode == invalid {
+ return
+ }
+
+ if !allOrdered(a.typ) {
+ check.errorf(a, InvalidMinMaxOperand, invalidArg+"%s cannot be ordered", a)
+ return
+ }
+
+ // The first argument is already in x and there's nothing left to do.
+ if i > 0 {
+ check.matchTypes(x, a)
+ if x.mode == invalid {
+ return
+ }
+
+ if !Identical(x.typ, a.typ) {
+ check.errorf(a, MismatchedTypes, invalidArg+"mismatched types %s (previous argument) and %s (type of %s)", x.typ, a.typ, a.expr)
+ return
+ }
+
+ if x.mode == constant_ && a.mode == constant_ {
+ if constant.Compare(a.val, op, x.val) {
+ *x = *a
+ }
+ } else {
+ x.mode = value
+ }
+ }
+ }
+
+ // If nargs == 1, make sure x.mode is either a value or a constant.
+ if x.mode != constant_ {
+ x.mode = value
+ }
+
+ if check.recordTypes() && x.mode != constant_ {
+ types := make([]Type, nargs)
+ for i := range types {
+ types[i] = x.typ
+ }
+ check.recordBuiltinType(call.Fun, makeSig(x.typ, types...))
+ }
+
case _New:
// new(T)
// (no argument evaluated yet)
// go.dev/issue/45667
{"make", `const l uint = 1; _ = make([]int, l)`, `func([]int, uint) []int`},
+ {"max", ` _ = max(0 )`, `invalid type`}, // constant
+ {"max", `var x int ; _ = max(x )`, `func(int) int`},
+ {"max", `var x int ; _ = max(0, x )`, `func(int, int) int`},
+ {"max", `var x string ; _ = max("a", x )`, `func(string, string) string`},
+ {"max", `var x float32; _ = max(0, 1.0, x)`, `func(float32, float32, float32) float32`},
+
+ {"min", ` _ = min(0 )`, `invalid type`}, // constant
+ {"min", `var x int ; _ = min(x )`, `func(int) int`},
+ {"min", `var x int ; _ = min(0, x )`, `func(int, int) int`},
+ {"min", `var x string ; _ = min("a", x )`, `func(string, string) string`},
+ {"min", `var x float32; _ = min(0, 1.0, x)`, `func(float32, float32, float32) float32`},
+
{"new", `_ = new(int)`, `func(int) *int`},
{"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`},
_Imag
_Len
_Make
+ _Max
+ _Min
_New
_Panic
_Print
_Imag: {"imag", 1, false, expression},
_Len: {"len", 1, false, expression},
_Make: {"make", 1, true, expression},
+ // To disable max/min, remove the next two lines.
+ _Max: {"max", 1, true, expression},
+ _Min: {"min", 1, true, expression},
_New: {"new", 1, false, expression},
_Panic: {"panic", 1, false, statement},
_Print: {"print", 0, true, statement},
_ = x[InvalidUnsafeString-146]
_ = x[InvalidClear-148]
_ = x[TypeTooLarge-149]
+ _ = x[InvalidMinMaxOperand-150]
}
const (
_Code_name_2 = "InvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDot"
_Code_name_3 = "InvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDecl"
_Code_name_4 = "InvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParamInvalidUnsafeSliceDataInvalidUnsafeString"
- _Code_name_5 = "InvalidClearTypeTooLarge"
+ _Code_name_5 = "InvalidClearTypeTooLargeInvalidMinMaxOperand"
)
var (
_Code_index_2 = [...]uint16{0, 15, 22, 33, 56, 71, 83, 94, 109, 123, 138, 153, 166, 175, 189, 204, 215, 230, 239, 255, 275, 293, 312, 324, 343, 362, 378, 395, 414, 428, 439, 454, 467, 482, 498, 512, 528, 543, 560, 578, 593, 603, 613, 630, 652, 666, 680, 700, 718, 738, 756}
_Code_index_3 = [...]uint16{0, 16, 31, 44, 54, 66, 77, 91, 104, 115, 125, 140, 151, 162, 175, 191, 208, 232, 249, 264, 274, 283, 296, 312, 328, 339, 354}
_Code_index_4 = [...]uint16{0, 14, 30, 44, 61, 81, 94, 110, 124, 141, 158, 175, 190, 204, 218, 229, 241, 254, 271, 284, 295, 308, 320, 329, 336, 348, 364, 382, 400, 415, 432, 451, 465, 485, 497, 521, 544, 562, 584, 603}
- _Code_index_5 = [...]uint8{0, 12, 24}
+ _Code_index_5 = [...]uint8{0, 12, 24, 44}
)
func (i Code) String() string {
case 108 <= i && i <= 146:
i -= 108
return _Code_name_4[_Code_index_4[i]:_Code_index_4[i+1]]
- case 148 <= i && i <= 149:
+ case 148 <= i && i <= 150:
i -= 148
return _Code_name_5[_Code_index_5[i]:_Code_index_5[i+1]]
default:
// }
// var _ = unsafe.Offsetof(s.x)
TypeTooLarge
+
+ // InvalidMinMaxOperand occurs if min or max is called
+ // with an operand that cannot be ordered because it
+ // does not support the < operator.
+ //
+ // Example:
+ // const _ = min(true)
+ //
+ // Example:
+ // var s, t []byte
+ // var _ = max(s, t)
+ InvalidMinMaxOperand
)
_ = make(f1 /* ERROR "not a type" */ ())
}
+func max1() {
+ var b bool
+ var c complex128
+ var x int
+ var s string
+ type myint int
+ var m myint
+ _ = max() /* ERROR "not enough arguments" */
+ _ = max(b /* ERROR "cannot be ordered" */ )
+ _ = max(c /* ERROR "cannot be ordered" */ )
+ _ = max(x)
+ _ = max(s)
+ _ = max(x, x)
+ _ = max(x, x, x, x, x)
+ var _ int = max /* ERROR "cannot use max(m) (value of type myint) as int value" */ (m)
+ _ = max(x, m /* ERROR "invalid argument: mismatched types int (previous argument) and myint (type of m)" */ , x)
+
+ _ = max(1, x)
+ _ = max(1.0, x)
+ _ = max(1.2 /* ERROR "1.2 (untyped float constant) truncated to int" */ , x)
+ _ = max(-10, 1.0, c /* ERROR "cannot be ordered" */ )
+
+ const (
+ _ = max /* ERROR "max(x) (value of type int) is not constant" */ (x)
+ _ = max(true /* ERROR "invalid argument: true (untyped bool constant) cannot be ordered" */ )
+ _ = max(1)
+ _ = max(1, 2.3, 'a')
+ _ = max(1, "foo" /* ERROR "mismatched types" */ )
+ _ = max(1, 0i /* ERROR "cannot be ordered" */ )
+ _ = max(1, 2 /* ERROR "cannot be ordered" */ + 3i )
+ )
+}
+
+func max2() {
+ _ = assert(max(0) == 0)
+ _ = assert(max(0, 1) == 1)
+ _ = assert(max(0, -10, 123456789) == 123456789)
+ _ = assert(max(-12345678901234567890, 0) == 0)
+
+ _ = assert(max(1, 2.3) == 2.3)
+ _ = assert(max(1, 2.3, 'a') == 'a')
+
+ _ = assert(max("", "a") == "a")
+ _ = assert(max("abcde", "xyz", "foo", "bar") == "xyz")
+
+ const (
+ _ int = max(1.0)
+ _ float32 = max(1, 2)
+ _ int = max /* ERROR "cannot use max(1, 2.3) (untyped float constant 2.3) as int value" */ (1, 2.3)
+ _ int = max(1.2, 3) // ok!
+ _ byte = max(1, 'a')
+ )
+}
+
+func min1() {
+ var b bool
+ var c complex128
+ var x int
+ var s string
+ type myint int
+ var m myint
+ _ = min() /* ERROR "not enough arguments" */
+ _ = min(b /* ERROR "cannot be ordered" */ )
+ _ = min(c /* ERROR "cannot be ordered" */ )
+ _ = min(x)
+ _ = min(s)
+ _ = min(x, x)
+ _ = min(x, x, x, x, x)
+ var _ int = min /* ERROR "cannot use min(m) (value of type myint) as int value" */ (m)
+ _ = min(x, m /* ERROR "invalid argument: mismatched types int (previous argument) and myint (type of m)" */ , x)
+
+ _ = min(1, x)
+ _ = min(1.0, x)
+ _ = min(1.2 /* ERROR "1.2 (untyped float constant) truncated to int" */ , x)
+ _ = min(-10, 1.0, c /* ERROR "cannot be ordered" */ )
+
+ const (
+ _ = min /* ERROR "min(x) (value of type int) is not constant" */ (x)
+ _ = min(true /* ERROR "invalid argument: true (untyped bool constant) cannot be ordered" */ )
+ _ = min(1)
+ _ = min(1, 2.3, 'a')
+ _ = min(1, "foo" /* ERROR "mismatched types" */ )
+ _ = min(1, 0i /* ERROR "cannot be ordered" */ )
+ _ = min(1, 2 /* ERROR "cannot be ordered" */ + 3i )
+ )
+}
+
+func min2() {
+ _ = assert(min(0) == 0)
+ _ = assert(min(0, 1) == 0)
+ _ = assert(min(0, -10, 123456789) == -10)
+ _ = assert(min(-12345678901234567890, 0) == -12345678901234567890)
+
+ _ = assert(min(1, 2.3) == 1)
+ _ = assert(min(1, 2.3, 'a') == 1)
+
+ _ = assert(min("", "a") == "")
+ _ = assert(min("abcde", "xyz", "foo", "bar") == "abcde")
+
+ const (
+ _ int = min(1.0)
+ _ float32 = min(1, 2)
+ _ int = min(1, 2.3) // ok!
+ _ int = min /* ERROR "cannot use min(1.2, 3) (untyped float constant 1.2) as int value" */ (1.2, 3)
+ _ byte = min(1, 'a')
+ )
+}
+
func new1() {
_ = new() // ERROR "not enough arguments"
_ = new(1, 2) // ERROR "too many arguments"
_ = make(C3)
}
+// max
+
+func _[
+ P1 ~int|~float64,
+ P2 ~int|~string|~uint,
+ P3 ~int|bool,
+]() {
+ var x1 P1
+ _ = max(x1)
+ _ = max(x1, x1)
+ _ = max(1, x1, 2)
+ const _ = max /* ERROR "max(1, x1, 2) (value of type P1 constrained by ~int | ~float64) is not constant" */ (1, x1, 2)
+
+ 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(x1, x2 /* ERROR "mismatched types P1 (previous argument) and P2 (type of x2)" */ )
+}
+
+// min
+
+func _[
+ P1 ~int|~float64,
+ P2 ~int|~string|~uint,
+ P3 ~int|bool,
+]() {
+ var x1 P1
+ _ = min(x1)
+ _ = min(x1, x1)
+ _ = min(1, x1, 2)
+ const _ = min /* ERROR "min(1, x1, 2) (value of type P1 constrained by ~int | ~float64) is not constant" */ (1, x1, 2)
+
+ 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(x1, x2 /* ERROR "mismatched types P1 (previous argument) and P2 (type of x2)" */ )
+}
+
// unsafe.Alignof
func _[T comparable]() {