Unreviewed changes
1 is the latest approved patch-set.
The change was submitted with unreviewed changes in the following files:
```
The name of the file: go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go.golden
Insertions: 19, Deletions: 27.
@@ -351,50 +351,42 @@
}
}
-type Integer interface {
- ~int | ~uint
-}
-
-// Regression tests for golang/go#78571: the loop index cannot be a type parameter
-// constrained by multiple distinct integer types.
-func issue78571[I Integer](n I) {
+// Regression tests for golang/go#78571: the loop index cannot be a type
+// parameter constrained by multiple distinct integer types, nor a type
+// parameter constrained by a non-integer type.
+func issue78571[I ~int | ~uint](limit I) {
var i I
- for i = 0; i < n; i++ { // nope: int and uint have different underlying types.
+ for i = 0; i < limit; i++ { // nope: int and uint have different underlying types.
println(i)
}
}
type MyInt int
-type SameUnderlying interface {
- int | MyInt
-}
-
-func issue78571_same[I SameUnderlying](n I) {
- var i I
- for i = range n { // want "for loop can be modernized using range over int"
+func issue78571_sameunderlying[T int | MyInt](limit T) {
+ var i T
+ for i = range limit { // want "for loop can be modernized using range over int"
println(i)
}
}
-type SingleTerm interface {
- ~int
-}
-
-func issue78571_single[I SingleTerm](n I) {
- var i I
- for i = range n { // want "for loop can be modernized using range over int"
+func issue78571_single[T ~int](limit T) {
+ var i T
+ for i = range limit { // want "for loop can be modernized using range over int"
println(i)
}
}
-type Float interface {
- ~float64
+func issue78571_float[T ~float64](limit T) {
+ var i T
+ for i = 0; i < limit; i++ { // nope: can't range over a float
+ println(i)
+ }
}
-func issue78571_float[I Float](n I) {
- var i I
- for i = 0; i < n; i++ { // nope: can't range over a float
+func issue78571_floats[T float32 | float64](limit T) {
+ var i T
+ for i = 0; i < limit; i++ { // nope: can't range over a float
println(i)
}
}
```
```
The name of the file: go/analysis/passes/modernize/rangeint.go
Insertions: 21, Deletions: 17.
@@ -9,6 +9,7 @@
"go/ast"
"go/token"
"go/types"
+ "log"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/analysis/passes/inspect"
@@ -215,30 +216,33 @@
}
}
- // The loop index (v) may not be a type parameter constrained by
+ // The loop index (v) must not be a type parameter constrained by
// multiple distinct integer types, or a type parameter constrained
// by non-integer types. Transforming such instances to a range loop
// would result in a compiler error.
// See golang/go#78571.
- if tparam, ok := v.Type().(*types.TypeParam); ok {
- terms, err := typeparams.NormalTerms(tparam.Constraint())
- if err != nil {
- return nil, err
+ terms, err := typeparams.NormalTerms(v.Type()) // NormalTerms works for any type
+ if err != nil {
+ log.Fatalf("internal error: cannot compute type set of loop var %v: %v", v, err)
+ }
+ if len(terms) != 0 {
+ // From the spec (https://go.dev/ref/spec#For_range):
+ // "If the type of the range expression is a type parameter, all
+ // types in its type set must have the same underlying type and the
+ // range expression must be valid for that type."
+ //
+ // Check if all terms have the same underlying type by comparing
+ // them to the first term.
+ u := terms[0].Type().Underlying()
+ // If the constraint has any non-integer terms, skip. (Range over
+ // float is not allowed.)
+ if !isInteger(u) {
+ continue nextLoop
}
- if len(terms) != 0 {
- // Check if all terms have an identical underlying type by
- // comparing them to the first term.
- u := terms[0].Type().Underlying()
- // If the constraint has any non-integer terms, skip. (Range over
- // float is not allowed.)
- if !isInteger(u) {
+ for _, term := range terms[1:] {
+ if !types.Identical(u, term.Type().Underlying()) {
continue nextLoop
}
- for _, term := range terms[1:] {
- if !types.Identical(u, term.Type().Underlying()) {
- continue nextLoop
- }
- }
}
}
```
```
The name of the file: go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go
Insertions: 19, Deletions: 27.
@@ -352,50 +352,42 @@
}
}
-type Integer interface {
- ~int | ~uint
-}
-
-// Regression tests for golang/go#78571: the loop index cannot be a type parameter
-// constrained by multiple distinct integer types.
-func issue78571[I Integer](n I) {
+// Regression tests for golang/go#78571: the loop index cannot be a type
+// parameter constrained by multiple distinct integer types, nor a type
+// parameter constrained by a non-integer type.
+func issue78571[I ~int | ~uint](limit I) {
var i I
- for i = 0; i < n; i++ { // nope: int and uint have different underlying types.
+ for i = 0; i < limit; i++ { // nope: int and uint have different underlying types.
println(i)
}
}
type MyInt int
-type SameUnderlying interface {
- int | MyInt
-}
-
-func issue78571_same[I SameUnderlying](n I) {
- var i I
- for i = 0; i < n; i++ { // want "for loop can be modernized using range over int"
+func issue78571_sameunderlying[T int | MyInt](limit T) {
+ var i T
+ for i = 0; i < limit; i++ { // want "for loop can be modernized using range over int"
println(i)
}
}
-type SingleTerm interface {
- ~int
-}
-
-func issue78571_single[I SingleTerm](n I) {
- var i I
- for i = 0; i < n; i++ { // want "for loop can be modernized using range over int"
+func issue78571_single[T ~int](limit T) {
+ var i T
+ for i = 0; i < limit; i++ { // want "for loop can be modernized using range over int"
println(i)
}
}
-type Float interface {
- ~float64
+func issue78571_float[T ~float64](limit T) {
+ var i T
+ for i = 0; i < limit; i++ { // nope: can't range over a float
+ println(i)
+ }
}
-func issue78571_float[I Float](n I) {
- var i I
- for i = 0; i < n; i++ { // nope: can't range over a float
+func issue78571_floats[T float32 | float64](limit T) {
+ var i T
+ for i = 0; i < limit; i++ { // nope: can't range over a float
println(i)
}
}
```
Change information
Commit message:
go/analysis/passes/modernize: rangeint: handle type parameter constraints
The loop index of a range loop cannot be a type parameter constrained by multiple distinct integer types, nor a type parameter constrained by non-integer types.
This CL updates the rangeint modernizer to detect these cases and avoid suggesting a fix.
It also updates the documentation of typeparams.CoreTypes, whose concept was used in this implementation.
Fixes golang/go#78571
Change-Id: Id897c8f4be80c96cf258b71e7879721339cee7dd
Files:
- M go/analysis/passes/modernize/modernize.go
- M go/analysis/passes/modernize/rangeint.go
- M go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go
- M go/analysis/passes/modernize/testdata/src/rangeint/rangeint.go.golden
- M go/analysis/passes/modernize/unsafefuncs.go
- M internal/typeparams/coretype.go
Change size: M
Delta: 6 files changed, 124 insertions(+), 30 deletions(-)
Branch: refs/heads/master
Submit Requirements:
Code-Review: +2 by Alan Donovan
TryBots-Pass: LUCI-TryBot-Result+1 by Go LUCI