     ) -> Int {
       let ci = characterMap[i]!
       let cj = characterMap[j]!
+      return cj.offset - ci.offset
+    }
+
+    func referenceScalarDistance(
+      from i: String.Index, to j: String.Index
+    ) -> Int {
       let si = scalarMap[i]!
       let sj = scalarMap[j]!
-      var d = string.distance(from: ci, to: cj)
-      if si < sj {
-        if ci == cj { d = 1 }
-        else if cj < sj { d += 1 }
-      } else if si > sj {
-        if ci == cj { d = -1 }
-        else if ci < si { d -= 1 }
-      }
-      return d
+      return sj.offset - si.offset
     }
 
     for i in allIndices {
       for j in allIndices {
-        let si = scalarMap[i]!
-        let sj = scalarMap[j]!
-
         let characterDistance = referenceCharacterDistance(from: i, to: j)
-        let scalarDistance = string.unicodeScalars.distance(from: si, to: sj)
+        let scalarDistance = referenceScalarDistance(from: i, to: j)
+
+        let substringDistance: Int
+        if i <= j {
+          // The substring `string[i..<j]` does not round its bounds to
+          // `Character` boundaries, so it may have a different count than what
+          // the base string reports.
+          let s = String.UnicodeScalarView(string.unicodeScalars[i ..< j])
+          substringDistance = String(s).count
+        } else {
+          substringDistance = -1
+        }
 
         // Check distance calculations.
         if #available(SwiftStdlib 5.7, *) {

        self.formIndex(after: &j)
      }
      let end = j
      try body(current, self[start ..< end])
    }
  }
}

extension String {
  /// Returns a dictionary mapping each valid index to the index that lies on
  /// the nearest scalar boundary, rounding down.
  func scalarMap() -> [String.Index: (index: String.Index, offset: Int)] {
    var map: [String.Index: (index: String.Index, offset: Int)] = [:]

    self.utf8.forEachIndexGroup(by: self.unicodeScalars) { scalar, slice, offset in
      for i in slice.indices { map[i] = (scalar, offset) }
    }
    self.utf16.forEachIndexGroup(by: self.unicodeScalars) { scalar, slice, offset in
      for i in slice.indices { map[i] = (scalar, offset) }
    }
    self.forEachIndexGroup(by: self.unicodeScalars) { scalar, slice, offset in
      for i in slice.indices { map[i] = (scalar, offset) }
    }
    map[endIndex] = (endIndex, self.unicodeScalars.count)
    return map
  }

  /// Returns a dictionary mapping each valid index to the index that lies on
  /// the nearest character boundary, rounding down.
  func characterMap() -> [String.Index: (index: String.Index, offset: Int)] {
    var map: [String.Index: (index: String.Index, offset: Int)] = [:]
    self.utf8.forEachIndexGroup(by: self) { char, slice, offset in
      for i in slice.indices { map[i] = (char, offset) }
    }
    self.utf16.forEachIndexGroup(by: self) { char, slice, offset in
      for i in slice.indices { map[i] = (char, offset) }
    }
    self.unicodeScalars.forEachIndexGroup(by: self) { char, slice, offset in
      for i in slice.indices { map[i] = (char, offset) }
    }
    map[endIndex] = (endIndex, count)
    return map
  }
}

StringIndexTests.test("Extra Exhaustive Index Interchange") {
  guard #available(SwiftStdlib 5.7, *) else {
    // Index navigation in 5.7 always rounds input indices down to the nearest
    // Character, so that we always have a well-defined distance between
    // indices, even if they aren't valid.
    //
    // 5.6 and below did not behave consistently in this case.
    return
  }

  func check(
    _ string: String,
    stackTrace: SourceLocStack = SourceLocStack(),
