sway/scripts/mdbook-forc-documenter/examples/forc_migrate.md
Igor Rončević bb7c99b24a
Implement partial equivalence and extend forc migrate tool (#6900)
## Description

This PR:
- implements partial equivalence in the `core::ops`, as explained in
detail in #6883. The implementation is opt-in and behind the
`partial_eq` experimental feature flag.
- implements `forc migrate` migration steps for automatic migration to
`partial_eq` feature.
- extends the infrastructure for writing `forc migrate` migrations.
- preserves `Annotation`s on `LexedModule`s in the `LexedProgram`.
(Those were before stripped off and not available in the compiled
`Programs`. This resulted in loss off `//!` doc-comments that are
represented as `doc-comment` annotations.)

Extensions in the `forc migrate` infrastructure include:
- possibility to postpone migration steps. This allows writing
multi-step migrations where the first step is usually early adopting an
experimental feature by using `cfg` attributes in code. This possibility
is crucial for migrating our own codebase where we want to early-adopt
and test and stabilize experimental features.
- possibility to match elements on both mutable and immutable parsed
trees. The initial assumption that immutable matching on typed trees
will always be sufficient does not hold. Experimental `cfg` attributes
can remove parts of typed trees that might be needed in analysis.
- `LexedLocate(As)Annotated` for easier location and retrieval of
`Annotated` elements.
- additional implementations of existing traits.
- additional `Modifier`s for modifying existing elements in the lexed
tree.
- `New` struct for convenient creation of often needed lexed tree
elements. Note that we do not expect migrations to generate large new
parts of lexed trees, but mostly to modify or copy and modify existing
ones.

Almost all of the changes in the Sway files are done automatically by
the migration steps. The only manual change was in the `core` library
(`std` library is also automatically migrated) and in slight extension
of two of the tests.

Note that some of the tests have `Eq` traits in trait constraints. As
explained in the #6883, it is not necessary to change those to
`PartialEq`. We might consider changing some of them, for testing
purposes, and such a change is done on one of the tests that was testing
the behavior of the `Eq` trait. But for the majority of the tests, there
is no strict need for switching from `Eq` to `PartialEq`.

Rolling `PartialEq` out in the tests provoked three existing issues that
will be fixed in separate PRs: #6897, #6898, #6899.

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [x] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [ ] If my change requires substantial documentation changes, I have
[requested support from the DevRel
team](https://github.com/FuelLabs/devrel-requests/issues/new/choose)
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [ ] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.
2025-02-11 10:02:45 -03:00

8.7 KiB

Migrating Sway projects

forc-migrate guides you through breaking changes between Sway versions. It fully or semiautomatically adapts your code, making it compatible with the next breaking change version of Sway.

forc-migrate migrates the code to the next breaking change version of Sway. That means, if you want to migrate to, e.g., Sway v0.67.0, you will need to use the latest v0.66.x version of the forc-migrate.

For example, let's say that your Sway project is on version v0.66.1, and that the latest v0.66 version is v0.66.42. You should first update your Fuel toolchain to version v0.66.42 of forc, and compile your project with that version:

fuelup component add forc@0.66.42

Sway guarantees that all the versions with the same minor version, 0.66 in the above example, are compatible. That means that the latest patch version, 0.66.42 in the example, will correctly compile your project.

Showing the breaking changes

Once you've installed the latest non-breaking version of forc-migrate, use the show command to make yourself familiar with the upcoming breaking changes:

forc migrate show

A typical output of the show command will look like this:

Breaking change features:
  - storage_domains    (https://github.com/FuelLabs/sway/issues/6701)
  - references         (https://github.com/FuelLabs/sway/issues/5063)

Migration steps (1 manual and 1 semiautomatic):
storage_domains
  [M] Review explicitly defined slot keys in storage declarations (`in` keywords)

references
  [S] Replace `ref mut` function parameters with `&mut`

Experimental feature flags:
- for Forc.toml:  experimental = { storage_domains = true, references = true }
- for CLI:        --experimental storage_domains,references

The output will contain:

  • the upcoming breaking change features, storage_domains and references in this example,
  • their tracking issues on GitHub, with detailed migration guides,
  • and the migration steps potentially required to migrate existing code.

The migration steps can be manual, semiautomatic, or fully automatic. They are marked in the output with [M], [S], and [A], respectively.

The show command will also provide experimental feature flags that will be needed during the migration, as explained in the next chapter.

Migrating a single Sway project

Let's assume that we want to migrate a Sway project called my_project that depends on std and a third_party_lib.

First, we will go to the folder that contains my_project, e.g.: cd my_project. All of the upcoming CLI commands assume that we are running the forc-migrate tool within the my_project folder.

Before migrating the code, make sure that the project builds without any errors by running:

forc build

Check the migration summary

Next, let's check the project first. The check command will dry-run the migration steps. It will not do any changes in code, but will provide a detailed information of all the places in code that need to be either reviewed or changed during the migration process. The check command will also provide a rough time estimate for the migration.

forc migrate check

The output of the check command will end in a summary of the migration effort, containing:

  • the number of occurrences of a particular migration step in the project's code,
  • the rough migration effort estimate for each migration step,
  • and the rough total migration effort.
Migration effort:

storage_domains
  [M] Review explicitly defined slot keys in storage declarations (`in` keywords)
      Occurrences:     3    Migration effort (hh::mm): ~00:06

references
  [S] Replace `ref mut` function parameters with `&mut`
      Occurrences:    18    Migration effort (hh::mm): ~01:30

Total migration effort (hh::mm): ~01:36

Before the summary, instructions will be shown for each migration step. A typical instruction output for a single migration step will contain:

  • the name of the step,
  • the places in code affected by the migration step,
  • and the short help with a link to the detailed migration guide.
info: [references] Replace `ref mut` function parameters with `&mut`
  --> my_project/src/main.sw:30:51
   |
...
30 | fn ref_mut_fn(ref mut x: u64) {}
   |               ---------
...
35 | fn another_ref_mut_fn(ref mut arg: S) {}
   |                       -----------
   |
   = help: Migration will replace `ref mut` function parameters with `&mut`.
   = help: E.g., `ref mut x: u64` will become `x: &mut u64`.
   = help:  
   = help: After the migration, you will still need to:
   = help: - change function callers, by adding `&mut` to passed parameters.
   = help: - change function bodies, by dereferencing (`*`) parameters where needed.
   = help:  
   = help: For a detailed migration guide see: https://github.com/FuelLabs/sway/issues/5063

Update dependencies

Before running the migrations on the project itself, first update the project dependencies to the versions that use the next Sway breaking change version.

In our example, the my_project's Forc.toml file will have the [dependencies] section similar to this one:

[dependencies]
std = { git = "https://github.com/FuelLabs/sway", tag = "v0.66.1" }
third_party_lib = { git = "https://github.com/ThirdParty/swaylib", tag = "v1.0.0" }

Assuming that the third_party_lib version compatible with Sway v0.67.0 is the version v2.0.0 we will end up in the following changes:

[dependencies]
# Changed v0.66.1 -> v0.67.0
std = { git = "https://github.com/FuelLabs/sway", tag = "v0.67.0" }
# Changed v1.0.0  -> v2.0.0
third_party_lib = { git = "https://github.com/ThirdParty/swaylib", tag = "v2.0.0" }

Run forc build to make sure that the project still compiles. At this point, it is very likely that you will need to compile the project with the experimental features turned on. The reason is the likelihood that either the new std or the third_party_lib uses the new Sway features.

To compile the project with experimental features, you can take the feature flags from the forc migrate show output, and place them either in the [build-profile] section of the projects Forc.toml file, or pass them to forc build via the command line.

Experimental feature flags:
- for Forc.toml:  experimental = { storage_domains = true, references = true }
- for CLI:        --experimental storage_domains,references

In the remaining part of this tutorial, we will be passing the feature flags via the command line. E.g.:

forc build --experimental storage_domains,references

Run the migrations

Once the my_project successfully builds with updated dependencies, we can run the migration steps on it. E.g.:

forc migrate run --experimental storage_domains,references

The run command will execute the migration steps, and guide you through the migration process. For each migration step, the output of the step can be one of the following:

Step output Meaning
Checked The step is executed and does not require any changes in code. No action needed.
Review The step suggests a manual code review.
Changing The step is automatically changing the code. There might be additional manual actions needed.

At the end of the run, the migration will either guide you to:

  • Continue the migration process by performing the manual actions and re-running the forc migrate run afterwards,
  • or will mark the migration process as Finished. At this point, your project will be compatible with the next breaking change version of Sway.

forc migrate, same like forc fmt, does its best to preserve the positions of comments in the modified code. This is a challenging task, especially if migration steps remove parts of the code. It is a good practice to always diff the changes done within migration steps and check if the comments are placed where expected.

Migrating workspaces

To migrate a workspace, you will need to migrate each workspace member separately, following the above procedure. The projects should be migrated in order of their dependencies.

Note

: There is a know limitation when running forc migrate on projects that are listed as workspace members. forc migrate will run, but possibly not find all the occurrences in code that need to be migrated. Therefore, before running migrations on projects that are workspace members, remove them temporarily from the the list of workspace members.

Additional after-migration steps

There are some additional manual steps that might be needed after the migration.

E.g., if tests use hardcoded contract IDs, those need to be changed, because the new version of Sway will, very likely, produce different bytecode.