@@ -1387,13 +1387,21 @@ func (f *File) DropRetract(vi VersionInterval) error {
1387
1387
func (f * File ) SortBlocks () {
1388
1388
f .removeDups () // otherwise sorting is unsafe
1389
1389
1390
+ // semanticSortForExcludeVersionV is the Go version (plus leading "v") at which
1391
+ // lines in exclude blocks start to use semantic sort instead of lexicographic sort.
1392
+ // See go.dev/issue/60028.
1393
+ const semanticSortForExcludeVersionV = "v1.21"
1394
+ useSemanticSortForExclude := f .Go != nil && semver .Compare ("v" + f .Go .Version , semanticSortForExcludeVersionV ) >= 0
1395
+
1390
1396
for _ , stmt := range f .Syntax .Stmt {
1391
1397
block , ok := stmt .(* LineBlock )
1392
1398
if ! ok {
1393
1399
continue
1394
1400
}
1395
1401
less := lineLess
1396
- if block .Token [0 ] == "retract" {
1402
+ if block .Token [0 ] == "exclude" && useSemanticSortForExclude {
1403
+ less = lineExcludeLess
1404
+ } else if block .Token [0 ] == "retract" {
1397
1405
less = lineRetractLess
1398
1406
}
1399
1407
sort .SliceStable (block .Line , func (i , j int ) bool {
@@ -1496,6 +1504,22 @@ func lineLess(li, lj *Line) bool {
1496
1504
return len (li .Token ) < len (lj .Token )
1497
1505
}
1498
1506
1507
+ // lineExcludeLess reports whether li should be sorted before lj for lines in
1508
+ // an "exclude" block.
1509
+ func lineExcludeLess (li , lj * Line ) bool {
1510
+ if len (li .Token ) != 2 || len (lj .Token ) != 2 {
1511
+ // Not a known exclude specification.
1512
+ // Fall back to sorting lexicographically.
1513
+ return lineLess (li , lj )
1514
+ }
1515
+ // An exclude specification has two tokens: ModulePath and Version.
1516
+ // Compare module path by string order and version by semver rules.
1517
+ if pi , pj := li .Token [0 ], lj .Token [0 ]; pi != pj {
1518
+ return pi < pj
1519
+ }
1520
+ return semver .Compare (li .Token [1 ], lj .Token [1 ]) < 0
1521
+ }
1522
+
1499
1523
// lineRetractLess returns whether li should be sorted before lj for lines in
1500
1524
// a "retract" block. It treats each line as a version interval. Single versions
1501
1525
// are compared as if they were intervals with the same low and high version.
0 commit comments