I paraphrased that section from this proposal's spiritual predecessor, SE-0445. @lorentey, as the author of that proposal, I'd love to hear if you have anything to add, and whether there was any negative feedback after Swift 6.1 shipped. I'll venture my own justification for why this change is ok:
In places where someone is doing run-time checks such as the one you linked to, it will be in a context where they do not already know what type they are dealing with (or else they would already know whether they could call debugDescription).
In the linked code from Swift Testing, for example, passing an EncodingError or DecodingError currently falls through to the if valueTypeInfo.isSwiftEnumeration { branch, which looks like this:
Here is a snippet of test code to exercise that code path:
enum FooCodingKey: String, CodingKey { case bar }
let error = DecodingError.dataCorrupted(
DecodingError.Context(
codingPath: [FooCodingKey.bar],
debugDescription: "stuff happened here"
)
)
print(String(describingForTest: error))
It prints:
.dataCorrupted(Swift.DecodingError.Context(codingPath: [FooCodingKey(stringValue: "bar", intValue: nil)], debugDescription: "stuff happened here", underlyingError: nil))
After the conformance ships, it would hit the earlier as? any CustomDebugStringConvertible branch, as you point out. The output of the above example would look like this (reminder that the specific details of the output format are subject to change):
Data was corrupted.
Debug description: stuff happened here
Path: bar
If I'm reading this output for while trying to understand a test failure, this seems like a win to me. And, since, the error types in question are public, it is my hope that anyone who cared about the precise value of a particular error would be switching on it directly, rather than relying on its default String.init(describing:) behavior.
Maybe someone is recording a text-based snapshot test to confirm that a particular error is returned? That could result in a spurious test failure when they update the stdlib. But I would lump automated tests into the "this is a feature for debugging" category: it may be annoying to have to re-capture snapshots after updating your toolchain, but it's not going to cause a user-facing crash or bug, and the end result is clearer error messages.
It's true that there should be no surprises within the stdlib, but if any of those dynamic casts are used to produce values that are returned to client code, it's technically possible that it could invalidate some assumption that someone made somewhere. I'd still make the case that any such assumptions are overwhelmingly likely to be in the context of testing or debugging code, and are therefore acceptable.
Part of this review process is to suss out any such cases that might be concerning, so please let me know what you think about the above, and keep the feedback coming!