Skip to content

Commit 4c74101

Browse files
authored
FS-1146-scoped-nowarn RFC proposal
2 parents 4f2a62a + 14f9f7d commit 4c74101

File tree

1 file changed

+250
-0
lines changed

1 file changed

+250
-0
lines changed

RFCs/FS-1146-scoped-nowarn.md

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
# F# RFC FS-1146-scoped-nowarn
2+
3+
The design suggestion [278](https://github.com/fsharp/fslang-suggestions/issues/278) has been marked "approved in principle".
4+
5+
This RFC covers the detailed proposal for this suggestion.
6+
7+
- [x] [Suggestion](https://github.com/fsharp/fslang-suggestions/issues/278)
8+
- [x] Approved in principle
9+
- [x] [Implementation](https://github.com/dotnet/fsharp/pull/18049)
10+
- [x] [Discussion](https://github.com/fsharp/fslang-design/discussions/786)
11+
12+
# Summary
13+
14+
Allow the #nowarn directive to become scoped (per warning number) by a corresponding #warnon directive.
15+
16+
# Motivation
17+
18+
Today, the #nowarn directive disables the specified warnings for all code from the directive to the end of the file. Usually, however, people want to see all warnings except for some very specific situations. Therefore, a way to disable warnings for some fragment of the code is a much-requested feature.
19+
20+
Quotes form the language suggestion thread:
21+
22+
- "being able to nowarn a few lines is most critical for my workplace"
23+
- "it would be huge if we could get this"
24+
- "it would be great to do only small sections that we know we want to ignore rather than the whole file"
25+
26+
Motivating examples, again from the suggestion thread:
27+
28+
```
29+
// We know f is never called with a None.
30+
let f (Some a) = // creates warning 25, which we want to suppress
31+
// 2000 loc, where the incomplete match warning is beneficial
32+
```
33+
34+
```
35+
// We have a union with an obsolete case
36+
type MyErrors =
37+
| CoolError1 of CoolError1
38+
| CoolError2 of CoolError2
39+
| [<Obsolete>] OldError1 of OldError1
40+
41+
let handler e =
42+
match e with
43+
| CoolError1 ce -> ...
44+
| CoolError2 ce -> ...
45+
| OldError ce -> ... // warning 44, which we want to suppress only here
46+
```
47+
48+
# Detailed specification
49+
50+
1. The compiler shall recognize a new "warnon" *compiler directive* (to be added to §12.4 of the F# spec).
51+
52+
So, F# has now two *warn directives*: "nowarn" and "warnon".
53+
54+
2. A warn directive is a single line of source code that consists of
55+
- Optional leading whitespace
56+
- The string `#nowarn` or `#warnon`
57+
- Whitespace
58+
- One or more arguments, separated by whitespace, in one of the formats specified by RFC-1147 (integer warning number, `FS` followed by an integer warning number, both optionally surrounded by double quotes)
59+
- Optional whitespace
60+
- Optional line comment
61+
- Newline
62+
63+
> *Note:* See the [Compatibility](#compatibility) section below for some consequences.
64+
65+
66+
3. In the following, we use the term NOWARN for a `#nowarn` directive for a certain warning number. Similarly, we use WARNON for a `#warnon` with the same warning number.
67+
68+
- NOWARN and WARNON shall disable/enable the warning until eof or a corresponding WARNON / NOWARN
69+
70+
- Compiler defaults (system defaults and compiler flags) shall be valid outside of scopes defined by
71+
- NOWARN - WARNON pairs
72+
- WARNON - NOWARN pairs
73+
- NOWARN and eof
74+
- WARNON and eof
75+
76+
where these pairs are identified by scanning the file linearly.
77+
78+
- [Alternatives](#alternatives) have been considered but dismissed.
79+
80+
4. The current definition "*Compiler directives are declarations in non-nested modules or namespace declaration groups*" (§12.4) shall be relaxed for `#nowarn` and `#warnon`.
81+
82+
These directives now can appear also inside modules anywhere on a separate single line.
83+
84+
The style guide shall recommend the same indentation as the following line (for an opening directive) or previous line (for a closing directive).
85+
86+
"Multi-line" #nowarn directives (possible with the current compiler) shall no longer be accepted.
87+
88+
Warning 236 shall no longer be issued.
89+
90+
5. All of the above rules shall be valid for `.fs` source files, `.fsi` signature files, `.fsx` script files and shall also be reflected in the compiler service.
91+
92+
> *Note:* This leads to some breaking changes as described in the [Compatibility](#compatibility) section below.
93+
94+
6. For the interactive `fsi` REPL, the warn directives shall be processed across all interactions.
95+
96+
7. The warn directives shall be processed independently of any `#line` directives (§3.9 of the spec).
97+
98+
The warn directives shall work only against the actual source file being compiled, the #line directive shall only impact the file and line number of error messages. For nowarn they are irrelevant.
99+
100+
> *Note:* The interaction of `#nowarn` and `#line` directives is not specified in the F# spec.
101+
Due to the way the #line directives are implemented in the compiler, the new specification can be reliably implemented only if the same #line target file is not targeted from multiple source files. This should, however, not be a significant limitation.
102+
103+
### Examples:
104+
105+
```
106+
module A
107+
match None with None -> () // warning
108+
let x =
109+
#nowarn 25
110+
match None with None -> 1 // no warning
111+
#warnon 25
112+
match None with None -> () // warning
113+
#nowarn 25
114+
match None with None -> () // no warning
115+
```
116+
117+
# Drawbacks
118+
119+
Again more logic to maintain in the compiler.
120+
121+
# Alternatives
122+
123+
## Functionality
124+
125+
The following alternatives have been considered in terms of functionality (item 3 of the [Detailed Specification](#detailed-specification) section).
126+
127+
Alternative 1
128+
- NOWARN and WARNON disable/enable the warning until a corresponding WARNON / NOWARN
129+
- Compiler defaults (system defaults and compiler flags) shall be valid outside of scopes defined by
130+
- NOWARN - WARNON pairs
131+
- WARNON - NOWARN pairs
132+
133+
Alternative 2
134+
- NOWARN and WARNON disable/enable the warning
135+
- Defaults are valid from the beginning of the file to the first NOWARN or WARNON
136+
137+
Alternative 3
138+
- NOWARN disables the warning (independent of the defaults), until eof or a WARNON
139+
- WARNON is allowed only after a NOWARN and restores the defaults for the warning
140+
141+
Alternative 1 would have been nice and simple, but is not backwards compatible.
142+
143+
Alternative 2 has no way of going back to the default settings.
144+
145+
Alternative 3 is not symmetrical and therefore more difficult to learn.
146+
147+
148+
## Script files
149+
150+
Item 5 of the [Detailed Specification](#detailed-specification) section extends the new functionality to script files, thereby introducing a breaking change. Alternatively, we could disallow `#warnon` for script files. Or define rules for `#warnon` before the `#nowarn` that are different from the rules for `.fs` source files and necessarily complicated.
151+
152+
153+
# Compatibility
154+
155+
Warn scopes will be introduced under a feature flag.
156+
When the feature flag is off (for earlier language versions), `#nowarn` will work as before (with the exceptions mentioned below) and `#warnon` will produce an error (see the [Diagnostics](#diagnostics) section below).
157+
158+
## Fixes that can affect old code when compiled with the new compiler, feature flag off
159+
160+
a) There were a following inconsistencies in the previous behavior that cannot easily be replicated with the new code or that are just being fixed now.
161+
162+
- Multiline and empty warn directives are no longer allowed
163+
- Whitespace between the hash character and the `nowarn` is no longer allowed.
164+
- Simple string warning numbers continue to be valid, but no triple quoted, interpolated or verbatim strings.
165+
- Some invalid arguments used to be ignored. They now produce warnings.
166+
- Two nowarn directives for the same warning number, without a warnon directive inbetween, produce a warning.
167+
168+
```
169+
#nowarn 25 // valid (was valid before)
170+
#nowarn "25" // valid (was valid before)
171+
#nowarn "FS0025" // valid (was valid before)
172+
#nowarn FS25 // valid (was valid before)
173+
#nowarn // error (was allowed before)
174+
25
175+
#nowarn // error (was allowed before)
176+
# nowarn 25 // error (was allowed before)
177+
#nowarn """25""" // error (was allowed before)
178+
#nowarn $"25" // error (was error before)
179+
#nowarn @"25" // error (was allowed before)
180+
#nowarn "FS0xy" // error (was error before)
181+
#nowarn "FSxy" // error (was ignored before)
182+
#nowarn 0xy // error (was error before)
183+
#nowarn "0xy" // error (was warning before)
184+
#nowarn xy // error (was ignored before)
185+
#nowarn 20 // valid (was valid before)
186+
#warnon 20 // error (for old langversion only) (was ignored before) (see d) below)
187+
#nowarn 20 // valid (was valid before)
188+
#nowarn 20 // warning (in the context of the previous line) (was valid before)
189+
```
190+
191+
b) Previously, when using the compiler proper (fsc), a `#nowarn` correctly disables warnings from that directive until end of file. The compiler service (as used by the IDEs), however, considers a `#nowarn` anywhere in a file as valid everywhere in this file. We consider the latter a bug that will be fixed so that the IDEs display the same warnings as the compiler.
192+
193+
194+
```
195+
"" // warning 20 when compiled, but no squiggles in the IDE
196+
#nowarn 20
197+
```
198+
199+
c) The interaction with #line directives might in rare cases now correctly suppress a warning that was visible before.
200+
201+
d) Previously, any accidental `#warnon` directive in the code was an unknown hash directive and as such ignored. With the new compiler and "-langversion=9.0", it will produce a "new feature" error (see the [Diagnostics](#diagnostics) section below).
202+
203+
204+
## Additional changes that can affect old code when compiled as F# 10
205+
206+
e) Previously, a `#nowarn` anywhere in a script file affected *the whole compilation*. As from F# 10, this will no longer be the case. Warn directives in scripts will now work as specified in this RFC, in the same way as in ".fs" files. This is a breaking change, see also the [Alternatives](#alternatives) section above.
207+
208+
f) Previously, any accidental `#warnon` directive in the code was an unknown hash directive and as such ignored. Now it will have an effect and might produce errors.
209+
210+
211+
## Binary compatibility
212+
213+
Since warnings are a compile time feature, there is no binary compatibility issue.
214+
215+
216+
# Pragmatics
217+
218+
## Diagnostics
219+
220+
Today there are no warnings for empty or repeated `#nowarn` directives (or only in very specific situations). Most invalid arguments are ignored.
221+
222+
With the new feature, there shall be errors for all syntactically invalid directives. See also the [Compatibility](#compatibility) section above.
223+
224+
Warn directives shall under earlier language versions continue to produce warning 236 if used inside a sub-module.
225+
226+
Use of the new `#warnon` directive under earlier language versions shall produce error 3350 (language feature error).
227+
228+
## Tooling
229+
230+
Tooling (fsac, vs, fantomas) will need to adapt to correctly color the warn directives.
231+
232+
More tools might be affected by the changes in the compiler service surface area.
233+
234+
235+
## Performance and Scaling
236+
237+
No performance and scaling impact is expected.
238+
239+
## Culture-aware formatting/parsing
240+
241+
There is no interaction with culture-aware formatting and parsing of numbers, dates and currencies.
242+
243+
244+
## Documentation
245+
246+
In the ["Line Directives" section](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/compiler-directives#line-directives) of the language reference, an additional paragraph on the interaction between line and nowarn/warnon directives should be inserted.
247+
248+
In the ["Preprocessor Directives"](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/compiler-directives#preprocessor-directives) section, the `#nowarn` entry should be extended to include `#warnon` and the functionality defined in this RFC. For the interaction with the `#line` directive, the "Line Directives" section should be referenced. Finally, the text should be updated to reflect RFC FS-1147.
249+
250+
In the [F# code formatting guidelines](https://learn.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting), the recommendation of the above Detailed Specification, item 4, should be added.

0 commit comments

Comments
 (0)