RFC: `swift migrate` command

Introduction

Adoption tooling for upcoming features pitch proposed to extend the Swift compiler to add an integrated mechanism for producing source-compatible adjustments to code that can be applied to preserve its behavior once a given eligible upcoming feature is enabled.

To enable seemless migration experience for Swift packages, I'd like to propose a new Swift Package Manager command - swift migrate to complement the Swift compiler-side changes.

The command would accept one or more features that have migration mode enabled and optionally a set of targets to migrate, if no targets are specified the whole package is going to be migrated to use new features.

Interface

USAGE: swift migrate [<options>] --to-feature <to-feature> ...

OPTIONS:
  --targets <targets>     The targets to migrate to specified set of features or a new language mode.
  --to-feature <to-feature>
                          The Swift language upcoming/experimental feature to migrate to.
  -h, --help              Show help information.

Use case

swift migrate --targets MyTarget,MyTest --to-feature ExistentialAny

This command would attempt to build MyTarget and MyTest targets with ExistentialAny:migrate feature flag, apply any fix-its associated with
the feature produced by the compiler, and update the Package.swift to
enable the feature(s) if both of the previous actions are successful:

.target(
  name: "MyTarget",
  ...
  swiftSettings: [
    // ... existing settings,
    .enableUpcomingFeature("ExistentialAny")
  ]
)
...
.testTarget(
  name: "MyTest",
  ...
  swiftSettings: [
    // ... existing settings,
    .enableUpcomingFeature("ExistentialAny")
  ]
)

In the "whole package" mode, every target is going to be updated to include
new feature flag(s). This is supported by the same functionality as swift package add-setting command.

If it's, for some reason, impossible to add the setting the diagnostic message would suggest what to add and where i.e. ...; please add '.enableUpcomingFeature("ExistentialAny")' to MyTarget target manually.

Impact on Interface

This proposal introduces a new command but does that does not interfere with existing commands. It follows the same pattern as swift build and swift test in a consistent manner.

14 Likes

Any and all feedback is welcome!

This is really cool.

What happens if the code fails to compile after the fix-its are applied? Will the modified code be left in the package, so any other necessary fixes can be made before enabling the feature?

1 Like

The compiler is responsible for not letting that happen since the fix-its for the migratable features should be source compatible but if it happens the code would stay modified. We did discuss possible rollback, it could be a future direction.

1 Like

I’m trying to use this command to migrate with NonisolatedNonsendingByDefault (Approachable Swift Concurrency).

However, the command compiles my package for macOS platform, even though my package is restricted to the iOS platform.
As a result, I get errors like “No such module UIKit”.

My question is:

Is it possible to build for iOS using the swift package migrate command?
If so, what parameters need to be passed to this command?

Thank you for your help, as I’ve been stuck on this issue for several days.