Skip to content

Commit a583edd

Browse files
[sui-pkg-alt] move-analyzer fixes (#24493)
## Description This PR brings a few fixes to move-analyzer and a small optimization to reuse a regex rather than creating a new one every time. ## Test plan Existing tests. --- ## Release notes Check each box that your changes affect. If none of the boxes relate to your changes, release notes aren't required. For each box you select, include information after the relevant heading that describes the impact of your changes that a user might notice and any actions they must take to implement updates. - [ ] Protocol: - [ ] Nodes (Validators and Full nodes): - [ ] gRPC: - [ ] JSON-RPC: - [ ] GraphQL: - [ ] CLI: - [ ] Rust SDK: - [ ] Indexing Framework:
1 parent bae8f68 commit a583edd

File tree

6 files changed

+136
-61
lines changed

6 files changed

+136
-61
lines changed

external-crates/move/crates/move-analyzer/src/symbols/compilation.rs

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use move_compiler::{
4444
};
4545
use move_ir_types::location::Loc;
4646

47-
use move_package_alt::{flavor::MoveFlavor, package::RootPackage, schema::PackageName};
47+
use move_package_alt::{flavor::MoveFlavor, package::RootPackage};
4848
use move_package_alt_compilation::{
4949
build_config::BuildConfig,
5050
build_plan::BuildPlan,
@@ -339,13 +339,19 @@ pub fn get_compiled_pkg<F: MoveFlavor>(
339339

340340
let root_pkg = load_root_pkg::<F>(&build_config, pkg_path)?;
341341
let root_pkg_name = Symbol::from(root_pkg.name().to_string());
342+
// the package's transitive dependencies
343+
let mut dependencies: Vec<_> = root_pkg
344+
.packages()
345+
.into_iter()
346+
.filter(|x| !x.is_root())
347+
.collect();
342348
let build_plan =
343349
BuildPlan::create(&root_pkg, &build_config)?.set_compiler_vfs_root(overlay_fs_root.clone());
344350

345-
let mapped_files_data =
346-
compute_mapped_files(&root_pkg, &build_config, overlay_fs_root.clone())?;
347351
// Hash dependencies so we can check if something has changed.
348352
// TODO: do we still need this?
353+
let mapped_files_data =
354+
compute_mapped_files(&root_pkg, &build_config, overlay_fs_root.clone())?;
349355
let file_paths: Arc<BTreeMap<FileHash, PathBuf>> = Arc::new(
350356
mapped_files_data
351357
.files
@@ -361,12 +367,9 @@ pub fn get_compiled_pkg<F: MoveFlavor>(
361367
let mut compiler_analysis_info_opt = None;
362368
let mut compiler_autocomplete_info_opt = None;
363369

364-
// TODO: we need to rework on loading the root pkg only once.
365-
let dependencies = root_pkg.packages();
366-
367370
let compiler_flags = compiler_flags(&build_config);
368371
let (mut caching_result, other_diags) = if let Ok(deps_package_paths) =
369-
make_deps_for_compiler(&mut Vec::new(), dependencies, &build_config)
372+
make_deps_for_compiler(&mut Vec::new(), dependencies.clone(), &build_config)
370373
{
371374
let src_deps: BTreeMap<Symbol, PackagePaths> = deps_package_paths
372375
.into_iter()
@@ -414,8 +417,13 @@ pub fn get_compiled_pkg<F: MoveFlavor>(
414417

415418
let caching_result = match cached_pkg_info_opt {
416419
Some(cached_pkg_info) => {
417-
// TODO: do we need to do anything here?
418-
// dependencies.remove_deps(cached_pkg_info.dep_names.clone());
420+
// remove dependencies that are already included in the cached package info to
421+
// avoid recompiling them
422+
dependencies.retain(|d| {
423+
!cached_pkg_info
424+
.dep_names
425+
.contains(&Symbol::from(d.id().to_string()))
426+
});
419427

420428
let deps = cached_pkg_info.deps.clone();
421429
let analyzed_pkg_info = AnalyzedPkgInfo::new(
@@ -435,8 +443,15 @@ pub fn get_compiled_pkg<F: MoveFlavor>(
435443
)
436444
}
437445
None => {
438-
let sorted_deps = root_pkg.sorted_deps();
439-
let sorted_deps: Vec<PackageName> = sorted_deps.into_iter().cloned().collect();
446+
// get the topologically sorted dependencies, but use the package ids instead of
447+
// package names. In the new pkg system, multiple packages with the same name can
448+
// exist as the package system will assign unique package ids to them, before
449+
// passing them to the compiler.
450+
let sorted_deps: Vec<Symbol> = root_pkg
451+
.sorted_deps_ids()
452+
.into_iter()
453+
.map(|x| Symbol::from(x.to_string()))
454+
.collect();
440455
if let Some((program_deps, dep_names)) = compute_pre_compiled_dep_data(
441456
&mut cached_packages.compiled_dep_pkgs,
442457
mapped_files_data.dep_pkg_paths,
@@ -508,8 +523,8 @@ pub fn get_compiled_pkg<F: MoveFlavor>(
508523
// (that no longer have failures/warnings) are reset
509524
let mut ide_diags = lsp_empty_diagnostics(mapped_files_data.files.file_name_mapping());
510525
if full_compilation || !files_to_compile.is_empty() {
511-
build_plan.compile_with_driver(
512-
// dependencies,
526+
build_plan.compile_with_driver_and_deps(
527+
dependencies.into_iter().map(|x| x.id()).cloned().collect(),
513528
&mut std::io::sink(),
514529
|compiler| {
515530
let compiler = compiler.set_ide_mode();
@@ -548,7 +563,6 @@ pub fn get_compiled_pkg<F: MoveFlavor>(
548563
let failure = true;
549564
diagnostics = Some((diags, failure));
550565
eprintln!("typed AST compilation failed");
551-
eprintln!("diagnostics: {:#?}", diagnostics);
552566
return Ok((files, vec![]));
553567
}
554568
};
@@ -574,7 +588,6 @@ pub fn get_compiled_pkg<F: MoveFlavor>(
574588
});
575589
caching_result.edition =
576590
Some(compiler.compilation_env().edition(Some(root_pkg_name)));
577-
578591
// compile to CFGIR for accurate diags
579592
eprintln!("compiling to CFGIR");
580593
let compilation_result = compiler.at_typing(typed_program).run::<PASS_CFGIR>();
@@ -696,23 +709,24 @@ fn compute_pre_compiled_dep_data(
696709
mut dep_paths: BTreeMap<Symbol, PathBuf>,
697710
mut src_deps: BTreeMap<Symbol, PackagePaths>,
698711
root_package_name: Symbol,
699-
topological_order: &[PackageName],
712+
topological_order: &[Symbol],
700713
compiler_flags: Flags,
701714
vfs_root: VfsPath,
702715
) -> Option<(Arc<PreCompiledProgramInfo>, BTreeSet<Symbol>)> {
703716
let mut pre_compiled_modules = BTreeMap::new();
704717
let mut pre_compiled_names = BTreeSet::new();
705718
for pkg_name in topological_order.iter().rev() {
706-
let pkg_name = Symbol::from(pkg_name.to_string());
707-
if pkg_name == root_package_name {
719+
// both pkg_name and root_package_name are actually PackageIDs and generated by the pkg
720+
// system
721+
if pkg_name == &root_package_name {
708722
continue;
709723
}
710-
let Some(dep_path) = dep_paths.remove(&pkg_name) else {
724+
let Some(dep_path) = dep_paths.remove(pkg_name) else {
711725
eprintln!("no dep path for {pkg_name}, no caching");
712726
// do non-cached path
713727
return None;
714728
};
715-
let Some(dep_info) = src_deps.remove(&pkg_name) else {
729+
let Some(dep_info) = src_deps.remove(pkg_name) else {
716730
eprintln!("no dep info for {pkg_name}, no caching");
717731
// do non-cached path
718732
return None;
@@ -827,10 +841,7 @@ fn compute_mapped_files<F: MoveFlavor>(
827841
if is_dep {
828842
hasher.update(fhash.0);
829843
dep_hashes.push(fhash);
830-
dep_pkg_paths.insert(
831-
rpkg.name().as_str().into(),
832-
rpkg.path().path().to_path_buf(),
833-
);
844+
dep_pkg_paths.insert(rpkg.id().clone().into(), rpkg.path().path().to_path_buf());
834845
}
835846
// write to top layer of the overlay file system so that the content
836847
// is immutable for the duration of compilation and symbolication

external-crates/move/crates/move-package-alt-compilation/src/build_plan.rs

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use move_package_alt::{
2727
errors::PackageResult,
2828
flavor::MoveFlavor,
2929
package::{RootPackage, layout::SourcePackageLayout},
30-
schema::PackageName,
30+
schema::PackageID,
3131
};
3232
use move_symbol_pool::Symbol;
3333
use toml_edit::{DocumentMut, value};
@@ -36,14 +36,18 @@ const EDITION_NAME: &str = "edition";
3636

3737
pub struct BuildPlan<'a, F: MoveFlavor> {
3838
root_pkg: &'a RootPackage<F>,
39+
sorted_deps_ids: Vec<&'a PackageID>,
3940
compiler_vfs_root: Option<VfsPath>,
4041
build_config: BuildConfig,
4142
}
4243

4344
impl<'a, F: MoveFlavor> BuildPlan<'a, F> {
4445
pub fn create(root_pkg: &'a RootPackage<F>, build_config: &BuildConfig) -> PackageResult<Self> {
46+
let mut sorted_deps_ids = root_pkg.sorted_deps_ids();
47+
sorted_deps_ids.reverse();
4548
Ok(Self {
4649
root_pkg,
50+
sorted_deps_ids,
4751
build_config: build_config.clone(),
4852
compiler_vfs_root: None,
4953
})
@@ -73,12 +77,52 @@ impl<'a, F: MoveFlavor> BuildPlan<'a, F> {
7377
Compiler,
7478
)
7579
-> anyhow::Result<(MappedFiles, Vec<AnnotatedCompiledUnit>)>,
80+
) -> anyhow::Result<CompiledPackage> {
81+
let program_info_hook = SaveHook::new([SaveFlag::TypingInfo]);
82+
let dependencies: BTreeSet<PackageID> = self
83+
.root_pkg
84+
.packages()
85+
.into_iter()
86+
.filter(|x| !x.is_root())
87+
.map(|x| x.id().to_string())
88+
.collect();
89+
let compiled = build_all::<W, F>(
90+
writer,
91+
self.compiler_vfs_root.clone(),
92+
self.root_pkg,
93+
dependencies,
94+
&self.build_config,
95+
|compiler| {
96+
let compiler = compiler.add_save_hook(&program_info_hook);
97+
compiler_driver(compiler)
98+
},
99+
)?;
100+
101+
let project_root = self.root_pkg.package_path();
102+
103+
self.clean(
104+
&project_root.join(CompiledPackageLayout::Root.path()),
105+
self.sorted_deps_ids.clone(),
106+
)?;
107+
108+
Ok(compiled)
109+
}
110+
111+
pub fn compile_with_driver_and_deps<W: Write + Send>(
112+
&self,
113+
dependencies: BTreeSet<PackageID>,
114+
writer: &mut W,
115+
compiler_driver: impl FnOnce(
116+
Compiler,
117+
)
118+
-> anyhow::Result<(MappedFiles, Vec<AnnotatedCompiledUnit>)>,
76119
) -> anyhow::Result<CompiledPackage> {
77120
let program_info_hook = SaveHook::new([SaveFlag::TypingInfo]);
78121
let compiled = build_all::<W, F>(
79122
writer,
80123
self.compiler_vfs_root.clone(),
81124
self.root_pkg,
125+
dependencies,
82126
&self.build_config,
83127
|compiler| {
84128
let compiler = compiler.add_save_hook(&program_info_hook);
@@ -87,11 +131,10 @@ impl<'a, F: MoveFlavor> BuildPlan<'a, F> {
87131
)?;
88132

89133
let project_root = self.root_pkg.package_path();
90-
let sorted_deps = self.root_pkg.sorted_deps().into_iter().cloned().collect();
91134

92135
self.clean(
93136
&project_root.join(CompiledPackageLayout::Root.path()),
94-
sorted_deps,
137+
self.sorted_deps_ids.clone(),
95138
)?;
96139

97140
Ok(compiled)
@@ -134,7 +177,7 @@ impl<'a, F: MoveFlavor> BuildPlan<'a, F> {
134177

135178
// Clean out old packages that are no longer used, or no longer used under the current
136179
// compilation flags
137-
fn clean(&self, project_root: &Path, keep_paths: BTreeSet<PackageName>) -> anyhow::Result<()> {
180+
fn clean(&self, project_root: &Path, keep_paths: Vec<&PackageID>) -> anyhow::Result<()> {
138181
// Compute the actual build directory based on install_dir configuration
139182
let build_root = shared::get_build_output_path(project_root, &self.build_config);
140183

@@ -159,11 +202,18 @@ impl<'a, F: MoveFlavor> BuildPlan<'a, F> {
159202
/// Migrate the package from legacy to Move 2024 edition, if possible.
160203
pub fn migrate<W: Write + Send>(&self, writer: &mut W) -> anyhow::Result<Option<Migration>> {
161204
let root_name = Symbol::from(self.root_pkg.name().to_string());
205+
let dependencies: BTreeSet<_> = self
206+
.root_pkg
207+
.sorted_deps_ids()
208+
.into_iter()
209+
.cloned()
210+
.collect();
162211
let (files, res) = build_for_driver(
163212
writer,
164213
None,
165214
&self.build_config,
166215
self.root_pkg,
216+
dependencies,
167217
|compiler| compiler.generate_migration_patch(&root_name),
168218
)?;
169219
let migration = match res {
@@ -183,11 +233,10 @@ impl<'a, F: MoveFlavor> BuildPlan<'a, F> {
183233
};
184234

185235
let project_root = self.root_pkg.package_path();
186-
let sorted_deps = self.root_pkg.sorted_deps().into_iter().cloned().collect();
187236

188237
self.clean(
189238
&project_root.join(CompiledPackageLayout::Root.path()),
190-
sorted_deps,
239+
self.sorted_deps_ids.clone(),
191240
)?;
192241

193242
Ok(migration)

external-crates/move/crates/move-package-alt-compilation/src/compilation.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ use move_compiler::{
3232
};
3333
use move_docgen::DocgenFlags;
3434
use move_package_alt::{
35-
flavor::MoveFlavor, graph::PackageInfo, package::RootPackage, schema::Environment,
35+
flavor::MoveFlavor,
36+
graph::PackageInfo,
37+
package::RootPackage,
38+
schema::{Environment, PackageID},
3639
};
3740
use move_symbol_pool::Symbol;
3841
use std::{collections::BTreeMap, io::Write, path::PathBuf, str::FromStr};
@@ -76,17 +79,24 @@ pub fn build_all<W: Write + Send, F: MoveFlavor>(
7679
w: &mut W,
7780
vfs_root: Option<VfsPath>,
7881
root_pkg: &RootPackage<F>,
82+
dependencies: BTreeSet<PackageID>,
7983
build_config: &BuildConfig,
8084
compiler_driver: impl FnOnce(Compiler) -> Result<(MappedFiles, Vec<AnnotatedCompiledUnit>)>,
8185
) -> Result<CompiledPackage> {
8286
let project_root = root_pkg.package_path().to_path_buf();
8387
let program_info_hook = SaveHook::new([SaveFlag::TypingInfo]);
8488
let package_name = Symbol::from(root_pkg.name().as_str());
85-
let (file_map, all_compiled_units) =
86-
build_for_driver(w, vfs_root, build_config, root_pkg, |compiler| {
89+
let (file_map, all_compiled_units) = build_for_driver(
90+
w,
91+
vfs_root,
92+
build_config,
93+
root_pkg,
94+
dependencies,
95+
|compiler| {
8796
let compiler = compiler.add_save_hook(&program_info_hook);
8897
compiler_driver(compiler)
89-
})?;
98+
},
99+
)?;
90100

91101
let mut all_compiled_units_vec = vec![];
92102
let mut root_compiled_units = vec![];
@@ -195,9 +205,15 @@ pub fn build_for_driver<W: Write + Send, T, F: MoveFlavor>(
195205
vfs_root: Option<VfsPath>,
196206
build_config: &BuildConfig,
197207
root_pkg: &RootPackage<F>,
208+
dependencies: BTreeSet<PackageID>,
198209
compiler_driver: impl FnOnce(Compiler) -> Result<T>,
199210
) -> Result<T> {
211+
// TODO: pkg-alt this seems to add more packages for the compiler than necessary.
200212
let packages = root_pkg.packages();
213+
let packages = packages
214+
.into_iter()
215+
.filter(|p| p.is_root() || dependencies.contains(p.id()))
216+
.collect::<Vec<_>>();
201217
let package_paths = make_deps_for_compiler(w, packages, build_config)?;
202218

203219
debug!("Package paths {:#?}", package_paths);
@@ -212,7 +228,6 @@ pub fn build_for_driver<W: Write + Send, T, F: MoveFlavor>(
212228
let lint_level = build_config.lint_flag.get();
213229
let sui_mode = build_config.default_flavor == Some(Flavor::Sui);
214230
let flags = compiler_flags(build_config);
215-
216231
let mut compiler = Compiler::from_package_paths(vfs_root, package_paths, vec![])
217232
.unwrap()
218233
.set_flags(flags);
@@ -372,7 +387,7 @@ pub fn make_deps_for_compiler<W: Write + Send, F: MoveFlavor>(
372387
warning_filter: WarningFiltersBuilder::new_for_source(),
373388
};
374389

375-
// TODO: improve/rework this? Renaming the root pkg to have a unique name for the compiler
390+
// Assign a unique name for the compiler for each package.
376391
let safe_name = Symbol::from(pkg.id().clone());
377392

378393
debug!("Package name {:?} -- Safe name {:?}", name, safe_name);

external-crates/move/crates/move-package-alt/src/compatibility/mod.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::path::{Path, PathBuf};
88

99
use anyhow::{Context, Result, bail};
1010
use move_core_types::account_address::{AccountAddress, AccountAddressParseError};
11+
use once_cell::sync::Lazy;
1112
use regex::Regex;
1213
use tracing::debug;
1314

@@ -34,6 +35,9 @@ pub enum LegacySubstOrRename {
3435
/// The regex to detect `module <name>::<module_name>` on its different forms.
3536
const MODULE_REGEX: &str = r"\bmodule\s+([a-zA-Z_][\w]*)::([a-zA-Z_][\w]*)";
3637

38+
// Compile regex once at program startup
39+
static MODULE_REGEX_COMPILED: Lazy<Regex> = Lazy::new(|| Regex::new(MODULE_REGEX).unwrap());
40+
3741
/// This is a naive way to detect all module names that are part of the source code
3842
/// for a given package.
3943
///
@@ -111,18 +115,15 @@ fn find_files(files: &mut Vec<PathBuf>, dir: &Path, extension: &str, max_depth:
111115
// Consider supporting the legacy `address { module {} }` format.
112116
fn parse_module_names(contents: &str) -> Result<HashSet<String>> {
113117
let clean = strip_comments(contents);
114-
let mut set = HashSet::new();
118+
115119
// This matches `module a::b {}`, and `module a::b;` cases.
116120
// In both cases, the match is the 2nd group (so `match.get(1)`)
117-
let regex = Regex::new(MODULE_REGEX).unwrap();
118-
119-
for cap in regex.captures_iter(&clean) {
120-
set.insert(cap[1].to_string());
121-
}
122-
123-
Ok(set
124-
.into_iter()
125-
.filter(|name| !is_address_like(name.as_str()))
121+
Ok(MODULE_REGEX_COMPILED
122+
.captures_iter(&clean)
123+
.filter_map(|cap| {
124+
let name = &cap[1];
125+
(!is_address_like(name)).then(|| name.to_string())
126+
})
126127
.collect())
127128
}
128129

0 commit comments

Comments
 (0)