Skip to content

Commit 26fa1d0

Browse files
authored
Support proc macro crate fingerprint in PMS (#2892)
software-mansion/cairols#775
1 parent fb051c7 commit 26fa1d0

File tree

13 files changed

+221
-78
lines changed

13 files changed

+221
-78
lines changed

scarb/src/compiler/incremental/fingerprint.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ impl UnitComponentsFingerprint {
151151
),
152152
ToFingerprint::Plugin(plugin) => (
153153
plugin.component_dependency_id.clone(),
154-
PluginFingerprint::try_from_plugin(plugin, unit, ws)
154+
PluginFingerprint::try_from_plugin(plugin, ws)
155155
.await
156156
.map(ComponentFingerprint::Plugin),
157157
),
@@ -233,7 +233,6 @@ impl ComponentFingerprint {
233233
impl PluginFingerprint {
234234
pub async fn try_from_plugin(
235235
component: &CompilationUnitCairoPlugin,
236-
_unit: &CairoCompilationUnit,
237236
ws: &Workspace<'_>,
238237
) -> Result<Self> {
239238
let component_discriminator = component
@@ -299,6 +298,14 @@ impl PluginFingerprint {
299298
}
300299

301300
pub fn digest(&self) -> String {
301+
self.prepare_hasher().finish_as_short_hash()
302+
}
303+
304+
pub fn digest_u64(&self) -> u64 {
305+
self.prepare_hasher().finish()
306+
}
307+
308+
fn prepare_hasher(&self) -> StableHasher {
302309
let mut hasher = StableHasher::new();
303310
self.component_discriminator.hash(&mut hasher);
304311
self.is_builtin.hash(&mut hasher);
@@ -322,7 +329,7 @@ impl PluginFingerprint {
322329
.unwrap_or_default()
323330
.hash(&mut hasher);
324331
}
325-
hasher.finish_as_short_hash()
332+
hasher
326333
}
327334
}
328335

scarb/src/compiler/incremental/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ pub use compilation::{
77
IncrementalContext, load_incremental_artifacts, save_incremental_artifacts,
88
warmup_incremental_cache,
99
};
10+
11+
pub use fingerprint::PluginFingerprint;

scarb/src/compiler/plugin/collection.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use smol_str::SmolStr;
1010
use std::vec::IntoIter;
1111

1212
use super::proc_macro::{DeclaredProcMacroInstances, ProcMacroHostPlugin, ProcMacroInstance};
13+
use crate::compiler::incremental::PluginFingerprint;
1314
use crate::compiler::plugin::CairoPlugin;
1415
use crate::core::PackageId;
1516
use crate::{
@@ -27,12 +28,17 @@ impl PluginsForComponents {
2728
pub fn collect(workspace: &Workspace<'_>, unit: &CairoCompilationUnit) -> Result<Self> {
2829
let mut plugins = collect_builtin_plugins(workspace, unit)?;
2930

30-
let proc_macros = collect_proc_macros(workspace, unit)?
31+
let proc_macros = collect_proc_macros(workspace, unit, false)?
3132
.into_iter()
3233
.map(|(component_id, instances)| {
3334
Ok((
3435
component_id,
35-
ComponentProcMacroHost::try_from_instances(instances)?,
36+
ComponentProcMacroHost::try_from_instances(
37+
instances
38+
.into_iter()
39+
.map(|(instance, _hash)| instance)
40+
.collect(),
41+
)?,
3642
))
3743
})
3844
.collect::<Result<HashMap<_, _>>>()?;
@@ -65,6 +71,8 @@ pub struct WorkspaceProcMacros {
6571
/// each mapped to a [`ProcMacroHostPlugin`] which contains
6672
/// **all proc macro dependencies of the package** collected from **all compilation units it appears in**.
6773
pub macros_for_components: HashMap<CompilationUnitComponent, Arc<Vec<ProcMacroHostPlugin>>>,
74+
/// Mapping from package id to fingerprint hash.
75+
pub instance_to_hash: HashMap<PackageId, u64>,
6876
}
6977

7078
impl WorkspaceProcMacros {
@@ -76,7 +84,7 @@ impl WorkspaceProcMacros {
7684
let mut macros_for_components = HashMap::<_, Vec<_>>::new();
7785

7886
for &unit in compilation_units {
79-
for (component_id, mut macro_instances) in collect_proc_macros(workspace, unit)? {
87+
for (component_id, mut macro_instances) in collect_proc_macros(workspace, unit, true)? {
8088
let component: CompilationUnitComponent = unit
8189
.components
8290
.iter()
@@ -91,11 +99,18 @@ impl WorkspaceProcMacros {
9199
}
92100
}
93101

102+
let instance_to_hash: HashMap<_, _> = macros_for_components
103+
.values()
104+
.flatten()
105+
.map(|(key, value)| (key.package_id(), *value))
106+
.collect();
107+
94108
let macros_for_components = macros_for_components
95109
.into_iter()
96110
.map(|(component, macro_instances)| {
97111
let deduplicated_instances: Vec<Arc<ProcMacroInstance>> = macro_instances
98112
.into_iter()
113+
.map(|(instance, _hash)| instance)
99114
.unique_by(|instance| instance.package_id())
100115
.collect();
101116
let proc_macros =
@@ -107,6 +122,7 @@ impl WorkspaceProcMacros {
107122

108123
Ok(Self {
109124
macros_for_components,
125+
instance_to_hash,
110126
})
111127
}
112128

@@ -189,12 +205,15 @@ impl PluginSuiteAssembler {
189205
}
190206
}
191207

208+
type InstanceAndHash = (Arc<ProcMacroInstance>, u64);
209+
192210
/// Collects [`ProcMacroInstances`]s for each component of the [`CairoCompilationUnit`],
193211
/// according to the dependencies on procedural macros.
194212
fn collect_proc_macros(
195213
workspace: &Workspace<'_>,
196214
unit: &CairoCompilationUnit,
197-
) -> Result<HashMap<CompilationUnitComponentId, Vec<Arc<ProcMacroInstance>>>> {
215+
include_hash: bool,
216+
) -> Result<HashMap<CompilationUnitComponentId, Vec<InstanceAndHash>>> {
198217
let mut proc_macros_for_components = HashMap::new();
199218

200219
for component in unit.components.iter() {
@@ -215,7 +234,19 @@ fn collect_proc_macros(
215234
continue;
216235
}
217236

218-
component_proc_macro_instances.push(plugin.instantiate(workspace.config())?);
237+
// We have to disable it in regular scarb in order to `--no-proc-macros` flag work correctly
238+
let hash = if include_hash {
239+
workspace
240+
.config()
241+
.tokio_handle()
242+
.block_on(PluginFingerprint::try_from_plugin(plugin, workspace))?
243+
.digest_u64()
244+
} else {
245+
// This value will be ignored, it does not matter
246+
0
247+
};
248+
249+
component_proc_macro_instances.push((plugin.instantiate(workspace.config())?, hash));
219250
}
220251

221252
proc_macros_for_components.insert(component.id.clone(), component_proc_macro_instances);

scarb/src/compiler/plugin/proc_macro/host.rs

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::compiler::plugin::proc_macro::{ExpansionQuery, ProcMacroInstance};
22
use crate::compiler::plugin::{ProcMacroApiVersion, proc_macro};
3+
use crate::core::PackageId;
34
use anyhow::Result;
45
use cairo_lang_semantic::db::SemanticGroup;
56
use cairo_lang_semantic::plugin::PluginSuite;
@@ -76,48 +77,69 @@ pub trait DeclaredProcMacroInstances {
7677
})
7778
}
7879

79-
// NOTE: Required for proc macro server. `<ProcMacroHostPlugin as MacroPlugin>::declared_attributes`
80-
// returns attributes **and** executables. In PMS, we only need the former because the latter is handled separately.
81-
fn declared_attributes_without_executables(&self) -> Vec<String> {
80+
fn declared_inline_macros(&self) -> Vec<String> {
8281
self.instances()
8382
.iter()
84-
.flat_map(|instance| instance.declared_attributes())
83+
.flat_map(|instance| instance.inline_macros())
8584
.collect()
8685
}
8786

88-
fn declared_inline_macros(&self) -> Vec<String> {
87+
fn declared_derives(&self) -> Vec<String> {
8988
self.instances()
9089
.iter()
91-
.flat_map(|instance| instance.inline_macros())
90+
.flat_map(|m| m.declared_derives())
9291
.collect()
9392
}
9493

95-
fn declared_derives(&self) -> Vec<String> {
94+
fn executable_attributes(&self) -> Vec<String> {
9695
self.instances()
9796
.iter()
98-
.flat_map(|m| m.declared_derives())
97+
.flat_map(|m| m.executable_attributes())
9998
.collect()
10099
}
101100

102-
fn declared_derives_snake_case(&self) -> Vec<String> {
101+
fn declared_attributes(&self) -> Vec<String> {
103102
self.instances()
104103
.iter()
105-
.flat_map(|m| m.declared_derives_snake_case())
104+
.flat_map(|m| m.declared_attributes_and_executables())
105+
.chain(vec![FULL_PATH_MARKER_KEY.to_string()])
106106
.collect()
107107
}
108108

109-
fn executable_attributes(&self) -> Vec<String> {
109+
// NOTE: Required for proc macro server. `<ProcMacroHostPlugin as MacroPlugin>::declared_attributes`
110+
// returns attributes **and** executables. In PMS, we only need the former because the latter is handled separately.
111+
fn declared_attributes_without_executables_with_package(&self) -> Vec<(String, PackageId)> {
110112
self.instances()
111113
.iter()
112-
.flat_map(|m| m.executable_attributes())
114+
.flat_map(|instance| {
115+
instance
116+
.declared_attributes()
117+
.into_iter()
118+
.map(|name| (name, instance.package_id()))
119+
})
113120
.collect()
114121
}
115122

116-
fn declared_attributes(&self) -> Vec<String> {
123+
fn declared_inline_macros_with_package(&self) -> Vec<(String, PackageId)> {
117124
self.instances()
118125
.iter()
119-
.flat_map(|m| m.declared_attributes_and_executables())
120-
.chain(vec![FULL_PATH_MARKER_KEY.to_string()])
126+
.flat_map(|instance| {
127+
instance
128+
.inline_macros()
129+
.into_iter()
130+
.map(|name| (name, instance.package_id()))
131+
})
132+
.collect()
133+
}
134+
135+
fn declared_derives_snake_case_with_package(&self) -> Vec<(String, PackageId)> {
136+
self.instances()
137+
.iter()
138+
.flat_map(|m| {
139+
m.declared_derives_snake_case()
140+
.into_iter()
141+
.map(|name| (name, m.package_id()))
142+
})
121143
.collect()
122144
}
123145
}

scarb/src/compiler/plugin/proc_macro/instance.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use camino::{Utf8Path, Utf8PathBuf};
88
use serde::{Deserialize, Serialize};
99
use smol_str::SmolStr;
1010
use std::fmt::Debug;
11+
use std::hash::Hash;
1112
use tracing::trace;
1213

1314
#[derive(

scarb/src/ops/proc_macro_server/methods/defined_macros.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use anyhow::Result;
44
use camino::Utf8Path;
55
use itertools::Itertools;
66
use scarb_proc_macro_server_types::methods::defined_macros::{
7-
CompilationUnitComponentMacros, DebugInfo, DefinedMacros, DefinedMacrosResponse,
7+
CompilationUnitComponentMacros, DebugInfo, DefinedMacros, DefinedMacrosResponse, MacroWithHash,
88
};
99

1010
use crate::{
@@ -94,9 +94,30 @@ fn get_macros_for_components(
9494
plugin
9595
.iter()
9696
.map(|plugin| {
97-
let attributes = plugin.declared_attributes_without_executables();
98-
let inline_macros = plugin.declared_inline_macros();
99-
let derives = plugin.declared_derives_snake_case();
97+
let attributes = plugin
98+
.declared_attributes_without_executables_with_package()
99+
.into_iter()
100+
.map(|(name, package)| MacroWithHash {
101+
name,
102+
hash: *workspace_macros.instance_to_hash.get(&package).unwrap(),
103+
})
104+
.collect();
105+
let inline_macros = plugin
106+
.declared_inline_macros_with_package()
107+
.into_iter()
108+
.map(|(name, package)| MacroWithHash {
109+
name,
110+
hash: *workspace_macros.instance_to_hash.get(&package).unwrap(),
111+
})
112+
.collect();
113+
let derives = plugin
114+
.declared_derives_snake_case_with_package()
115+
.into_iter()
116+
.map(|(name, package)| MacroWithHash {
117+
name,
118+
hash: *workspace_macros.instance_to_hash.get(&package).unwrap(),
119+
})
120+
.collect();
100121
let executables = plugin.executable_attributes();
101122
let source_packages = plugin
102123
.instances()

scarb/src/ops/proc_macro_server/methods/expand_attribute.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ use scarb_proc_macro_server_types::methods::{ProcMacroResult, expand::ExpandAttr
99
use super::{Handler, interface_code_mapping_from_cairo};
1010
use crate::compiler::plugin::proc_macro::v2::generate_code_mappings;
1111
use crate::compiler::plugin::proc_macro::{
12-
DeclaredProcMacroInstances, ExpansionKind, ExpansionQuery, ProcMacroApiVersion,
13-
ProcMacroInstance,
12+
ExpansionKind, ExpansionQuery, ProcMacroApiVersion, ProcMacroInstance,
1413
};
1514
use crate::core::Config;
1615
use crate::ops::store::ProcMacroStore;
@@ -29,34 +28,37 @@ impl Handler for ExpandAttribute {
2928
adapted_call_site,
3029
} = params;
3130
let expansion = ExpansionQuery::with_expansion_name(&attr, ExpansionKind::Attr);
32-
let plugins = proc_macros.lock().unwrap().get_plugins(&context);
33-
let proc_macro_instance = plugins
34-
.as_ref()
35-
.and_then(|v| {
36-
v.iter()
37-
.filter_map(|plugin| plugin.find_instance_with_expansion(&expansion))
38-
.next()
39-
})
31+
let (proc_macro_instance, hash) = proc_macros
32+
.lock()
33+
.unwrap()
34+
.get_instance_and_hash(&context, &expansion)
4035
.with_context(|| {
4136
format!("No \"{attr}\" attribute macros found in scope: {context:?}")
4237
})?;
4338

4439
match proc_macro_instance.api_version() {
4540
ProcMacroApiVersion::V1 => expand_attribute_v1(
46-
proc_macro_instance,
41+
&proc_macro_instance,
42+
hash,
4743
attr,
4844
token_stream_v2_to_v1(&args),
4945
token_stream_v2_to_v1(&item),
5046
),
51-
ProcMacroApiVersion::V2 => {
52-
expand_attribute_v2(proc_macro_instance, attr, adapted_call_site, args, item)
53-
}
47+
ProcMacroApiVersion::V2 => expand_attribute_v2(
48+
&proc_macro_instance,
49+
hash,
50+
attr,
51+
adapted_call_site,
52+
args,
53+
item,
54+
),
5455
}
5556
}
5657
}
5758

5859
fn expand_attribute_v1(
5960
proc_macro_instance: &Arc<ProcMacroInstance>,
61+
fingerprint: u64,
6062
attr: String,
6163
args: TokenStreamV1,
6264
item: TokenStreamV1,
@@ -69,11 +71,13 @@ fn expand_attribute_v1(
6971
token_stream: result.token_stream,
7072
diagnostics: result.diagnostics.iter().map(diagnostic_v1_to_v2).collect(),
7173
code_mappings: None,
74+
fingerprint,
7275
})
7376
}
7477

7578
fn expand_attribute_v2(
7679
proc_macro_instance: &Arc<ProcMacroInstance>,
80+
fingerprint: u64,
7781
attr: String,
7882
adapted_call_site: TextSpan,
7983
args: TokenStreamV2,
@@ -96,5 +100,6 @@ fn expand_attribute_v2(
96100
.map(interface_code_mapping_from_cairo)
97101
.collect(),
98102
),
103+
fingerprint,
99104
})
100105
}

0 commit comments

Comments
 (0)