Closed
Description
Go version
x/tools/gopls v0.18.1
Output of go env
in your module/workspace:
irrelevant
What did you do?
This program prints 1, 2, 3 4:
func main() {
s := []int{1, 2, 3}
for i := 0; i < len(s); i++ {
fmt.Println(s[i])
if s[i] == 2 {
s = append(s, 4)
}
}
}
What did you see happen?
Gopls wants to modernize the for loop to for i := range len(s)
.
Since the range expression is evaluated only once instead of each time through the loop, the semantics change, and the program prints 1, 2 3.
What did you expect to see?
Behavior unchanged.
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
adonovan commentedon Mar 18, 2025
Thanks for reporting. (Curious: was this an encountered bug or an a priori deduction?)
Pretty much all our uses of equalSyntax in modernizers have some kind of exploitable edge case like this. Depending on how strict we want to be about aliasing and side effects, we may need to downgrade a number of modernizers if we are to achieve our goal of "first do no harm". Seeing how many subtle bugs we have had so far even among the easy cases, I am starting to wonder whether (continuing the medical analogy) modernizers are mere cosmetic surgery, a procedure of no medical benefit that is not without risk, and whether batch modernization is ever something we should recommend.
The benefits may be clearer in cases of interactive modernization, when the user is already critically studying the code (to stretch the metaphor, a form of informed consent), or in the LLM-inference feedback loop, where the user has indicated a penchant for backstreet brain surgery. ;-)
[-]x/tools/gopls/internal/analysis/modernize: a three-way for loop with changes in the loop body cannot be changed to a range[/-][+]x/tools/gopls/internal/analysis/modernize: rangeint: transformation unsound when loop body has effects on iterated array[/+]jba commentedon Mar 18, 2025
Found it during actual use.
findleyr commentedon Mar 19, 2025
Milestoning for next minor.
adonovan commentedon Mar 19, 2025
This bug caused a bad transformation in the regexp package too:
Fortunately it was caught by tests.
9 remaining items