Skip to content

Commit 2269420

Browse files
committed
burp
1 parent 78c8b36 commit 2269420

File tree

1 file changed

+316
-0
lines changed

1 file changed

+316
-0
lines changed
+316
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
# Migration 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+
As Swift evolves, source-breaking changes to the language are staged behind new
13+
language modes and, more recently, [upcoming features][SE-0362] that may be
14+
enabled piecemeal without adopting an entire new language mode.
15+
16+
This proposal centers on the experience of adopting individual features.
17+
The proposition is that Swift needs a flexible, integrated mechanism for
18+
supporting quality assistance with code migration and adoption.
19+
And that — in principle — comprehensive, code-aware assistance can be delivered
20+
without breaking source and acted upon incrementally.
21+
22+
## Motivation
23+
24+
Whether you are adjusting code to follow new language rules or researching ways
25+
to apply new functionality, adopting features can be a time-consuming endeavor
26+
at the least.
27+
28+
Certain source-breaking language features are anticipated to generate hundreds
29+
of errors in sizable projects.
30+
Some of these errors are going to be knock-on or collateral errors (such as
31+
those that cascade into dependent modules or occasionally fall out from the
32+
expression checker) that are not indicative of the precise cause or source of
33+
the issue, and require further investigation.
34+
Developers are left to either resolve all errors or address a subset and take
35+
the risk of switching a feature back off before they can resume development.
36+
At the other end of the spectrum, baseline or source-compatible features
37+
immediately become part of the language and require no migration, but
38+
cannot offer any adoption tips in the current model.
39+
40+
### User Intent
41+
42+
> [!CAUTION]
43+
> TODO: No way to for users to declare an intetion to adopt a feature
44+
45+
### Automation
46+
47+
Many existing and prospective upcoming features come with simple, sure-fire
48+
solutions for preserving behavior:
49+
50+
* [`NonfrozenEnumExhaustivity`][SE-0192]: Restore exhaustivity with
51+
`@unknown default:`.
52+
* [`ConciseMagicFile`][SE-0274]: `#file``#filePath`.
53+
* [`ForwardTrailingClosures`][SE-0286]: Disambiguate argument matching by
54+
de-trailing closures and/or inlining default arguments.
55+
* [`ExistentialAny`][SE-0335]: `P``any P`.
56+
* [`ImplicitOpenExistentials`][SE-0352]: Suppress opening with `as any P`
57+
coercions.
58+
* [`BareSlashRegexLiterals`][SE-0354]: Disambiguate using parentheses,
59+
e.g. `foo(/a, b/)``foo((/a), b/)`.
60+
* [`DeprecateApplicationMain`][SE-0383]: `@UIApplicationMain``@main`,
61+
`@NSApplicationMain``@main`.
62+
* [`DisableOutwardActorInference`][SE-0401]: Specify global actor isolation
63+
explicitly.
64+
* [`InternalImportsByDefault`][SE-0409]: `import X``public import X`.
65+
* [`GlobalConcurrency`][SE-0412]: Mark nonisolated global state with
66+
`nonisolated(unsafe)`.
67+
* [`MemberImportVisibility`][SE-0444]: Add explicit imports appropriately.
68+
* [`InferSendableFromCaptures`][SE-0418]: Suppress inference with coercions
69+
and type annotations.
70+
* [Inherit isolation by default for async functions][async-inherit-isolation-pitch]:
71+
Mark nonisolated functions with the proposed attribute.
72+
73+
Extending diagnostic metadata to include information that allows for
74+
recognizing these diagnostics and distinguish semantics-preserving fix-its from
75+
alternative source changes would open up numerous opportunities for higher-level
76+
tools — ranging from the Swift package manager to IDEs — to implement powerful
77+
solutions for organizing, automating, and tuning code migration processes.
78+
79+
### Flexibility/Ergonomics
80+
81+
> [!CAUTION]
82+
> Still a draft.
83+
84+
Although upcoming features should strive to facilitate code migration, compilers
85+
are limited
86+
87+
language design principles may prevail over bespoke code migration solutions.
88+
Some features, like [StrictConcurrency][SE-0337], inherently require user
89+
intervetion
90+
91+
Adjusting to new behaviors or language requirements can demand research,
92+
careful consideration, coordinated efforts, and manual code refactorings,
93+
sometimes on a case-by-case basis.
94+
95+
Currently best solution is to implement custom staging solutions. This approach
96+
has limited applications (why?).
97+
98+
UPCOMING_FEATURE(DynamicActorIsolation, 423, 6)
99+
UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6)
100+
UPCOMING_FEATURE(StrictConcurrency, 0337, 6)
101+
UPCOMING_FEATURE(IsolatedDefaultValues, 411, 6)
102+
UPCOMING_FEATURE(RegionBasedIsolation, 414, 6)
103+
104+
* [SE-0335] introduced syntax for existential or boxed types to visually
105+
distinguish them from conformance constraints and deliver contrast between
106+
dynamic existential types and fixed `some` types. The associated
107+
`ExistentialAny` feature is a vivid example where automatic migration is
108+
possible, but not desirable. The niche that exitential types occupy combined
109+
with their lighweight syntax make for an enticing and viable, yet often
110+
misused, abstraction construct. In places where type dynamism may be
111+
superfluous, we want to guide developers toward an informed choice of
112+
abstraction.
113+
114+
## Proposed Solution
115+
116+
Introduce the notion of a "adoption" mode for individual Swift features.
117+
If enabling a feature communicates an intent to *enact* new rules or
118+
functionality, invoking adoption mode communicates an intent to *adopt* them.
119+
The core idea behind adoption mode is to provide adoption tips and
120+
specific source code modifications that can be applied to preserve or improve
121+
the behavior of existing code when the feature is enacted.
122+
123+
> [!NOTE]
124+
> The subject of this proposal is an enhancement to the Swift feature model.
125+
> Applications of adoption mode to existing features are beyond its scope.
126+
127+
## Detailed Design
128+
129+
### Behavior
130+
131+
Enabling an additive feature or previously disabled source-breaking feature in
132+
adoption mode is necessarily a source-compatible action and must never result in
133+
behavioral changes or new errors per se.
134+
135+
The effect of adoption mode on the state of a feature will depend on whether it
136+
can break source:
137+
* Additive features will be enabled in adoption mode.
138+
* Source-breaking features will be disabled in adoption mode.
139+
If a source-breaking feature does not implement adoption mode, a corresponding
140+
warning will also be emitted to avoid the false impression that the impacted
141+
source code is compatible with the feature.
142+
143+
> [!NOTE]
144+
> Experimental features can be both additive and source-breaking.
145+
> Upcoming features are necessarily source-breaking.
146+
> Baseline features, such as [`AsyncAwait`][SE-0296], are necessarily
147+
> additive and cannot be disabled.
148+
> They are currently defined for the sole purpose of supporting feature
149+
> availability checks in conditional compilation blocks:
150+
> `#if hasFeature(<feature>)`.
151+
152+
adoption mode will deliver guidance in the shape of warnings, notes, remarks,
153+
and fix-its, as and when appropriate.
154+
155+
When implemented, adoption mode for upcoming features is expected to anticipate
156+
and call out any hard and soft source breaks (compilation errors and silent
157+
behavioral differences) that will result from enacting the feature, coupling
158+
diagnostic messages with counteracting source-compatible changes whenever
159+
possible.
160+
Although upcoming features should strive to facilitate automatic code
161+
migration, language design principles may prevail over bespoke code migration
162+
solutions.
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 without a subsequent clean build.
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 by analogy with `-disable-upcoming-feature`.
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+
> [!IMPORTANT]
254+
> TODO: `-Werror` and `-warnings-as-errors` can abuse adoption mode.
255+
> Do we want adoption mode to overpower these options?
256+
257+
Diagnostics emitted in relation to a specific feature in adoption mode must
258+
belong to a diagnostic group named after the feature.
259+
There are several reasons why this will be useful:
260+
* Future feature-oriented adoption tooling can use the group identifier to
261+
filter out relevant diagnostics.
262+
* IDEs and other diagnostic consumers can integrate group identifiers into
263+
their interfaces to, well, group diagnostics, as well as to communicate
264+
relationships between diagnostics and features. This can prove especially
265+
handy when multiple features are simultaneously enabled in adoption mode.
266+
267+
> [!CAUTION]
268+
> Establish guidelines for adoption mode diagnostics?
269+
270+
## Source compatibility
271+
272+
This proposal does not affect language rules. Proposed changes to the API
273+
surface are source-compatible.
274+
275+
## ABI compatibility
276+
277+
This proposal does not affect binary compatibility or binary interfaces.
278+
279+
## Implications on adoption
280+
281+
Demoting an enabled source-breaking feature to adoption mode is analogous to
282+
disabling it, and therefore a source-breaking action.
283+
284+
## Future directions
285+
286+
TBD. Talk about `swift migrate`.
287+
288+
## Alternatives considered
289+
290+
?
291+
292+
## Acknowledgements
293+
294+
This proposal is inspired by documents devised by [Allan Shortlidge][Allan]
295+
and [Holly Borla][Holly] (@bhorla).
296+
297+
[Holly]: https://github.com/hborla
298+
[Allan]: https://github.com/tshortli
299+
300+
[SE-0192]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0192-non-exhaustive-enums.md
301+
[SE-0274]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0274-magic-file.md
302+
[SE-0286]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0286-forward-scan-trailing-closures.md
303+
[SE-0296]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0296-async-await.md
304+
[SE-0335]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0335-existential-any.md
305+
[SE-0337]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0337-support-incremental-migration-to-concurrency-checking.md
306+
[SE-0352]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0352-implicit-open-existentials.md
307+
[SE-0354]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0354-regex-literals.md
308+
[SE-0362]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0362-piecemeal-future-features.md
309+
[SE-0383]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0383-deprecate-uiapplicationmain-and-nsapplicationmain.md
310+
[SE-0401]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0401-remove-property-wrapper-isolation.md
311+
[SE-0409]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0409-access-level-on-imports.md
312+
[SE-0411]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0411-isolated-default-values.md
313+
[SE-0412]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0412-strict-concurrency-for-global-variables.md
314+
[SE-0418]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0418-inferring-sendable-for-methods.md
315+
[SE-0444]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0444-member-import-visibility.md
316+
[async-inherit-isolation-pitch]: https://forums.swift.org/t/pitch-inherit-isolation-by-default-for-async-functions/74862

0 commit comments

Comments
 (0)