Hey all,
SE-0443 introduced diagnostic groups, which have many similarities with educational notes: they tag specific diagnostics produced by the compiler and associate documentation with them. I've been aligning the implementation scheme for these features so that the documentation for a diagnostic group is available in the same way as an educational note.
I've also been thinking about the user experience on the command line: how can we help users find the documentation we write for diagnostics? The compiler currently has -print-diagnostic-groups
, which prints the name of a diagnostic group in square brackets at the end of the message, e.g.,
t.swift:2:7: warning: expression uses unsafe constructs but is not marked with 'unsafe' [StrictMemorySafety]
That's useful, but you need to know that [StrictMemorySafety]
means it's a diagnostic group, and then go hunting in the toolchain for the corresponding strict-memory-safety.md
.
The compiler also has a hidden -print-educational-notes
, which renders the Markdown for educational notes into the terminal:
t.swift:2:1: error: non-nominal type 'Crap' (aka '() -> ()') cannot be extended
extension Crap {}
^ ~~~~
Nominal Types
In Swift, a type is considered a nominal type if it has been explicitly named by a declaration somewhere in code. Examples of nominal types include classes, structures and enumerations. Nominal types are an important concept in Swift because they may conform to protocols, be extended, and have values created using the initializer syntax 'MyType()'.
In contrast, non-nominal types do not have these capabilities. Many are obtained by composing other types. Examples include function types like '(Int) -> (String)', tuple types like '(Int, String)', metatypes like 'Int.Type', and special types like 'Any' and 'AnyObject'.
Since a protocol is named by a declaration in code, it may conform to (in other words, refine) other protocols and it may be extended. However, when written as the type of a constant or variable such as 'let value: MyProtocol', the name refers to a distinct, non-nominal existential type that provides a “box” for a value of any concrete type that conforms to the protocol. The existential type itself does not conform to any protocols and cannot be extended, and a value cannot be created using the initializer syntax 'MyProtocol()'.
For more on using existential types, see [Protocols as Types](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID275) in The Swift Programming Language.
This provides the documentation, but: it's quite verbose, the terminal isn't necessarily the best place to read this documentation, and you likely don't want to see this most of the time.
In both cases, you have to find the flag to turn it on. I think we can do a lot better for our users here!
I suggest that, by default, we print the diagnostic group name or educational note name in brackets with a leading #
to imply that it's a reference. Then, at the end of the compile, provide links to the documentation for each of the diagnostic groups or educational notes that were referenced in any diagnostic above. The result could look like this:
t.swift:2:7: warning: expression uses unsafe constructs but is not marked with 'unsafe' [#StrictMemorySafety]
1 | func somethingUnsafe(x: Int) {
2 | _ = UnsafeRawPointer(bitPattern: x)
| |- warning: expression uses unsafe constructs but is not marked with 'unsafe' [^StrictMemorySafety]
| |- note: reference to unsafe type 'UnsafeRawPointer'
| |- note: reference to initializer 'init(bitPattern:)' involves unsafe type 'UnsafeRawPointer'
| `- note: @unsafe conformance of 'UnsafeRawPointer' to protocol '_Pointer' involves unsafe code
3 | }
4 |
[#StrictMemorySafety]: /path/to/swift/toolchain/share/doc/swift/diagnostics/strict-memory-safety.md
For terminals that support it, we could make the [#StrictMemorySafety]
a hyperlink to the markdown file and elide the footnotes at the end.
We could also consider rendering the markdown into HTML in the toolchain (as part of the install process), so we're not dependent on the user having a nice way to view markdown files by default.
What do y'all think? Does this hit the right balance between discoverability and verbosity? What could we do better?
Doug