mod demo;
mod error_type;
mod merge_core_std;
mod new_hashing;
mod partial_eq;
mod references;
mod storage_domains;
mod str_array_layout;
mod try_from_bytes_for_b256;
use std::{collections::HashSet, sync::Arc};
use anyhow::{bail, Result};
use duplicate::duplicate_item;
use itertools::Itertools;
use sway_ast::Module;
use sway_core::{
language::{
lexed::{LexedModule, LexedProgram},
ty::{TyModule, TyProgram},
},
Engines,
};
use sway_features::Feature;
use sway_types::Span;
use crate::internal_error;
pub(crate) struct ProgramInfo<'a> {
pub pkg_name: String,
pub lexed_program: Arc<LexedProgram>,
pub ty_program: Arc<TyProgram>,
pub engines: &'a Engines,
}
pub(crate) struct MutProgramInfo<'a> {
pub pkg_name: &'a str,
pub lexed_program: &'a mut LexedProgram,
pub ty_program: &'a TyProgram,
pub engines: &'a Engines,
}
impl ProgramInfo<'_> {
pub(crate) fn as_mut(&mut self) -> MutProgramInfo {
MutProgramInfo {
pkg_name: &self.pkg_name,
lexed_program: Arc::make_mut(&mut self.lexed_program),
ty_program: &self.ty_program,
engines: self.engines,
}
}
}
pub(crate) struct MigrationStep {
pub title: &'static str,
pub duration: usize,
pub kind: MigrationStepKind,
pub help: &'static [&'static str],
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
pub(crate) enum MigrationStepExecution {
Manual,
Semiautomatic,
Automatic,
}
impl MigrationStep {
pub(crate) fn execution(&self) -> MigrationStepExecution {
use MigrationStepExecution::*;
match self.kind {
MigrationStepKind::Instruction(_) => Manual,
MigrationStepKind::CodeModification(_, manual_migration_actions, _)
if !manual_migration_actions.is_empty() =>
{
Semiautomatic
}
MigrationStepKind::CodeModification(..) => Automatic,
MigrationStepKind::Interaction(..) => Semiautomatic,
}
}
pub(crate) fn has_manual_actions(&self) -> bool {
match self.kind {
MigrationStepKind::Instruction(_) => true,
MigrationStepKind::CodeModification(_, [], _) => false,
MigrationStepKind::CodeModification(_, _, _) => true,
MigrationStepKind::Interaction(_, _, [], _) => false,
MigrationStepKind::Interaction(_, _, _, _) => true,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub(crate) enum DryRun {
Yes,
No,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub(crate) enum InteractionResponse {
None,
ExecuteStep,
StepNotNeeded,
PostponeStep,
}
pub(crate) struct Occurrence {
pub span: Span,
pub msg: Option<String>,
}
impl Occurrence {
pub fn new(span: Span, msg: String) -> Self {
Occurrence {
span,
msg: Some(msg),
}
}
pub fn msg_or_empty(&self) -> String {
self.msg.clone().unwrap_or_default()
}
}
impl From<Span> for Occurrence {
fn from(span: Span) -> Self {
Occurrence { span, msg: None }
}
}
type InstructionFn = for<'a> fn(&'a ProgramInfo<'a>) -> Result<Vec<Occurrence>>;
type CodeModificationFn = for<'a> fn(&'a mut MutProgramInfo<'a>, DryRun) -> Result<Vec<Occurrence>>;
type InteractionFn =
for<'a> fn(&'a mut MutProgramInfo<'a>) -> Result<(InteractionResponse, Vec<Occurrence>)>;
type ModuleVisitorMutFn<T> =
for<'a> fn(&'a Engines, &'a mut Module, &'a TyModule, DryRun) -> Result<T>;
type ModuleVisitorFn<T> = for<'a> fn(&'a Engines, &'a Module, &'a TyModule, DryRun) -> Result<T>;
#[derive(PartialEq, Eq, Clone, Copy)]
pub(crate) enum ContinueMigrationProcess {
IfNoManualMigrationActionsNeeded,
Never,
}
pub(crate) enum MigrationStepKind {
Instruction(InstructionFn),
CodeModification(
CodeModificationFn,
&'static [&'static str],
ContinueMigrationProcess,
),
Interaction(
InstructionFn,
InteractionFn,
&'static [&'static str],
ContinueMigrationProcess,
),
}
#[deprecated(note = "use `crate::visiting::ProgramVisitor/Mut::visit_program()` instead")]
#[allow(deprecated)]
pub(crate) fn visit_all_modules<T>(
program_info: &ProgramInfo,
dry_run: DryRun,
visitor: ModuleVisitorFn<T>,
) -> Result<Vec<T>> {
visit_modules(
program_info.engines,
&program_info.lexed_program.root,
&program_info.ty_program.root_module,
dry_run,
visitor,
)
}
#[deprecated(note = "use `crate::visiting::ProgramVisitor/Mut::visit_program()` instead")]
#[allow(deprecated)]
pub(crate) fn visit_all_modules_mut<T>(
program_info: &mut MutProgramInfo,
dry_run: DryRun,
visitor: ModuleVisitorMutFn<T>,
) -> Result<Vec<T>> {
visit_modules_mut(
program_info.engines,
&mut program_info.lexed_program.root,
&program_info.ty_program.root_module,
dry_run,
visitor,
)
}
#[duplicate_item(
__visit_modules __ModuleVisitorFn __ref_type(type) __ref(value) __iter;
[visit_modules] [ModuleVisitorFn] [&type] [&value] [iter];
[visit_modules_mut] [ModuleVisitorMutFn] [&mut type] [&mut value] [iter_mut];
)]
#[deprecated(note = "use `crate::visiting::ProgramVisitor/Mut::visit_program()` instead")]
#[allow(deprecated)]
pub(crate) fn __visit_modules<T>(
engines: &Engines,
lexed_module: __ref_type([LexedModule]),
ty_module: &TyModule,
dry_run: DryRun,
visitor: __ModuleVisitorFn<T>,
) -> Result<Vec<T>> {
fn visit_modules_rec<T>(
engines: &Engines,
lexed_module: __ref_type([LexedModule]),
ty_module: &TyModule,
dry_run: DryRun,
visitor: __ModuleVisitorFn<T>,
result: &mut Vec<T>,
) -> Result<()> {
let visitor_result = visitor(
engines,
__ref([lexed_module.tree.value]),
ty_module,
dry_run,
)?;
result.push(visitor_result);
let mut lexed_submodules = lexed_module.submodules.__iter().collect_vec();
let mut ty_submodules = ty_module.submodules.iter().collect_vec();
if lexed_submodules.len() != ty_submodules.len() {
bail!(internal_error(format!(
"Lexed module has \"{}\" submodules, and typed module has \"{}\" submodules.",
lexed_submodules.len(),
ty_submodules.len(),
)));
}
lexed_submodules.sort_by(|a, b| a.0.cmp(&b.0));
ty_submodules.sort_by(|a, b| a.0.cmp(&b.0));
let lexed_submodules = lexed_submodules.__iter();
let ty_submodules = ty_submodules.iter();
for (lexed_submodule, ty_submodule) in lexed_submodules.zip(ty_submodules) {
if lexed_submodule.0 != ty_submodule.0 {
bail!(internal_error(format!(
"Lexed module \"{}\" does not match with the typed module \"{}\".",
lexed_submodule.0, ty_submodule.0,
)));
}
visit_modules_rec(
engines,
__ref([lexed_submodule.1.module]),
&ty_submodule.1.module,
dry_run,
visitor,
result,
)?;
}
Ok(())
}
let mut result = vec![];
visit_modules_rec(
engines,
lexed_module,
ty_module,
dry_run,
visitor,
&mut result,
)?;
Ok(result)
}
pub(crate) type MigrationSteps = &'static [(Feature, &'static [MigrationStep])];
pub(crate) type MigrationStepsWithOccurrences<'a> =
&'a [(Feature, Vec<(&'a MigrationStep, Option<usize>)>)];
#[macro_export]
macro_rules! get_migration_steps_or_return {
() => {{
let migration_steps = $crate::migrations::get_migration_steps();
if migration_steps.is_empty() {
println!("There are currently no migration steps defined for the upcoming breaking change version of Sway.");
return Ok(());
}
migration_steps
}};
}
pub(crate) fn get_migration_steps() -> MigrationSteps {
assert_migration_steps_consistency(MIGRATION_STEPS);
MIGRATION_STEPS
}
fn assert_migration_steps_consistency(migration_steps: MigrationSteps) {
if migration_steps.is_empty() {
return;
}
let num_of_features_in_migration_steps = migration_steps.len();
let num_of_unique_features_in_migration_steps = migration_steps
.iter()
.map(|(feature, _)| feature)
.collect::<HashSet<_>>()
.len();
if num_of_features_in_migration_steps != num_of_unique_features_in_migration_steps {
panic!("Inconsistent migration steps: each experimental feature can appear only once in the migration steps.");
}
let num_of_migration_steps = migration_steps
.iter()
.map(|(_, steps)| steps.len())
.sum::<usize>();
let num_of_migration_steps_with_unique_title = migration_steps
.iter()
.flat_map(|(_, steps)| steps.iter().map(|step| step.title))
.collect::<HashSet<_>>()
.len();
if num_of_migration_steps != num_of_migration_steps_with_unique_title {
panic!("Inconsistent migration steps: migration step titles must be unique.");
}
let has_non_automatic_steps_with_zero_duration = migration_steps
.iter()
.flat_map(|(_, steps)| {
steps.iter().map(|step| {
(
matches!(step.execution(), MigrationStepExecution::Automatic),
step.duration,
)
})
})
.any(|(is_automatic, duration)| !is_automatic && duration == 0);
if has_non_automatic_steps_with_zero_duration {
panic!("Inconsistent migration steps: only fully automatic steps can have duration set to zero.");
}
}
const MIGRATION_STEPS: MigrationSteps = &[
(
Feature::NewHashing,
&[new_hashing::REVIEW_EXISTING_USAGES_OF_STORAGE_MAP_SHA256_AND_KECCAK256],
),
(
Feature::StrArrayNoPadding,
&[str_array_layout::REVIEW_EXISTING_USAGES_OF_STORAGE_STR_ARRAY],
),
];