SE-0196 — Compiler Diagnostic Directives


(Jordan Rose) #28

The recommended way to do call-site / use-site warnings today is deprecation: @available(*, deprecated, message="Uh oh!"). It is a bit verbose, I admit, and some people have mentioned wanting to have a way to produce warnings that don’t say “deprecated”, but those are both improvements that should be independent of Harlan’s proposal.


(Matthew Johnson) #29

@AlexanderM that could be accomplished if #warning and #error accepted file and line arguments in addition to the message argument.

// produces a warning with the specified `message` at the site specified by `file` and `line`
// and returns a value if specified, calling fatalError if no value was provided
func TODO<T>(_ value: T? = nil, _ message: StaticString? = nil, file: StaticString = #file, line: UInt = #line) -> T {
    #warning(message ?? "TODO", file: file, line: line)
    if let value = value {
        return value
    } else {
        fatalError()
    }
}

This is the kind of flexibility I would like to see. It allows us to define our own warning-producing functions. I’m not sure how feasible implementation of this exact mechanism would be, however.


(Michał Kałużny) #30

I’m very much in favour of adding #warning and #error directives, preferably with message in parenthesis. I’m intrigued by the idea of runtime warnings, not sure if errors should also be available in such mode. One concern I have though is the syntax, currently runtime directives use @directive, should we implement runtime warnings shouldn’t they use @warning too?


(Alexander Momchilov) #31

I think I already outlined the purpose: Having #fixme and #todo as separate can allow the compiler’s response to them to be customization using flags, similar to SWIFT_TREAT_WARNINGS_AS_ERRORS.

Furthermore, there are #warnings that aren’t #TODO or #FIXME related. We should make a distinction between them, even if a programmer ultimately sets the compiler to treat all 3 as just warnings.


(Alexander Momchilov) #32

Wouldn’t that require some form of StaticInt? The line would have to guaranteed to be known at compile time.


(Matthew Johnson) #33

@jrose I had forgotten that a message argument was available on @available. But it is odd for a function that isn’t really deprecated to have to specify itself as deprecated. This also does not allow the warning message to be customized by the call site which also seems very useful.

I described the behavior I would like to see in a code in a previous post. I suspect that the exact mechanism I described may not be workable but I hope something similar might be possible. I think it is very relevant to the discussion of this proposal even if the result is that it ends up being an alternative or a future direction.


(Adrian Zubarev) #34

I see your point there, but I still have the impression that this still would require tooling support for a different set of messages. Don’t get me wrong, I’d love to see a set of fix-me’s, todo’s and warnings in Xcode sorted and differentiated whether those were at compile time or at runtime. However this makes this proposal much more complex and the probability of it’s success is lowered. Furthermore it requires a full implementation as well.

I think we should keep it simple but keep the door open for more. ;) On the other hand if there is someone who can implement all that, then forget my concerns and go for it.


(Matthew Johnson) #35

Yes, it would probably need something like that. That’s why I hedged on the exact mechanism. I expect it would need to look a little bit different. My goal is to demonstrate the kind of function I would like to be able to write.


(Alexander Momchilov) #36

I’d have to look into it in more detail, but it doesn’t seem that difficult
Here’s what the proposal says about the behaviour of #warning and #error:

Upon parsing a #error directive, the Swift compiler will emit the provided string literal as an error, pointing to the beginning of the string, and ignore the directive.

Upon parsing a #warning directive, the Swift compiler will emit the provided string literal as a warning, pointing to the beginning of the string, and ignore the directive.

#todo aren’t that much harder (same applied for #fixme):

Upon parsing a #todo directive, the Swift compiler will consult the compiler flag for the treatment of #todo, and either do nothing, or emit the provided string literal as a warning or as an error, pointing to the beginning of the string, and ignore the directive.


(Erica Sadun) #37

I vote yes. We’ve talked about this for years. This is the right direction for Swift, useful on both its own merits and widely used elsewhere. In terms of naming, both #warning and #error are simple and obvious.

The proposed syntax looks out of step with other build directives. It doesn’t feel Swifty without parentheses. I see I am not alone in this preference.

With regard to feedback about #message, I see no reason to include both warnings and messages. The set of #warning and #error is sufficient in my mind, creating a minimal additive change. Unifying them into a single directive differentiating #emit("warning", "text") and #emit("error", "text") is roughly 500% uglier than #warning and #error, but it would allow future expansion to "message" if that direction would ever arise.

I am hesitant to co-mingle run-time and build-time uses of #warning. Something like nonfatalWarning(_ message: String = "#file:#line warning") or similar could parallel fatalError. (I’m not sure it would add value, but I’d like to throw this into the mix if run-time is a real concern.)

