Skip to content

Commit cdcafe5

Browse files
committed
burp
1 parent 78c8b36 commit cdcafe5

File tree

1 file changed

+317
-0
lines changed

1 file changed

+317
-0
lines changed
+317
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
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+
37+
### User Intent
38+
39+
40+
> [!CAUTION]
41+
> TODO: No way to for users to declare an intetion to adopt a feature
42+
43+
### Automation
44+
45+
Many existing and prospective upcoming features imply or implement simple and
46+
consistent source modifications to aid adoption:
47+
48+
* [`NonfrozenEnumExhaustivity`][SE-0192]: Restore exhaustivity with
49+
`@unknown default:`.
50+
* [`ConciseMagicFile`][SE-0274]: `#file``#filePath`.
51+
* [`ForwardTrailingClosures`][SE-0286]: Disambiguate argument matching by
52+
de-trailing closures and/or inlining default arguments.
53+
* [`ExistentialAny`][SE-0335]: `P``any P`.
54+
* [`ImplicitOpenExistentials`][SE-0352]: Suppress opening with `as any P`
55+
coercions.
56+
* [`BareSlashRegexLiterals`][SE-0354]: Disambiguate using parentheses,
57+
e.g. `foo(/a, b/)``foo((/a), b/)`.
58+
* [`DeprecateApplicationMain`][SE-0383]: `@UIApplicationMain``@main`,
59+
`@NSApplicationMain``@main`.
60+
* [`DisableOutwardActorInference`][SE-0401]: Specify global actor isolation
61+
explicitly.
62+
* [`InternalImportsByDefault`][SE-0409]: `import X``public import X`.
63+
* [`GlobalConcurrency`][SE-0412]:
64+
- Convert the global variable to a `let` (or)
65+
- `@MainActor`-isolate it (or)
66+
- Mark it with `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+
Feature
74+
75+
Extending diagnostic metadata to include information that allows for
76+
recognizing these diagnostics and distinguishing semantics-preserving fix-its
77+
from alternative source changes would open up numerous opportunities for
78+
higher-level tools — ranging from the Swift package manager to IDEs — to
79+
implement powerful solutions for organizing, automating, and tuning code
80+
migration processes.
81+
82+
### Flexibility/Ergonomics
83+
84+
> [!CAUTION]
85+
> Still a draft.
86+
87+
Although upcoming features should strive to facilitate code migration, compilers
88+
are limited
89+
90+
language design principles may prevail over bespoke code migration solutions.
91+
Some features, like [StrictConcurrency][SE-0337], inherently require user
92+
intervetion
93+
94+
Adjusting to new behaviors or language requirements can demand research,
95+
careful consideration, coordinated efforts, and manual code refactorings,
96+
sometimes on a case-by-case basis.
97+
98+
Currently best solution is to implement custom staging solutions. This approach
99+
has limited applications (why?).
100+
101+
UPCOMING_FEATURE(DynamicActorIsolation, 423, 6)
102+
UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6)
103+
UPCOMING_FEATURE(StrictConcurrency, 0337, 6)
104+
UPCOMING_FEATURE(IsolatedDefaultValues, 411, 6)
105+
UPCOMING_FEATURE(RegionBasedIsolation, 414, 6)
106+
107+
## Proposed Solution
108+
109+
Introduce the notion of a "adoption" mode for individual experimental and
110+
upcoming features.
111+
If enabling a feature communicates an intent to *enact* new rules or
112+
functionality, invoking adoption mode communicates an intent to *adopt* them.
113+
The core idea behind adoption mode is to provide adoption tips and
114+
specific source code modifications that can be applied to preserve or improve
115+
the behavior of existing code when the feature is enacted.
116+
117+
> [!NOTE]
118+
> The subject of this proposal is an enhancement to the Swift feature model.
119+
> Applications of adoption mode to existing features are beyond its scope.
120+
121+
## Detailed Design
122+
123+
### Behavior
124+
125+
Enabling a previously disabled source-breaking feature in adoption mode is
126+
necessarily a source-compatible action and must never result in behavioral
127+
changes or new errors per se.
128+
129+
The effect of adoption mode on the state of a feature will depend on whether it
130+
can break source:
131+
* Additive features will be enabled in adoption mode.
132+
* Source-breaking features will be disabled in adoption mode.
133+
If a source-breaking feature does not implement adoption mode, a corresponding
134+
warning will also be emitted to avoid the false impression that the impacted
135+
source code is compatible with the feature.
136+
137+
> [!NOTE]
138+
> Experimental features can be both additive and source-breaking.
139+
> Upcoming features are necessarily source-breaking.
140+
141+
adoption mode will deliver guidance in the shape of warnings, notes, remarks,
142+
and fix-its, as and when appropriate.
143+
144+
When implemented, adoption mode for upcoming features is expected to anticipate
145+
and call out any hard and soft source breaks (compilation errors and silent
146+
behavioral differences) that will result from enacting the feature, coupling
147+
diagnostic messages with counteracting source-compatible changes whenever
148+
possible.
149+
Although upcoming features should strive to facilitate automatic code
150+
migration, language design principles may prevail over bespoke code migration
151+
solutions.
152+
adoption mode cannot guarantee to provide exclusively source-compatible
153+
modifications because the impact of a change on dependent source code is
154+
generally unpredictable without a subsequent clean build.
155+
Neither can it promise to always offer fix-its in the first place for the
156+
same reason in regards to user intention.
157+
158+
### Interface
159+
160+
#### Compiler
161+
162+
The `-enable-*-feature` frontend and driver command line options will start
163+
supporting an optional mode specifier with `adoption` as the only valid mode:
164+
165+
```
166+
-enable-upcoming-feature <feature>[:<mode>]
167+
-enable-experimental-feature <feature>[:<mode>]
168+
169+
<mode> := adoption
170+
```
171+
172+
For example:
173+
174+
```
175+
-enable-upcoming-feature InternalImportsByDefault:adoption
176+
```
177+
178+
In a series of either of these options applied to a given feature, only the
179+
last option will be honored.
180+
If an upcoming feature is both implied by the effective language mode and
181+
enabled in adoption mode using either of the aforementioned options, the latter
182+
will be disregarded.
183+
184+
#### Swift Package Manager
185+
186+
The [`SwiftSetting.enableUpcomingFeature`] and
187+
[`SwiftSetting.enableExperimentalFeature`] methods from the
188+
[`PackageDescription`](https://developer.apple.com/documentation/packagedescription)
189+
library will be augmented with a `mode` parameter defaulted to match the
190+
current behavior:
191+
192+
```swift
193+
extension SwiftSetting {
194+
@available(_PackageDescription, introduced: 6.2)
195+
public enum SwiftFeatureMode {
196+
case adoption
197+
case on
198+
}
199+
}
200+
```
201+
```diff
202+
public static func enableUpcomingFeature(
203+
_ name: String,
204+
+ mode: SwiftFeatureMode = .on,
205+
_ condition: BuildSettingCondition? = nil
206+
) -> SwiftSetting {
207+
+ let argument = switch mode {
208+
+ case .adoption: "\(name):adoption"
209+
+ case .mode: name
210+
+ }
211+
+
212+
return SwiftSetting(
213+
- name: "enableUpcomingFeature", value: [name], condition: condition)
214+
+ name: "enableUpcomingFeature", value: [argument], condition: condition)
215+
}
216+
```
217+
```diff
218+
public static func enableExperimentalFeature(
219+
_ name: String,
220+
+ mode: SwiftFeatureMode = .on,
221+
_ condition: BuildSettingCondition? = nil
222+
) -> SwiftSetting {
223+
+ let argument = switch mode {
224+
+ case .adoption: "\(name):adoption"
225+
+ case .mode: name
226+
+ }
227+
+
228+
return SwiftSetting(
229+
- name: "enableExperimentalFeature", value: [name], condition: condition)
230+
+ name: "enableExperimentalFeature", value: [argument], condition: condition)
231+
}
232+
```
233+
234+
For example:
235+
236+
```
237+
SwiftSetting.enableUpcomingFeature("InternalImportsByDefault", mode: .adoption)
238+
```
239+
240+
### Diagnostics
241+
242+
Diagnostics emitted in relation to a specific feature in adoption mode must
243+
belong to a diagnostic group named after the feature.
244+
There are several reasons why this will be useful:
245+
* Future feature-oriented adoption tooling can use the group identifier to
246+
filter out relevant diagnostics.
247+
* IDEs and other diagnostic consumers can integrate group identifiers into
248+
their interfaces to, well, group diagnostics, as well as to communicate
249+
relationships between diagnostics and features. This can prove especially
250+
handy when multiple features are simultaneously enabled in adoption mode.
251+
252+
> [!CAUTION]
253+
> Establish guidelines for adoption mode diagnostics?
254+
255+
## Source compatibility
256+
257+
This proposal does not affect language rules. Proposed changes to the API
258+
surface are source-compatible.
259+
260+
## ABI compatibility
261+
262+
This proposal does not affect binary compatibility or binary interfaces.
263+
264+
## Implications on adoption
265+
266+
Demoting an enabled source-breaking feature to adoption mode is analogous to
267+
disabling it, and therefore a source-breaking action.
268+
269+
## Future directions
270+
271+
### Support Baseline Features
272+
273+
Adoption mode could be extrapolated to baseline features like `TypedThrows` or
274+
opaque parameter types with
275+
an emphasis on adoption tips and otherwise unsolicited educational notes.
276+
These additive features are always enabled in all language modes and
277+
immediately become an integral part of the language.
278+
Baseline features are kept around for the sole purpose of supporting feature
279+
availability checks in conditional compilation blocks:
280+
`#if hasFeature(<feature>)`.
281+
282+
### `swift adopt`
283+
284+
TBD.
285+
286+
## Alternatives considered
287+
288+
### Naming
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-0341]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0341-opaque-parameters.md
307+
[SE-0352]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0352-implicit-open-existentials.md
308+
[SE-0354]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0354-regex-literals.md
309+
[SE-0362]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0362-piecemeal-future-features.md
310+
[SE-0383]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0383-deprecate-uiapplicationmain-and-nsapplicationmain.md
311+
[SE-0401]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0401-remove-property-wrapper-isolation.md
312+
[SE-0409]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0409-access-level-on-imports.md
313+
[SE-0411]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0411-isolated-default-values.md
314+
[SE-0412]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0412-strict-concurrency-for-global-variables.md
315+
[SE-0418]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0418-inferring-sendable-for-methods.md
316+
[SE-0444]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0444-member-import-visibility.md
317+
[async-inherit-isolation-pitch]: https://forums.swift.org/t/pitch-inherit-isolation-by-default-for-async-functions/74862

0 commit comments

Comments
 (0)