Skip to content

Commit a4dd515

Browse files
committed
wip
1 parent f24e37a commit a4dd515

File tree

9 files changed

+117
-63
lines changed

9 files changed

+117
-63
lines changed

crates/compilers/src/artifact_output/mod.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pub struct ArtifactId {
5252
pub version: Version,
5353
/// `solc` build id
5454
pub build_id: String,
55+
pub profile: String,
5556
}
5657

5758
impl ArtifactId {
@@ -299,6 +300,7 @@ impl<T> Artifacts<T> {
299300
source: source.clone(),
300301
version: artifact.version.clone(),
301302
build_id: artifact.build_id.clone(),
303+
profile: artifact.profile.clone(),
302304
}
303305
.with_slashed_paths(),
304306
&artifact.artifact,
@@ -325,6 +327,7 @@ impl<T> Artifacts<T> {
325327
source: source.clone(),
326328
version: artifact.version,
327329
build_id: artifact.build_id.clone(),
330+
profile: artifact.profile.clone(),
328331
}
329332
.with_slashed_paths(),
330333
artifact.artifact,
@@ -873,13 +876,11 @@ pub trait ArtifactOutput {
873876
let unique_profiles =
874877
versioned_contracts.iter().map(|c| &c.profile).collect::<HashSet<_>>();
875878
for contract in versioned_contracts {
879+
non_standalone_sources.insert(file);
880+
876881
// track `SourceFile`s that can be mapped to contracts
877882
let source_file = sources.find_file_and_version(file, &contract.version);
878883

879-
if let Some(source) = source_file {
880-
non_standalone_sources.insert((source.id, &contract.version));
881-
}
882-
883884
let artifact_path = Self::get_artifact_path(
884885
&ctx,
885886
&taken_paths_lowercase,
@@ -934,7 +935,7 @@ pub trait ArtifactOutput {
934935
let unique_versions = sources.iter().map(|s| &s.version).collect::<HashSet<_>>();
935936
let unique_profiles = sources.iter().map(|s| &s.profile).collect::<HashSet<_>>();
936937
for source in sources {
937-
if !non_standalone_sources.contains(&(source.source_file.id, &source.version)) {
938+
if !non_standalone_sources.contains(file) {
938939
// scan the ast as a safe measure to ensure this file does not include any
939940
// source units
940941
// there's also no need to create a standalone artifact for source files that
@@ -962,24 +963,21 @@ pub trait ArtifactOutput {
962963
unique_profiles.len() > 1,
963964
);
964965

965-
let entries = artifacts
966+
taken_paths_lowercase
967+
.insert(artifact_path.to_slash_lossy().to_lowercase());
968+
969+
artifacts
966970
.entry(file.clone())
967971
.or_default()
968972
.entry(name.to_string())
969-
.or_default();
970-
971-
if entries.iter().all(|entry| entry.version != source.version) {
972-
taken_paths_lowercase
973-
.insert(artifact_path.to_slash_lossy().to_lowercase());
974-
975-
entries.push(ArtifactFile {
973+
.or_default()
974+
.push(ArtifactFile {
976975
artifact,
977976
file: artifact_path,
978977
version: source.version.clone(),
979978
build_id: source.build_id.clone(),
980979
profile: source.profile.clone(),
981980
});
982-
}
983981
}
984982
}
985983
}

crates/compilers/src/cache.rs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,6 @@ impl<S: CompilerSettings> CompilerCache<S> {
6464
self.files.is_empty()
6565
}
6666

67-
/// Returns `true` if the cache contains any artifacts for the given file and version.
68-
pub fn contains(&self, file: &Path, version: &Version) -> bool {
69-
self.files.get(file).map_or(true, |entry| !entry.contains_version(version))
70-
}
71-
7267
/// Removes entry for the given file
7368
pub fn remove(&mut self, file: &Path) -> Option<CacheEntry> {
7469
self.files.remove(file)
@@ -533,8 +528,10 @@ impl CacheEntry {
533528
}
534529

535530
/// Returns `true` if the artifacts set contains the given version
536-
pub fn contains_version(&self, version: &Version) -> bool {
537-
self.artifacts_versions().any(|(v, _, _)| v == version)
531+
pub fn contains(&self, version: &Version, profile: &str) -> bool {
532+
self.artifacts.values().any(|artifacts| {
533+
artifacts.get(version).and_then(|artifacts| artifacts.get(profile)).is_some()
534+
})
538535
}
539536

540537
/// Iterator that yields all artifact files and their version
@@ -688,7 +685,7 @@ impl<'a, T: ArtifactOutput, C: Compiler> ArtifactsCacheInner<'a, T, C> {
688685
/// 2. [SourceCompilationKind::Optimized] - the file is not dirty, but is imported by a dirty
689686
/// file and thus will be processed by solc. For such files we don't need full data, so we
690687
/// are marking them as clean to optimize output selection later.
691-
fn filter(&mut self, sources: &mut Sources, version: &Version) {
688+
fn filter(&mut self, sources: &mut Sources, version: &Version, profile: &str) {
692689
// sources that should be passed to compiler.
693690
let mut compile_complete = HashSet::new();
694691
let mut compile_optimized = HashSet::new();
@@ -697,7 +694,7 @@ impl<'a, T: ArtifactOutput, C: Compiler> ArtifactsCacheInner<'a, T, C> {
697694
self.sources_in_scope.insert(file.clone(), version.clone());
698695

699696
// If we are missing artifact for file, compile it.
700-
if self.is_missing_artifacts(file, version) {
697+
if self.is_missing_artifacts(file, version, profile) {
701698
compile_complete.insert(file.clone());
702699
}
703700

@@ -731,7 +728,7 @@ impl<'a, T: ArtifactOutput, C: Compiler> ArtifactsCacheInner<'a, T, C> {
731728

732729
/// Returns whether we are missing artifacts for the given file and version.
733730
#[instrument(level = "trace", skip(self))]
734-
fn is_missing_artifacts(&self, file: &Path, version: &Version) -> bool {
731+
fn is_missing_artifacts(&self, file: &Path, version: &Version, profile: &str) -> bool {
735732
let Some(entry) = self.cache.entry(file) else {
736733
trace!("missing cache entry");
737734
return true;
@@ -745,7 +742,7 @@ impl<'a, T: ArtifactOutput, C: Compiler> ArtifactsCacheInner<'a, T, C> {
745742
return false;
746743
}
747744

748-
if !entry.contains_version(version) {
745+
if !entry.contains(version, profile) {
749746
trace!("missing linked artifacts");
750747
return true;
751748
}
@@ -788,6 +785,7 @@ impl<'a, T: ArtifactOutput, C: Compiler> ArtifactsCacheInner<'a, T, C> {
788785
.get(profile.as_str())
789786
.map_or(false, |p| p.can_use_cached(settings))
790787
{
788+
trace!("dirty profile: {}", profile);
791789
dirty_profiles.insert(profile.clone());
792790
}
793791
}
@@ -796,15 +794,20 @@ impl<'a, T: ArtifactOutput, C: Compiler> ArtifactsCacheInner<'a, T, C> {
796794
self.cache.profiles.remove(profile);
797795
}
798796

799-
for (_, entry) in &mut self.cache.files {
797+
self.cache.files.retain(|_, entry| {
798+
// keep entries which already had no artifacts
799+
if entry.artifacts.is_empty() {
800+
return true;
801+
}
800802
entry.artifacts.retain(|_, artifacts| {
801803
artifacts.retain(|_, artifacts| {
802804
artifacts.retain(|profile, _| !dirty_profiles.contains(profile));
803805
!artifacts.is_empty()
804806
});
805807
!artifacts.is_empty()
806808
});
807-
}
809+
!entry.artifacts.is_empty()
810+
});
808811

809812
for (profile, settings) in existing_profiles {
810813
if !self.cache.profiles.contains_key(profile) {
@@ -1031,10 +1034,10 @@ impl<'a, T: ArtifactOutput, C: Compiler> ArtifactsCache<'a, T, C> {
10311034
}
10321035

10331036
/// Filters out those sources that don't need to be compiled
1034-
pub fn filter(&mut self, sources: &mut Sources, version: &Version) {
1037+
pub fn filter(&mut self, sources: &mut Sources, version: &Version, profile: &str) {
10351038
match self {
10361039
ArtifactsCache::Ephemeral(..) => {}
1037-
ArtifactsCache::Cached(cache) => cache.filter(sources, version),
1040+
ArtifactsCache::Cached(cache) => cache.filter(sources, version, profile),
10381041
}
10391042
}
10401043

crates/compilers/src/compile/project.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,9 +392,9 @@ impl<L: Language, S: CompilerSettings> CompilerSources<'_, L, S> {
392392
) {
393393
cache.remove_dirty_sources();
394394
for versioned_sources in self.sources.values_mut() {
395-
for (version, sources, _) in versioned_sources {
395+
for (version, sources, (profile, _)) in versioned_sources {
396396
trace!("Filtering {} sources for {}", sources.len(), version);
397-
cache.filter(sources, version);
397+
cache.filter(sources, version, profile);
398398
trace!(
399399
"Detected {} sources to compile {:?}",
400400
sources.dirty().count(),

crates/compilers/src/compilers/multi.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ pub struct MultiCompilerRestrictions {
138138
}
139139

140140
impl CompilerSettingsRestrictions for MultiCompilerRestrictions {
141-
fn merge(&mut self, other: &Self) {
142-
self.solc.merge(&other.solc);
143-
self.vyper.merge(&other.vyper);
141+
fn merge(&mut self, other: Self) {
142+
self.solc.merge(other.solc);
143+
self.vyper.merge(other.vyper);
144144
}
145145
}
146146

crates/compilers/src/compilers/restrictions.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,40 @@ use std::{
66
use semver::VersionReq;
77

88
pub trait CompilerSettingsRestrictions: Debug + Sync + Send + Clone + Default {
9-
fn merge(&mut self, other: &Self);
9+
fn merge(&mut self, other: Self);
1010
}
1111

1212
/// Combines [CompilerVersionRestriction] with a restrictions on compiler versions for a given
1313
/// source file.
1414
#[derive(Debug, Clone, Default)]
1515
pub struct RestrictionsWithVersion<T> {
1616
pub version: Option<VersionReq>,
17-
pub settings: T,
17+
pub restrictions: T,
18+
}
19+
20+
impl<T: CompilerSettingsRestrictions> RestrictionsWithVersion<T> {
21+
pub fn merge(&mut self, other: Self) {
22+
if let Some(version) = other.version {
23+
if let Some(self_version) = self.version.as_mut() {
24+
self_version.comparators.extend(version.comparators);
25+
} else {
26+
self.version = Some(version.clone());
27+
}
28+
}
29+
self.restrictions.merge(other.restrictions);
30+
}
1831
}
1932

2033
impl<T> Deref for RestrictionsWithVersion<T> {
2134
type Target = T;
2235

2336
fn deref(&self) -> &Self::Target {
24-
&self.settings
37+
&self.restrictions
2538
}
2639
}
2740

2841
impl<T> DerefMut for RestrictionsWithVersion<T> {
2942
fn deref_mut(&mut self) -> &mut Self::Target {
30-
&mut self.settings
43+
&mut self.restrictions
3144
}
3245
}

crates/compilers/src/compilers/solc/mod.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,13 +234,27 @@ pub struct SolcRestrictions {
234234
}
235235

236236
impl CompilerSettingsRestrictions for SolcRestrictions {
237-
fn merge(&mut self, other: &Self) {
237+
fn merge(&mut self, other: Self) {
238238
self.evm_version.merge(&other.evm_version);
239239

240240
// Preserve true
241241
if self.via_ir.map_or(true, |via_ir| !via_ir) {
242242
self.via_ir = other.via_ir;
243243
}
244+
245+
if self
246+
.min_optimizer_runs
247+
.map_or(true, |min| min < other.min_optimizer_runs.unwrap_or(usize::MAX))
248+
{
249+
self.min_optimizer_runs = other.min_optimizer_runs;
250+
}
251+
252+
if self
253+
.max_optimizer_runs
254+
.map_or(true, |max| max > other.max_optimizer_runs.unwrap_or(usize::MIN))
255+
{
256+
self.max_optimizer_runs = other.max_optimizer_runs;
257+
}
244258
}
245259
}
246260

crates/compilers/src/compilers/vyper/settings.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub struct VyperRestrictions {
1313
}
1414

1515
impl CompilerSettingsRestrictions for VyperRestrictions {
16-
fn merge(&mut self, other: &Self) {
16+
fn merge(&mut self, other: Self) {
1717
self.evm_version.merge(&other.evm_version);
1818
}
1919
}

crates/compilers/src/resolver/mod.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ impl<L: Language, D: ParsedSource<Language = L>> Graph<D> {
500500
}
501501

502502
let versioned_nodes = self.get_input_node_versions(project)?;
503-
let versioned_nodes = self.resolve_settings(project, versioned_nodes);
503+
let versioned_nodes = self.resolve_settings(project, versioned_nodes)?;
504504
let (nodes, edges) = self.split();
505505

506506
let mut all_nodes = nodes.into_iter().enumerate().collect::<HashMap<_, _>>();
@@ -557,16 +557,20 @@ impl<L: Language, D: ParsedSource<Language = L>> Graph<D> {
557557
/// path/to/c.sol (<version>)
558558
/// ...
559559
/// ```
560-
fn format_imports_list<W: std::fmt::Write>(
560+
fn format_imports_list<W: std::fmt::Write, C: Compiler<Language = L>, T: ArtifactOutput>(
561561
&self,
562562
idx: usize,
563+
project: &Project<C, T>,
563564
f: &mut W,
564565
) -> std::result::Result<(), std::fmt::Error> {
565566
let node = self.node(idx);
566567
write!(f, "{} ", utils::source_name(&node.path, &self.root).display())?;
567568
if let Some(req) = node.data.version_req() {
568569
write!(f, "{req}")?;
569570
}
571+
if let Some(req) = project.restrictions.get(&node.path).and_then(|r| r.version.as_ref()) {
572+
write!(f, "{req}")?;
573+
}
570574
write!(f, " imports:")?;
571575
for dep in self.node_ids(idx).skip(1) {
572576
let dep = self.node(dep);
@@ -701,7 +705,7 @@ impl<L: Language, D: ParsedSource<Language = L>> Graph<D> {
701705
));
702706
} else {
703707
let mut msg = String::new();
704-
self.format_imports_list(idx, &mut msg).unwrap();
708+
self.format_imports_list(idx, project, &mut msg).unwrap();
705709
errors.push(format!("Found incompatible versions:\n{msg}"));
706710
}
707711

@@ -762,34 +766,37 @@ impl<L: Language, D: ParsedSource<Language = L>> Graph<D> {
762766
&self,
763767
project: &Project<C, T>,
764768
input_nodes_versions: HashMap<L, HashMap<Version, Vec<usize>>>,
765-
) -> HashMap<L, HashMap<Version, HashMap<usize, Vec<usize>>>> {
769+
) -> Result<HashMap<L, HashMap<Version, HashMap<usize, Vec<usize>>>>> {
766770
let mut resulted_sources = HashMap::new();
771+
let mut errors = Vec::new();
767772
for (language, versions) in input_nodes_versions {
768773
let mut versioned_sources = HashMap::new();
769774
for (version, nodes) in versions {
770775
let mut profile_to_nodes = HashMap::new();
771776
for idx in nodes {
772-
println!("resolving {:?}", self.node(idx).path.display());
773777
let mut profile_candidates =
774778
project.settings_profiles().enumerate().collect::<Vec<_>>();
775779
self.retain_compatible_profiles(idx, project, &mut profile_candidates);
776780

777781
if let Some((profile_idx, _)) = profile_candidates.first() {
778782
profile_to_nodes.entry(*profile_idx).or_insert_with(Vec::new).push(idx);
779783
} else {
780-
panic!(
781-
"failed to resolve settings for node {}",
782-
self.node(idx).path.display()
783-
);
784+
let mut msg = String::new();
785+
self.format_imports_list(idx, project, &mut msg).unwrap();
786+
errors.push(format!("Found incompatible settings restrictions:\n{msg}"));
784787
}
785-
println!("resolved");
786788
}
787789
versioned_sources.insert(version, profile_to_nodes);
788790
}
789791
resulted_sources.insert(language, versioned_sources);
790792
}
791793

792-
resulted_sources
794+
if errors.is_empty() {
795+
Ok(resulted_sources)
796+
} else {
797+
error!("failed to resolve settings");
798+
Err(SolcError::msg(errors.join("\n")))
799+
}
793800
}
794801

795802
/// Tries to find the "best" set of versions to nodes, See [Solc version

0 commit comments

Comments
 (0)