Please be clear about whether the directives should be leveled to permit or exclude suppression by compiler “hide warnings” options. For example, #warning("This must be implemented before deployment", ignoreWarningSuppression) or something like that would allow overriding the compiler flags for SPM and other source code sources.


(James Froggatt) #38

This problem partly ties in with compile-time functions. It would be interesting if the method of denoting such functions were to prefix the name with #.


(Alejandro Martinez) #39

I’m in favour of adding this directives but as it has been mentioned already I would prefer the syntax to include parenthesis. Not only that but I would like to see it accepting file and line parameters, with automatic default values. That would allow people to define custom functions like TODO/FIXME that behave as they want. @anandabits TODO example is a good one.
This would give an expected default behaviour as we have in other languages but would add the flexibility of defining user level warnings without adding more burden on the compiler. This is usually done at the moment with some scripts but I feel that this solution would be much nicer.


(David Beck) #40

What is your evaluation of the proposal?

Strong +1

Is the problem being addressed significant enough to warrant a change to Swift?

Yes. When it’s needed, there is simply no good alternative other than build scripts such as XcodeIssueGenerator.

Does this proposal fit well with the feel and direction of Swift?

I think there is a need to really lay out what the future of Swift precompiled directives are going to look like, but this certainly matches what we currently have.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

I currently use XcodeIssueGenerator to call out warnings and TODOs. This doesn’t cover a library that conditionally creates a compiler error when it is used in the wrong context though.


(Jarod Long) #41

What is your evaluation of the proposal?

+1, I’ve always wanted a #warning directive in Swift.

Is the problem being addressed significant enough to warrant a change to Swift?

Yes. There are workarounds, but imo they’re cumbersome enough to make this feature important.

The workaround I’ve used is to define a global TODO symbol that’s flagged as deprecated, so you can reference that symbol to produce a warning. However, this can only be used on lines where a standalone expression is supported, i.e. inside a function body, which is quite limiting. Also, the deprecation warning is semantically incorrect as mentioned above, and you can’t specify a message at the call site. #warning doesn’t have any of these limitations.

The other workaround I know of is to use a build script to surface TODO comments as warnings, but it’s cumbersome to set this up in every project, and it feels like a hack. Having something standardized and built-in would be very helpful.

Does this proposal fit well with the feel and direction of Swift?

I think it does.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

It’s basically the same as #warning / #error in ObjC, which worked well imo.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read the full proposal and skimmed the discussion.


(Michael Ilseman) #42

Did you consider a #assert, which would be an equivalent of C++'s static_assert? That could also tip the balance towards explicit parenthesis.


(Harlan Haskins) #43

That could be cool for mutually exclusive build configurations, but if we added #assert, I’d want constexpr 😈


(David Moore) #44

What is your evaluation of the proposal?

Adding these directives to the Swift compiler will be an excellent addition that has a number of particularly handy use cases. Definitely +1 on this.

Is the problem being addressed significant enough to warrant a change to Swift?

Although this might not be a necessarily essential feature, it’s definitely a helpful one that’ll hopefully improve code readability and review.

Does this proposal fit well with the feel and direction of Swift?

Since this is a compiler directive there isn’t necessarily a Swifty feel to it, but that is to be expected with such a feature. However, that being said, it does fit in well with the feel and direction of existing Swift compiler directives.

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

This is very similar to #pragma when using Clang (i.e., Objective-C, C++, etc…), so it should be intuitive for developers coming from those languages. It also improves on that syntax by using appropriate language that explicitly describes the purpose of the directive.

How much effort did you put into your review?

I read the entire proposal, in addition to the evolution discussion, and was very excited as this is something that I’ve felt Swift was missing.


(Nathan Gray) #45

+1

This is a small but significant improvement that will be useful in a variety of contexts. The proposed syntax seems fine to me.


(Paul Kirvan) #46

Oh we know. In Swift as it currently exists you can make an error just by typing ljkhhkljahlkh on the line you want the error to be. Sometimes out of desperation I do just that. However, that doesn’t cover the usage case of wanting a warning, not an error, so that I can compile and test other things in the mean time. This proposal also offers a much more professional looking way to get the error. 😀


(Ted Kremenek) #47

Review accepted with slight revision

On February 1, 2018 the Core Team decided to accept this proposal with slight revision over the original proposal.

The only revision over the original proposal is to change the syntax to use #warning(<Message>) instead of #warning <Messsage>. This fits well with most of Swift’s existing compiler directives, and was strongly supported in the review discussion.

The review discussion also covered a variety of possible extensions or variants to this proposal, including support for using #warning as an expression instead of a line directive and support for runtime issues. The Core Team decided that while these directions are interesting and worth exploring, they are complementary to the core functionality serviced by this proposal. Further, keeping #warning as a line directive allows it to be used in a wide variety of contexts, and serves a different need than using it as a placeholder expression.


Accepted: SE-0196 — Compiler Diagnostic Directives