Skip to content

Commit 7d2ae4e

Browse files
committed
burp
1 parent 78c8b36 commit 7d2ae4e

File tree

1 file changed

+335
-0
lines changed

1 file changed

+335
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
# Adoption tooling for Swift features
2+
3+
* Proposal: [SE-NNNN](NNNN-filename.md)
4+
* Authors: [Anthony Latsis](https://github.com/AnthonyLatsis)
5+
* Review Manager: TBD
6+
* Status: **Awaiting implementation**
7+
* Implementation: TBD
8+
* Review: TBD
9+
10+
## Introduction
11+
12+
The future we envision for Swift will take many more valiant evolutionary
13+
decisions and major transformations with a proportional impact on its
14+
expanding domains.
15+
16+
Source-breaking changes to Swift were first staged behind the now obsolete
17+
Swift 3 language mode.
18+
Each successive major release has since included a correponding language mode,
19+
using the previous language mode as the default to maximize source
20+
compatibility.
21+
For example, Swift 6 compilers operate in the Swift 5 language mode by default.
22+
Users that are not ready to adopt the new default can still specify an earlier
23+
language mode explicitly.
24+
Once the time is right, old language modes together with the legacy behaviors
25+
they manifest will be proposed to be deprecated.
26+
27+
The cumulative source compatibility impact of the changes that were accreting
28+
around a converging Swift 6 language mode gave rise to the
29+
[Swift feature model][SE-0362], which enabled piecemeal adoption of individual
30+
features as opposed to an entire language mode.
31+
Upcoming features facilitated sooner adoption of improvements and drastically
32+
reduced the pressures in our evolutionary model.
33+
34+
This proposal centers seeks to improve the experience of adopting individual
35+
features.
36+
The proposition is that the growing complexity and diversification of Swift
37+
calls for a flexible, integrated mechanism for supporting quality assistance
38+
with feature adoption.
39+
And that — in principle — comprehensive, code-aware assistance can be delivered
40+
without breaking source and acted upon incrementally.
41+
42+
## Motivation
43+
44+
Whether you are adjusting code to follow new language rules or researching ways
45+
to apply new functionality, adopting features can be a time-consuming endeavor
46+
at the least.
47+
48+
Some source-breaking language features are anticipated to generate hundreds
49+
of targeted errors in sizable projects.
50+
Occasionally, errors will also cascade down the dependecy graph or fall out
51+
from changes in behavior without a clear indication of the precise cause or source of
52+
the issue, requiring further investigation.
53+
Developers are left to either resolve all of these errors or address a subset
54+
and take the risk of switching the feature back off before they can resume
55+
development and focus on other important tasks.
56+
57+
### User Intent
58+
59+
> [!CAUTION]
60+
> TODO: No way for users to declare an intetion to adopt a feature
61+
62+
### Automation
63+
64+
Many existing and prospective upcoming features imply or implement simple and
65+
consistent code modifications to facilitate the adoption process:
66+
67+
* [`NonfrozenEnumExhaustivity`][SE-0192]: Restore exhaustivity with
68+
`@unknown default:`.
69+
* [`ConciseMagicFile`][SE-0274]: `#file``#filePath`.
70+
* [`ForwardTrailingClosures`][SE-0286]: Disambiguate argument matching by
71+
de-trailing closures and/or inlining default arguments.
72+
* [`ExistentialAny`][SE-0335]: `P``any P`.
73+
* [`ImplicitOpenExistentials`][SE-0352]: Suppress opening with `as any P`
74+
coercions.
75+
* [`BareSlashRegexLiterals`][SE-0354]: Disambiguate using parentheses,
76+
e.g. `foo(/a, b/)``foo((/a), b/)`.
77+
* [`DeprecateApplicationMain`][SE-0383]: `@UIApplicationMain``@main`,
78+
`@NSApplicationMain``@main`.
79+
* [`DisableOutwardActorInference`][SE-0401]: Specify global actor isolation
80+
explicitly.
81+
* [`InternalImportsByDefault`][SE-0409]: `import X``public import X`.
82+
* [`GlobalConcurrency`][SE-0412]:
83+
- Convert the global variable to a `let` (or)
84+
- `@MainActor`-isolate it (or)
85+
- Mark it with `nonisolated(unsafe)`
86+
* [`MemberImportVisibility`][SE-0444]: Add explicit imports appropriately.
87+
* [`InferSendableFromCaptures`][SE-0418]: Suppress inference with coercions
88+
and type annotations.
89+
* [Inherit isolation by default for async functions][async-inherit-isolation-pitch]:
90+
Mark nonisolated functions with the proposed attribute.
91+
92+
Feature
93+
94+
Extending diagnostic metadata to include information that allows for
95+
recognizing these diagnostics and distinguishing semantics-preserving fix-its
96+
from alternative source changes would open up numerous opportunities for
97+
higher-level tools — ranging from the Swift package manager to IDEs — to
98+
implement powerful solutions for organizing, automating, and tuning code
99+
migration processes.
100+
101+
### Flexibility/Ergonomics
102+
103+
> [!CAUTION]
104+
> Still a draft.
105+
106+
Although upcoming features should strive to facilitate code migration,
107+
108+
language design principles may prevail over bespoke code migration solutions.
109+
Some features, like [StrictConcurrency][SE-0337], inherently require user
110+
intervetion
111+
112+
Adjusting to new behaviors or language requirements can demand research,
113+
careful consideration, coordinated efforts, and manual code refactorings,
114+
sometimes on a case-by-case basis.
115+
116+
Currently best solution is to implement custom staging solutions. This approach
117+
has limited applications (why?).
118+
119+
UPCOMING_FEATURE(DynamicActorIsolation, 423, 6)
120+
UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6)
121+
UPCOMING_FEATURE(StrictConcurrency, 0337, 6)
122+
UPCOMING_FEATURE(IsolatedDefaultValues, 411, 6)
123+
UPCOMING_FEATURE(RegionBasedIsolation, 414, 6)
124+
125+
## Proposed solution
126+
127+
Introduce the notion of a "adoption" mode for individual experimental and
128+
upcoming features.
129+
The core idea behind adoption mode is a declaration of intent that can be
130+
leveraged to build holistic supportive adoption experiences for developers.
131+
If enabling a feature communicates an intent to *enact* rules, adoption mode
132+
communicates an intent to *adopt* them.
133+
An immediate benefit of adoption mode is the capability to deliver source
134+
modifications that can be applied to preserve or improve the behavior of
135+
existing code whenever the feature provides for them.
136+
137+
> [!NOTE]
138+
> The subject of this proposal is an enhancement to the Swift feature model.
139+
> Applications of adoption mode to existing features are beyond its scope.
140+
141+
## Detailed design
142+
143+
### Behavior
144+
145+
The action of enabling a previously disabled source-breaking feature in adoption
146+
mode per se must never produce compilation errors.
147+
Additionally, this action will have no effect on the state of the feature if
148+
it does not implement the mode.
149+
A corresponding warning will be emitted in this case to avoid the false
150+
impression that the impacted source code is compatible with the feature.
151+
152+
> [!NOTE]
153+
> Experimental features can be both additive and source-breaking.
154+
> Upcoming features are necessarily source-breaking.
155+
156+
adoption mode will deliver guidance in the shape of warnings, notes, remarks,
157+
and fix-its, as and when appropriate.
158+
159+
When implemented, adoption mode for upcoming features is expected to anticipate
160+
and call out any behavioral differences that will result from enacting the
161+
feature, coupling diagnostic messages with counteracting source-compatible
162+
changes and helpful alternatives whenever possible.
163+
Adoption mode cannot guarantee to provide exclusively source-compatible
164+
modifications because the impact of a change on dependent source code is
165+
generally unpredictable.
166+
Neither can it promise to always offer fix-its in the first place for the
167+
same reason in regards to user intention.
168+
169+
### Interface
170+
171+
#### Compiler
172+
173+
The `-enable-*-feature` frontend and driver command line options will start
174+
supporting an optional mode specifier with `adoption` as the only valid mode:
175+
176+
```
177+
-enable-upcoming-feature <feature>[:<mode>]
178+
-enable-experimental-feature <feature>[:<mode>]
179+
180+
<mode> := adoption
181+
```
182+
183+
For example:
184+
185+
```
186+
-enable-upcoming-feature InternalImportsByDefault:adoption
187+
```
188+
189+
In a series of either of these options applied to a given feature, only the
190+
last option will be honored.
191+
If an upcoming feature is both implied by the effective language mode and
192+
enabled in adoption mode using either of the aforementioned options, the latter
193+
will be disregarded.
194+
195+
#### Swift package manager
196+
197+
The [`SwiftSetting.enableUpcomingFeature`] and
198+
[`SwiftSetting.enableExperimentalFeature`] methods from the
199+
[`PackageDescription`](https://developer.apple.com/documentation/packagedescription)
200+
library will be augmented with a `mode` parameter defaulted to match the
201+
current behavior:
202+
203+
```swift
204+
extension SwiftSetting {
205+
@available(_PackageDescription, introduced: 6.2)
206+
public enum SwiftFeatureMode {
207+
case adoption
208+
case on
209+
}
210+
}
211+
```
212+
```diff
213+
public static func enableUpcomingFeature(
214+
_ name: String,
215+
+ mode: SwiftFeatureMode = .on,
216+
_ condition: BuildSettingCondition? = nil
217+
) -> SwiftSetting {
218+
+ let argument = switch mode {
219+
+ case .adoption: "\(name):adoption"
220+
+ case .mode: name
221+
+ }
222+
+
223+
return SwiftSetting(
224+
- name: "enableUpcomingFeature", value: [name], condition: condition)
225+
+ name: "enableUpcomingFeature", value: [argument], condition: condition)
226+
}
227+
```
228+
```diff
229+
public static func enableExperimentalFeature(
230+
_ name: String,
231+
+ mode: SwiftFeatureMode = .on,
232+
_ condition: BuildSettingCondition? = nil
233+
) -> SwiftSetting {
234+
+ let argument = switch mode {
235+
+ case .adoption: "\(name):adoption"
236+
+ case .mode: name
237+
+ }
238+
+
239+
return SwiftSetting(
240+
- name: "enableExperimentalFeature", value: [name], condition: condition)
241+
+ name: "enableExperimentalFeature", value: [argument], condition: condition)
242+
}
243+
```
244+
245+
For example:
246+
247+
```
248+
SwiftSetting.enableUpcomingFeature("InternalImportsByDefault", mode: .adoption)
249+
```
250+
251+
### Diagnostics
252+
253+
Diagnostics emitted in relation to a specific feature in adoption mode must
254+
belong to a diagnostic group named after the feature.
255+
There are several reasons why this will be useful:
256+
* Future feature-oriented adoption tooling can use the group identifier to
257+
filter out relevant diagnostics.
258+
* IDEs and other diagnostic consumers can integrate group identifiers into
259+
their interfaces to, well, group diagnostics, as well as to communicate
260+
relationships between diagnostics and features. This can prove especially
261+
handy when multiple features are simultaneously enabled in adoption mode.
262+
263+
## Source compatibility
264+
265+
This proposal does not affect language rules. The described changes to the API
266+
surface are source-compatible.
267+
268+
## ABI compatibility
269+
270+
This proposal does not affect binary compatibility or binary interfaces.
271+
272+
## Implications on adoption
273+
274+
Demoting an enabled source-breaking feature to adoption mode may affect
275+
behavior and is therefore a potentially source-breaking action.
276+
277+
## Future directions
278+
279+
### Augment diagnostic metadata
280+
281+
282+
283+
### Support baseline features
284+
285+
Adoption mode can be extrapolated to baseline features, such as `TypedThrows`
286+
or [opaque parameter types][SE-0341], with an emphasis on actionable adoption
287+
tips and otherwise unsolicited educational notes.
288+
These additive features are hard-enabled in all language modes and become an
289+
integral part of the language as soon as they ship.
290+
Baseline feature identifiers are currently kept around for the sole purpose of
291+
supporting [feature availability checks][feature-detection] in conditional
292+
compilation blocks.
293+
294+
### `swift adopt`
295+
296+
The Swift package manager could implement an `adopt` subcommand with an
297+
interactive command line interface similar to `git add --patch` for selecting
298+
and applying fix-its ...
299+
300+
## Alternatives considered
301+
302+
### Naming
303+
304+
305+
306+
## Acknowledgements
307+
308+
This proposal was inspired by documents prepared by [Allan Shortlidge][Allan]
309+
and [Holly Borla][Holly].
310+
Special thanks to Holly for her feedback throughout the draft stage.
311+
312+
<!----------------------------------------------------------------------------->
313+
314+
[Holly]: https://github.com/hborla
315+
[Allan]: https://github.com/tshortli
316+
317+
[SE-0192]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0192-non-exhaustive-enums.md
318+
[SE-0274]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0274-magic-file.md
319+
[SE-0286]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0286-forward-scan-trailing-closures.md
320+
[SE-0296]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0296-async-await.md
321+
[SE-0335]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0335-existential-any.md
322+
[SE-0337]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0337-support-incremental-migration-to-concurrency-checking.md
323+
[SE-0341]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0341-opaque-parameters.md
324+
[SE-0352]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0352-implicit-open-existentials.md
325+
[SE-0354]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0354-regex-literals.md
326+
[SE-0362]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0362-piecemeal-future-features.md
327+
[feature-detection]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0362-piecemeal-future-features.md#feature-detection-in-source-code
328+
[SE-0383]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0383-deprecate-uiapplicationmain-and-nsapplicationmain.md
329+
[SE-0401]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0401-remove-property-wrapper-isolation.md
330+
[SE-0409]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0409-access-level-on-imports.md
331+
[SE-0411]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0411-isolated-default-values.md
332+
[SE-0412]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0412-strict-concurrency-for-global-variables.md
333+
[SE-0418]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0418-inferring-sendable-for-methods.md
334+
[SE-0444]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0444-member-import-visibility.md
335+
[async-inherit-isolation-pitch]: https://forums.swift.org/t/pitch-inherit-isolation-by-default-for-async-functions/74862

0 commit comments

Comments
 (0)