From a087dbf51900cbd6295884922828ca8015f9b18d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Federico=20Rodr=C3=ADguez?= Date: Wed, 4 Dec 2024 12:46:31 -0300 Subject: [PATCH] refactor: make Contract generic for Compiler and add metadata to CompilerOutput (#224) Right now the compiler abstraction has two couplings that force foundry-zksync to implement it's [own fork of compilers](https://github.com/Moonsong-Labs/compilers/tree/zksync-v0.11.6): 1. `Contract` is specific to `solc`/EVM contracts. Era VM contracts, while requiring different fields, still could use most of the functionality of the `compilers` pipeline. 2. `CompilerOutput` has `solc` specific fields. `zksolc` compilation has relevant information that is useful to have later on, for example when storing `BuildInfo` This PR implements changes to address this. If implemented, it would allow `foundry-zksync` (and potentially other non EVM implementations of foundry) to get rid of all overrides and only maintain ZKsync specific data structures/trait implementations. See [sample PR](https://github.com/Moonsong-Labs/compilers/pull/42). Changes include: 1. Make `Compiler` generic over `Contract` (using `CompilerContract` as a trait type). 2. Add `metadata` field to `CompilerOutput` in order to add arbitrary data to compilation output. --------- Co-authored-by: Nisheeth Barthwal Co-authored-by: Arsenii Kulikov --- .../src/artifact_output/configurable.rs | 3 +- crates/compilers/src/artifact_output/hh.rs | 1 + crates/compilers/src/artifact_output/mod.rs | 29 +++---- crates/compilers/src/buildinfo.rs | 16 ++-- crates/compilers/src/cache.rs | 22 ++++-- .../compilers/src/compile/output/contracts.rs | 75 +++++++++++------- crates/compilers/src/compile/output/mod.rs | 52 +++++++------ crates/compilers/src/compile/project.rs | 45 +++++++---- crates/compilers/src/compilers/mod.rs | 78 ++++++++++++++++--- crates/compilers/src/compilers/multi.rs | 8 +- crates/compilers/src/compilers/solc/mod.rs | 12 ++- crates/compilers/src/compilers/vyper/mod.rs | 8 +- .../compilers/src/compilers/vyper/output.rs | 5 +- crates/compilers/src/flatten.rs | 6 +- crates/compilers/src/lib.rs | 42 ++++++---- crates/compilers/src/project_util/mod.rs | 31 ++++++-- crates/compilers/src/resolver/mod.rs | 38 +++++++-- crates/compilers/tests/project.rs | 10 ++- 18 files changed, 337 insertions(+), 144 deletions(-) diff --git a/crates/compilers/src/artifact_output/configurable.rs b/crates/compilers/src/artifact_output/configurable.rs index 699a5fbc..12574afc 100644 --- a/crates/compilers/src/artifact_output/configurable.rs +++ b/crates/compilers/src/artifact_output/configurable.rs @@ -169,11 +169,12 @@ impl ConfigurableArtifacts { impl ArtifactOutput for ConfigurableArtifacts { type Artifact = ConfigurableContractArtifact; + type CompilerContract = Contract; /// Writes extra files for compiled artifact based on [Self::additional_files] fn handle_artifacts( &self, - contracts: &crate::VersionedContracts, + contracts: &crate::VersionedContracts, artifacts: &crate::Artifacts, ) -> Result<(), SolcError> { for (file, contracts) in contracts.as_ref().iter() { diff --git a/crates/compilers/src/artifact_output/hh.rs b/crates/compilers/src/artifact_output/hh.rs index fe47a9ed..8c85cf2d 100644 --- a/crates/compilers/src/artifact_output/hh.rs +++ b/crates/compilers/src/artifact_output/hh.rs @@ -13,6 +13,7 @@ pub struct HardhatArtifacts { impl ArtifactOutput for HardhatArtifacts { type Artifact = HardhatArtifact; + type CompilerContract = Contract; fn contract_to_artifact( &self, diff --git a/crates/compilers/src/artifact_output/mod.rs b/crates/compilers/src/artifact_output/mod.rs index 493fe98b..d111d07c 100644 --- a/crates/compilers/src/artifact_output/mod.rs +++ b/crates/compilers/src/artifact_output/mod.rs @@ -37,7 +37,7 @@ use crate::{ contracts::VersionedContracts, sources::{VersionedSourceFile, VersionedSourceFiles}, }, - ProjectPathsConfig, + CompilerContract, ProjectPathsConfig, }; /// Represents unique artifact metadata for identifying artifacts on output @@ -110,7 +110,7 @@ impl ArtifactId { } } -/// Represents an artifact file representing a [`crate::Contract`] +/// Represents an artifact file representing a [`crate::compilers::CompilerContract`] #[derive(Clone, Debug, PartialEq, Eq)] pub struct ArtifactFile { /// The Artifact that was written @@ -428,7 +428,7 @@ impl Artifacts { } } -/// A trait representation for a [`crate::Contract`] artifact +/// A trait representation for a [`crate::compilers::CompilerContract`] artifact pub trait Artifact { /// Returns the artifact's [`JsonAbi`] and bytecode. fn into_inner(self) -> (Option, Option); @@ -596,9 +596,9 @@ where /// Handler invoked with the output of `solc` /// -/// Implementers of this trait are expected to take care of [`crate::Contract`] to -/// [`crate::ArtifactOutput::Artifact`] conversion and how that `Artifact` type is stored on disk, -/// this includes artifact file location and naming. +/// Implementers of this trait are expected to take care of [`crate::compilers::CompilerContract`] +/// to [`crate::ArtifactOutput::Artifact`] conversion and how that `Artifact` type is stored on +/// disk, this includes artifact file location and naming. /// /// Depending on the [`crate::Project`] contracts and their compatible versions, /// The project compiler may invoke different `solc` executables on the same @@ -609,16 +609,17 @@ where pub trait ArtifactOutput { /// Represents the artifact that will be stored for a `Contract` type Artifact: Artifact + DeserializeOwned + Serialize + fmt::Debug + Send + Sync; + type CompilerContract: CompilerContract; /// Handle the aggregated set of compiled contracts from the solc [`crate::CompilerOutput`]. /// /// This will be invoked with all aggregated contracts from (multiple) solc `CompilerOutput`. /// See [`crate::AggregatedCompilerOutput`] - fn on_output( + fn on_output( &self, - contracts: &VersionedContracts, + contracts: &VersionedContracts, sources: &VersionedSourceFiles, - layout: &ProjectPathsConfig, + layout: &ProjectPathsConfig, ctx: OutputContext<'_>, ) -> Result> { let mut artifacts = self.output_to_artifacts(contracts, sources, ctx, layout); @@ -638,7 +639,7 @@ pub trait ArtifactOutput { /// Invoked after artifacts has been written to disk for additional processing. fn handle_artifacts( &self, - _contracts: &VersionedContracts, + _contracts: &VersionedContracts, _artifacts: &Artifacts, ) -> Result<()> { Ok(()) @@ -800,7 +801,7 @@ pub trait ArtifactOutput { &self, _file: &Path, _name: &str, - contract: Contract, + contract: Self::CompilerContract, source_file: Option<&SourceFile>, ) -> Self::Artifact; @@ -845,7 +846,7 @@ pub trait ArtifactOutput { /// [`Self::on_output()`] fn output_to_artifacts( &self, - contracts: &VersionedContracts, + contracts: &VersionedContracts, sources: &VersionedSourceFiles, ctx: OutputContext<'_>, layout: &ProjectPathsConfig, @@ -1083,6 +1084,7 @@ pub struct MinimalCombinedArtifacts { impl ArtifactOutput for MinimalCombinedArtifacts { type Artifact = CompactContractBytecode; + type CompilerContract = Contract; fn contract_to_artifact( &self, @@ -1112,10 +1114,11 @@ pub struct MinimalCombinedArtifactsHardhatFallback { impl ArtifactOutput for MinimalCombinedArtifactsHardhatFallback { type Artifact = CompactContractBytecode; + type CompilerContract = Contract; fn on_output( &self, - output: &VersionedContracts, + output: &VersionedContracts, sources: &VersionedSourceFiles, layout: &ProjectPathsConfig, ctx: OutputContext<'_>, diff --git a/crates/compilers/src/buildinfo.rs b/crates/compilers/src/buildinfo.rs index 571e8471..0d6a82f5 100644 --- a/crates/compilers/src/buildinfo.rs +++ b/crates/compilers/src/buildinfo.rs @@ -1,6 +1,8 @@ //! Represents an entire build -use crate::compilers::{CompilationError, CompilerInput, CompilerOutput, Language}; +use crate::compilers::{ + CompilationError, CompilerContract, CompilerInput, CompilerOutput, Language, +}; use alloy_primitives::hex; use foundry_compilers_core::{error::Result, utils}; use md5::Digest; @@ -43,7 +45,7 @@ pub struct BuildContext { } impl BuildContext { - pub fn new(input: &I, output: &CompilerOutput) -> Result + pub fn new(input: &I, output: &CompilerOutput) -> Result where I: CompilerInput, { @@ -87,9 +89,9 @@ pub struct RawBuildInfo { impl RawBuildInfo { /// Serializes a `BuildInfo` object - pub fn new, E: CompilationError>( + pub fn new, E: CompilationError, C: CompilerContract>( input: &I, - output: &CompilerOutput, + output: &CompilerOutput, full_build_info: bool, ) -> Result { let version = input.version().clone(); @@ -130,7 +132,7 @@ impl RawBuildInfo { mod tests { use super::*; use crate::compilers::solc::SolcVersionedInput; - use foundry_compilers_artifacts::{sources::Source, Error, SolcLanguage, Sources}; + use foundry_compilers_artifacts::{sources::Source, Contract, Error, SolcLanguage, Sources}; use std::path::PathBuf; #[test] @@ -142,9 +144,9 @@ mod tests { SolcLanguage::Solidity, v, ); - let output = CompilerOutput::::default(); + let output = CompilerOutput::::default(); let raw_info = RawBuildInfo::new(&input, &output, true).unwrap(); - let _info: BuildInfo> = + let _info: BuildInfo> = serde_json::from_str(&serde_json::to_string(&raw_info).unwrap()).unwrap(); } } diff --git a/crates/compilers/src/cache.rs b/crates/compilers/src/cache.rs index 17777e66..ec224ec1 100644 --- a/crates/compilers/src/cache.rs +++ b/crates/compilers/src/cache.rs @@ -623,7 +623,11 @@ impl GroupedSources { /// A helper abstraction over the [`CompilerCache`] used to determine what files need to compiled /// and which `Artifacts` can be reused. #[derive(Debug)] -pub(crate) struct ArtifactsCacheInner<'a, T: ArtifactOutput, C: Compiler> { +pub(crate) struct ArtifactsCacheInner< + 'a, + T: ArtifactOutput, + C: Compiler, +> { /// The preexisting cache file. pub cache: CompilerCache, @@ -652,7 +656,9 @@ pub(crate) struct ArtifactsCacheInner<'a, T: ArtifactOutput, C: Compiler> { pub content_hashes: HashMap, } -impl ArtifactsCacheInner<'_, T, C> { +impl, C: Compiler> + ArtifactsCacheInner<'_, T, C> +{ /// Creates a new cache entry for the file fn create_cache_entry(&mut self, file: PathBuf, source: &Source) { let imports = self @@ -905,20 +911,26 @@ impl ArtifactsCacheInner<'_, T, C> { /// Abstraction over configured caching which can be either non-existent or an already loaded cache #[allow(clippy::large_enum_variant)] #[derive(Debug)] -pub(crate) enum ArtifactsCache<'a, T: ArtifactOutput, C: Compiler> { +pub(crate) enum ArtifactsCache< + 'a, + T: ArtifactOutput, + C: Compiler, +> { /// Cache nothing on disk Ephemeral(GraphEdges, &'a Project), /// Handles the actual cached artifacts, detects artifacts that can be reused Cached(ArtifactsCacheInner<'a, T, C>), } -impl<'a, T: ArtifactOutput, C: Compiler> ArtifactsCache<'a, T, C> { +impl<'a, T: ArtifactOutput, C: Compiler> + ArtifactsCache<'a, T, C> +{ /// Create a new cache instance with the given files pub fn new(project: &'a Project, edges: GraphEdges) -> Result { /// Returns the [CompilerCache] to use /// /// Returns a new empty cache if the cache does not exist or `invalidate_cache` is set. - fn get_cache( + fn get_cache, C: Compiler>( project: &Project, invalidate_cache: bool, ) -> CompilerCache { diff --git a/crates/compilers/src/compile/output/contracts.rs b/crates/compilers/src/compile/output/contracts.rs index 004c7d03..9717b857 100644 --- a/crates/compilers/src/compile/output/contracts.rs +++ b/crates/compilers/src/compile/output/contracts.rs @@ -1,6 +1,6 @@ -use crate::ArtifactId; +use crate::{compilers::CompilerContract, ArtifactId}; use foundry_compilers_artifacts::{ - CompactContractBytecode, CompactContractRef, Contract, FileToContractsMap, + CompactContractBytecode, CompactContractRef, FileToContractsMap, }; use semver::Version; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -11,11 +11,20 @@ use std::{ }; /// file -> [(contract name -> Contract + solc version)] -#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(transparent)] -pub struct VersionedContracts(pub FileToContractsMap>); +pub struct VersionedContracts(pub FileToContractsMap>>); + +impl Default for VersionedContracts { + fn default() -> Self { + Self(BTreeMap::new()) + } +} -impl VersionedContracts { +impl VersionedContracts +where + C: CompilerContract, +{ /// Converts all `\\` separators in _all_ paths to `/` pub fn slash_paths(&mut self) { #[cfg(windows)] @@ -53,7 +62,7 @@ impl VersionedContracts { /// ``` pub fn find_first(&self, contract_name: &str) -> Option> { self.contracts().find_map(|(name, contract)| { - (name == contract_name).then(|| CompactContractRef::from(contract)) + (name == contract_name).then(|| contract.as_compact_contract_ref()) }) } @@ -75,7 +84,7 @@ impl VersionedContracts { ) -> Option> { self.contracts_with_files().find_map(|(path, name, contract)| { (path == contract_path && name == contract_name) - .then(|| CompactContractRef::from(contract)) + .then(|| contract.as_compact_contract_ref()) }) } @@ -90,7 +99,7 @@ impl VersionedContracts { /// let contract = contracts.remove_first("Greeter").unwrap(); /// # Ok::<_, Box>(()) /// ``` - pub fn remove_first(&mut self, contract_name: &str) -> Option { + pub fn remove_first(&mut self, contract_name: &str) -> Option { self.0.values_mut().find_map(|all_contracts| { let mut contract = None; if let Some((c, mut contracts)) = all_contracts.remove_entry(contract_name) { @@ -116,7 +125,7 @@ impl VersionedContracts { /// let contract = contracts.remove("src/Greeter.sol".as_ref(), "Greeter").unwrap(); /// # Ok::<_, Box>(()) /// ``` - pub fn remove(&mut self, path: &Path, contract_name: &str) -> Option { + pub fn remove(&mut self, path: &Path, contract_name: &str) -> Option { let (key, mut all_contracts) = self.0.remove_entry(path)?; let mut contract = None; if let Some((c, mut contracts)) = all_contracts.remove_entry(contract_name) { @@ -142,18 +151,18 @@ impl VersionedContracts { .and_then(|contracts| { contracts.get(contract).and_then(|c| c.first().map(|c| &c.contract)) }) - .map(CompactContractRef::from) + .map(|c| c.as_compact_contract_ref()) } /// Returns an iterator over all contracts and their names. - pub fn contracts(&self) -> impl Iterator { + pub fn contracts(&self) -> impl Iterator { self.0 .values() .flat_map(|c| c.iter().flat_map(|(name, c)| c.iter().map(move |c| (name, &c.contract)))) } /// Returns an iterator over (`file`, `name`, `Contract`). - pub fn contracts_with_files(&self) -> impl Iterator { + pub fn contracts_with_files(&self) -> impl Iterator { self.0.iter().flat_map(|(file, contracts)| { contracts .iter() @@ -164,7 +173,7 @@ impl VersionedContracts { /// Returns an iterator over (`file`, `name`, `Contract`, `Version`). pub fn contracts_with_files_and_version( &self, - ) -> impl Iterator { + ) -> impl Iterator { self.0.iter().flat_map(|(file, contracts)| { contracts.iter().flat_map(move |(name, c)| { c.iter().map(move |c| (file, name, &c.contract, &c.version)) @@ -173,7 +182,7 @@ impl VersionedContracts { } /// Returns an iterator over all contracts and their source names. - pub fn into_contracts(self) -> impl Iterator { + pub fn into_contracts(self) -> impl Iterator { self.0.into_values().flat_map(|c| { c.into_iter() .flat_map(|(name, c)| c.into_iter().map(move |c| (name.clone(), c.contract))) @@ -181,7 +190,7 @@ impl VersionedContracts { } /// Returns an iterator over (`file`, `name`, `Contract`) - pub fn into_contracts_with_files(self) -> impl Iterator { + pub fn into_contracts_with_files(self) -> impl Iterator { self.0.into_iter().flat_map(|(file, contracts)| { contracts.into_iter().flat_map(move |(name, c)| { let file = file.clone(); @@ -193,7 +202,7 @@ impl VersionedContracts { /// Returns an iterator over (`file`, `name`, `Contract`, `Version`) pub fn into_contracts_with_files_and_version( self, - ) -> impl Iterator { + ) -> impl Iterator { self.0.into_iter().flat_map(|(file, contracts)| { contracts.into_iter().flat_map(move |(name, c)| { let file = file.clone(); @@ -226,30 +235,42 @@ impl VersionedContracts { } } -impl AsRef>> for VersionedContracts { - fn as_ref(&self) -> &FileToContractsMap> { +impl AsRef>>> for VersionedContracts +where + C: CompilerContract, +{ + fn as_ref(&self) -> &FileToContractsMap>> { &self.0 } } -impl AsMut>> for VersionedContracts { - fn as_mut(&mut self) -> &mut FileToContractsMap> { +impl AsMut>>> for VersionedContracts +where + C: CompilerContract, +{ + fn as_mut(&mut self) -> &mut FileToContractsMap>> { &mut self.0 } } -impl Deref for VersionedContracts { - type Target = FileToContractsMap>; +impl Deref for VersionedContracts +where + C: CompilerContract, +{ + type Target = FileToContractsMap>>; fn deref(&self) -> &Self::Target { &self.0 } } -impl IntoIterator for VersionedContracts { - type Item = (PathBuf, BTreeMap>); +impl IntoIterator for VersionedContracts +where + C: CompilerContract, +{ + type Item = (PathBuf, BTreeMap>>); type IntoIter = - std::collections::btree_map::IntoIter>>; + std::collections::btree_map::IntoIter>>>; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() @@ -258,8 +279,8 @@ impl IntoIterator for VersionedContracts { /// A contract and the compiler version used to compile it #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct VersionedContract { - pub contract: Contract, +pub struct VersionedContract { + pub contract: C, pub version: Version, pub build_id: String, pub profile: String, diff --git a/crates/compilers/src/compile/output/mod.rs b/crates/compilers/src/compile/output/mod.rs index 193ef1dd..6b4db352 100644 --- a/crates/compilers/src/compile/output/mod.rs +++ b/crates/compilers/src/compile/output/mod.rs @@ -1,8 +1,6 @@ //! The output of a compiled project use contracts::{VersionedContract, VersionedContracts}; -use foundry_compilers_artifacts::{ - CompactContractBytecode, CompactContractRef, Contract, Severity, -}; +use foundry_compilers_artifacts::{CompactContractBytecode, CompactContractRef, Severity}; use foundry_compilers_core::error::{SolcError, SolcIoError}; use info::ContractInfoRef; use semver::Version; @@ -18,7 +16,9 @@ use yansi::Paint; use crate::{ buildinfo::{BuildContext, RawBuildInfo}, - compilers::{multi::MultiCompiler, CompilationError, Compiler, CompilerOutput}, + compilers::{ + multi::MultiCompiler, CompilationError, Compiler, CompilerContract, CompilerOutput, + }, Artifact, ArtifactId, ArtifactOutput, Artifacts, ConfigurableArtifacts, }; @@ -65,7 +65,7 @@ impl IntoIterator for Builds { #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct ProjectCompileOutput< C: Compiler = MultiCompiler, - T: ArtifactOutput = ConfigurableArtifacts, + T: ArtifactOutput = ConfigurableArtifacts, > { /// contains the aggregated `CompilerOutput` pub(crate) compiler_output: AggregatedCompilerOutput, @@ -83,7 +83,9 @@ pub struct ProjectCompileOutput< pub(crate) builds: Builds, } -impl ProjectCompileOutput { +impl, C: Compiler> + ProjectCompileOutput +{ /// Converts all `\\` separators in _all_ paths to `/` pub fn slash_paths(&mut self) { self.compiler_output.slash_paths(); @@ -304,7 +306,7 @@ impl ProjectCompileOutput { /// `Contract` pub fn compiled_contracts_by_compiler_version( &self, - ) -> BTreeMap> { + ) -> BTreeMap> { let mut contracts: BTreeMap<_, Vec<_>> = BTreeMap::new(); let versioned_contracts = &self.compiler_output.contracts; for (_, name, contract, version) in versioned_contracts.contracts_with_files_and_version() { @@ -459,7 +461,9 @@ impl ProjectCompileOutput { } } -impl ProjectCompileOutput { +impl> + ProjectCompileOutput +{ /// Returns whether any errors were emitted by the compiler. pub fn has_compiler_errors(&self) -> bool { self.compiler_output.has_error( @@ -488,7 +492,9 @@ impl ProjectCompileOutput { } } -impl fmt::Display for ProjectCompileOutput { +impl> fmt::Display + for ProjectCompileOutput +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if self.compiler_output.is_unchanged() { f.write_str("Nothing to compile") @@ -514,7 +520,7 @@ pub struct AggregatedCompilerOutput { /// All source files combined with the solc version used to compile them pub sources: VersionedSourceFiles, /// All compiled contracts combined with the solc version used to compile them - pub contracts: VersionedContracts, + pub contracts: VersionedContracts, // All the `BuildInfo`s of solc invocations. pub build_infos: Vec>, } @@ -565,12 +571,12 @@ impl AggregatedCompilerOutput { version: Version, build_info: RawBuildInfo, profile: &str, - output: CompilerOutput, + output: CompilerOutput, ) { let build_id = build_info.id.clone(); self.build_infos.push(build_info); - let CompilerOutput { errors, sources, contracts } = output; + let CompilerOutput { errors, sources, contracts, .. } = output; self.errors.extend(errors); for (path, source_file) in sources { @@ -645,7 +651,7 @@ impl AggregatedCompilerOutput { /// let contract = output.remove_first("Greeter").unwrap(); /// # Ok::<_, Box>(()) /// ``` - pub fn remove_first(&mut self, contract: &str) -> Option { + pub fn remove_first(&mut self, contract: &str) -> Option { self.contracts.remove_first(contract) } @@ -660,7 +666,7 @@ impl AggregatedCompilerOutput { /// let contract = output.remove("src/Greeter.sol".as_ref(), "Greeter").unwrap(); /// # Ok::<_, Box>(()) /// ``` - pub fn remove(&mut self, path: &Path, contract: &str) -> Option { + pub fn remove(&mut self, path: &Path, contract: &str) -> Option { self.contracts.remove(path, contract) } @@ -683,7 +689,7 @@ impl AggregatedCompilerOutput { pub fn remove_contract<'a>( &mut self, info: impl Into>, - ) -> Option { + ) -> Option { let ContractInfoRef { path, name } = info.into(); if let Some(path) = path { self.remove(path[..].as_ref(), &name) @@ -693,40 +699,40 @@ impl AggregatedCompilerOutput { } /// Iterate over all contracts and their names - pub fn contracts_iter(&self) -> impl Iterator { + pub fn contracts_iter(&self) -> impl Iterator { self.contracts.contracts() } /// Iterate over all contracts and their names - pub fn contracts_into_iter(self) -> impl Iterator { + pub fn contracts_into_iter(self) -> impl Iterator { self.contracts.into_contracts() } /// Returns an iterator over (`file`, `name`, `Contract`) pub fn contracts_with_files_iter( &self, - ) -> impl Iterator { + ) -> impl Iterator { self.contracts.contracts_with_files() } /// Returns an iterator over (`file`, `name`, `Contract`) pub fn contracts_with_files_into_iter( self, - ) -> impl Iterator { + ) -> impl Iterator { self.contracts.into_contracts_with_files() } /// Returns an iterator over (`file`, `name`, `Contract`, `Version`) pub fn contracts_with_files_and_version_iter( &self, - ) -> impl Iterator { + ) -> impl Iterator { self.contracts.contracts_with_files_and_version() } /// Returns an iterator over (`file`, `name`, `Contract`, `Version`) pub fn contracts_with_files_and_version_into_iter( self, - ) -> impl Iterator { + ) -> impl Iterator { self.contracts.into_contracts_with_files_and_version() } @@ -758,7 +764,7 @@ impl AggregatedCompilerOutput { /// let (sources, contracts) = output.split(); /// # Ok::<_, Box>(()) /// ``` - pub fn split(self) -> (VersionedSourceFiles, VersionedContracts) { + pub fn split(self) -> (VersionedSourceFiles, VersionedContracts) { (self.sources, self.contracts) } @@ -872,7 +878,7 @@ impl AggregatedCompilerOutput { self.contracts.contracts_with_files().filter(|(path, _, _)| *path == contract_path).any( |(_, _, contract)| { - contract.abi.as_ref().is_some_and(|abi| abi.functions.contains_key("IS_TEST")) + contract.abi_ref().is_some_and(|abi| abi.functions.contains_key("IS_TEST")) }, ) } diff --git a/crates/compilers/src/compile/project.rs b/crates/compilers/src/compile/project.rs index 4d634e30..b64feb53 100644 --- a/crates/compilers/src/compile/project.rs +++ b/crates/compilers/src/compile/project.rs @@ -120,7 +120,11 @@ use std::{collections::HashMap, path::PathBuf, time::Instant}; pub(crate) type VersionedSources<'a, L, S> = HashMap>; #[derive(Debug)] -pub struct ProjectCompiler<'a, T: ArtifactOutput, C: Compiler> { +pub struct ProjectCompiler< + 'a, + T: ArtifactOutput, + C: Compiler, +> { /// Contains the relationship of the source files and their imports edges: GraphEdges, project: &'a Project, @@ -128,7 +132,9 @@ pub struct ProjectCompiler<'a, T: ArtifactOutput, C: Compiler> { sources: CompilerSources<'a, C::Language, C::Settings>, } -impl<'a, T: ArtifactOutput, C: Compiler> ProjectCompiler<'a, T, C> { +impl<'a, T: ArtifactOutput, C: Compiler> + ProjectCompiler<'a, T, C> +{ /// Create a new `ProjectCompiler` to bootstrap the compilation process of the project's /// sources. pub fn new(project: &'a Project) -> Result { @@ -211,7 +217,8 @@ impl<'a, T: ArtifactOutput, C: Compiler> ProjectCompiler<'a, T, C> { /// /// The main reason is to debug all states individually #[derive(Debug)] -struct PreprocessedState<'a, T: ArtifactOutput, C: Compiler> { +struct PreprocessedState<'a, T: ArtifactOutput, C: Compiler> +{ /// Contains all the sources to compile. sources: CompilerSources<'a, C::Language, C::Settings>, @@ -219,7 +226,9 @@ struct PreprocessedState<'a, T: ArtifactOutput, C: Compiler> { cache: ArtifactsCache<'a, T, C>, } -impl<'a, T: ArtifactOutput, C: Compiler> PreprocessedState<'a, T, C> { +impl<'a, T: ArtifactOutput, C: Compiler> + PreprocessedState<'a, T, C> +{ /// advance to the next state by compiling all sources fn compile(self) -> Result> { trace!("compiling"); @@ -240,12 +249,14 @@ impl<'a, T: ArtifactOutput, C: Compiler> PreprocessedState<'a, T, C> { /// Represents the state after `solc` was successfully invoked #[derive(Debug)] -struct CompiledState<'a, T: ArtifactOutput, C: Compiler> { +struct CompiledState<'a, T: ArtifactOutput, C: Compiler> { output: AggregatedCompilerOutput, cache: ArtifactsCache<'a, T, C>, } -impl<'a, T: ArtifactOutput, C: Compiler> CompiledState<'a, T, C> { +impl<'a, T: ArtifactOutput, C: Compiler> + CompiledState<'a, T, C> +{ /// advance to the next state by handling all artifacts /// /// Writes all output contracts to disk if enabled in the `Project` and if the build was @@ -303,13 +314,15 @@ impl<'a, T: ArtifactOutput, C: Compiler> CompiledState<'a, T, C> { /// Represents the state after all artifacts were written to disk #[derive(Debug)] -struct ArtifactsState<'a, T: ArtifactOutput, C: Compiler> { +struct ArtifactsState<'a, T: ArtifactOutput, C: Compiler> { output: AggregatedCompilerOutput, cache: ArtifactsCache<'a, T, C>, compiled_artifacts: Artifacts, } -impl ArtifactsState<'_, T, C> { +impl, C: Compiler> + ArtifactsState<'_, T, C> +{ /// Writes the cache file /// /// this concludes the [`Project::compile()`] statemachine @@ -384,7 +397,10 @@ impl CompilerSources<'_, L, S> { } /// Filters out all sources that don't need to be compiled, see [`ArtifactsCache::filter`] - fn filter>( + fn filter< + T: ArtifactOutput, + C: Compiler, + >( &mut self, cache: &mut ArtifactsCache<'_, T, C>, ) { @@ -403,7 +419,10 @@ impl CompilerSources<'_, L, S> { } /// Compiles all the files with `Solc` - fn compile, T: ArtifactOutput>( + fn compile< + C: Compiler, + T: ArtifactOutput, + >( self, cache: &mut ArtifactsCache<'_, T, C>, ) -> Result> { @@ -488,13 +507,13 @@ impl CompilerSources<'_, L, S> { } } -type CompilationResult<'a, I, E> = Result, &'a str, Vec)>>; +type CompilationResult<'a, I, E, C> = Result, &'a str, Vec)>>; /// Compiles the input set sequentially and returns a [Vec] of outputs. fn compile_sequential<'a, C: Compiler>( compiler: &C, jobs: Vec<(C::Input, &'a str, Vec)>, -) -> CompilationResult<'a, C::Input, C::CompilationError> { +) -> CompilationResult<'a, C::Input, C::CompilationError, C::CompilerContract> { jobs.into_iter() .map(|(input, profile, actually_dirty)| { let start = Instant::now(); @@ -516,7 +535,7 @@ fn compile_parallel<'a, C: Compiler>( compiler: &C, jobs: Vec<(C::Input, &'a str, Vec)>, num_jobs: usize, -) -> CompilationResult<'a, C::Input, C::CompilationError> { +) -> CompilationResult<'a, C::Input, C::CompilationError, C::CompilerContract> { // need to get the currently installed reporter before installing the pool, otherwise each new // thread in the pool will get initialized with the default value of the `thread_local!`'s // localkey. This way we keep access to the reporter in the rayon pool diff --git a/crates/compilers/src/compilers/mod.rs b/crates/compilers/src/compilers/mod.rs index d1843dfb..5abb74b7 100644 --- a/crates/compilers/src/compilers/mod.rs +++ b/crates/compilers/src/compilers/mod.rs @@ -1,11 +1,12 @@ use crate::ProjectPathsConfig; +use alloy_json_abi::JsonAbi; use core::fmt; use foundry_compilers_artifacts::{ error::SourceLocation, output_selection::OutputSelection, remappings::Remapping, sources::{Source, Sources}, - Contract, FileToContractsMap, Severity, SourceFile, + BytecodeObject, CompactContractRef, Contract, FileToContractsMap, Severity, SourceFile, }; use foundry_compilers_core::error::Result; use semver::{Version, VersionReq}; @@ -198,19 +199,21 @@ pub trait CompilationError: fn error_code(&self) -> Option; } -/// Output of the compiler, including contracts, sources and errors. Currently only generic over the -/// error but might be extended in the future. +/// Output of the compiler, including contracts, sources, errors and metadata. might be +/// extended to be more generic in the future. #[derive(Debug, Serialize, Deserialize)] -pub struct CompilerOutput { +pub struct CompilerOutput { #[serde(default = "Vec::new", skip_serializing_if = "Vec::is_empty")] pub errors: Vec, - #[serde(default)] - pub contracts: FileToContractsMap, + #[serde(default = "BTreeMap::new")] + pub contracts: FileToContractsMap, #[serde(default)] pub sources: BTreeMap, + #[serde(default, skip_serializing_if = "::std::collections::BTreeMap::is_empty")] + pub metadata: BTreeMap, } -impl CompilerOutput { +impl CompilerOutput { /// Retains only those files the given iterator yields /// /// In other words, removes all contracts for files not included in the iterator @@ -244,18 +247,24 @@ impl CompilerOutput { .collect(); } - pub fn map_err F>(self, op: O) -> CompilerOutput { + pub fn map_err F>(self, op: O) -> CompilerOutput { CompilerOutput { errors: self.errors.into_iter().map(op).collect(), contracts: self.contracts, sources: self.sources, + metadata: self.metadata, } } } -impl Default for CompilerOutput { +impl Default for CompilerOutput { fn default() -> Self { - Self { errors: Vec::new(), contracts: BTreeMap::new(), sources: BTreeMap::new() } + Self { + errors: Vec::new(), + contracts: BTreeMap::new(), + sources: BTreeMap::new(), + metadata: BTreeMap::new(), + } } } @@ -267,6 +276,48 @@ pub trait Language: const FILE_EXTENSIONS: &'static [&'static str]; } +/// Represents a compiled contract +pub trait CompilerContract: Serialize + Send + Sync + Debug + Clone + Eq + Sized { + /// Reference to contract ABI + fn abi_ref(&self) -> Option<&JsonAbi>; + + //// Reference to contract bytecode + fn bin_ref(&self) -> Option<&BytecodeObject>; + + //// Reference to contract runtime bytecode + fn bin_runtime_ref(&self) -> Option<&BytecodeObject>; + + fn as_compact_contract_ref(&self) -> CompactContractRef<'_> { + CompactContractRef { + abi: self.abi_ref(), + bin: self.bin_ref(), + bin_runtime: self.bin_runtime_ref(), + } + } +} + +impl CompilerContract for Contract { + fn abi_ref(&self) -> Option<&JsonAbi> { + self.abi.as_ref() + } + fn bin_ref(&self) -> Option<&BytecodeObject> { + if let Some(ref evm) = self.evm { + evm.bytecode.as_ref().map(|c| &c.object) + } else { + None + } + } + fn bin_runtime_ref(&self) -> Option<&BytecodeObject> { + if let Some(ref evm) = self.evm { + evm.deployed_bytecode + .as_ref() + .and_then(|deployed| deployed.bytecode.as_ref().map(|evm| &evm.object)) + } else { + None + } + } +} + /// The main compiler abstraction trait. /// /// Currently mostly represents a wrapper around compiler binary aware of the version and able to @@ -277,6 +328,8 @@ pub trait Compiler: Send + Sync + Clone { type Input: CompilerInput; /// Error type returned by the compiler. type CompilationError: CompilationError; + /// Output data for each contract + type CompilerContract: CompilerContract; /// Source parser used for resolving imports and version requirements. type ParsedSource: ParsedSource; /// Compiler settings. @@ -287,7 +340,10 @@ pub trait Compiler: Send + Sync + Clone { /// Main entrypoint for the compiler. Compiles given input into [CompilerOutput]. Takes /// ownership over the input and returns back version with potential modifications made to it. /// Returned input is always the one which was seen by the binary. - fn compile(&self, input: &Self::Input) -> Result>; + fn compile( + &self, + input: &Self::Input, + ) -> Result>; /// Returns all versions available locally and remotely. Should return versions with stripped /// metadata. diff --git a/crates/compilers/src/compilers/multi.rs b/crates/compilers/src/compilers/multi.rs index 48b942a8..d206076b 100644 --- a/crates/compilers/src/compilers/multi.rs +++ b/crates/compilers/src/compilers/multi.rs @@ -19,7 +19,7 @@ use foundry_compilers_artifacts::{ output_selection::OutputSelection, remappings::Remapping, sources::{Source, Sources}, - Error, Severity, SolcLanguage, + Contract, Error, Severity, SolcLanguage, }; use foundry_compilers_core::error::{Result, SolcError}; use semver::Version; @@ -280,8 +280,12 @@ impl Compiler for MultiCompiler { type ParsedSource = MultiCompilerParsedSource; type Settings = MultiCompilerSettings; type Language = MultiCompilerLanguage; + type CompilerContract = Contract; - fn compile(&self, input: &Self::Input) -> Result> { + fn compile( + &self, + input: &Self::Input, + ) -> Result> { match input { MultiCompilerInput::Solc(input) => { if let Some(solc) = &self.solc { diff --git a/crates/compilers/src/compilers/solc/mod.rs b/crates/compilers/src/compilers/solc/mod.rs index 218d51cc..5b4756aa 100644 --- a/crates/compilers/src/compilers/solc/mod.rs +++ b/crates/compilers/src/compilers/solc/mod.rs @@ -9,14 +9,14 @@ use foundry_compilers_artifacts::{ output_selection::OutputSelection, remappings::Remapping, sources::{Source, Sources}, - BytecodeHash, Error, EvmVersion, Settings, Severity, SolcInput, + BytecodeHash, Contract, Error, EvmVersion, Settings, Severity, SolcInput, }; use foundry_compilers_core::error::Result; use semver::Version; use serde::{Deserialize, Serialize}; use std::{ borrow::Cow, - collections::BTreeSet, + collections::{BTreeMap, BTreeSet}, ops::{Deref, DerefMut}, path::{Path, PathBuf}, }; @@ -43,8 +43,12 @@ impl Compiler for SolcCompiler { type ParsedSource = SolData; type Settings = SolcSettings; type Language = SolcLanguage; + type CompilerContract = Contract; - fn compile(&self, input: &Self::Input) -> Result> { + fn compile( + &self, + input: &Self::Input, + ) -> Result> { let mut solc = match self { Self::Specific(solc) => solc.clone(), @@ -62,6 +66,7 @@ impl Compiler for SolcCompiler { errors: solc_output.errors, contracts: solc_output.contracts, sources: solc_output.sources, + metadata: BTreeMap::new(), }; Ok(output) @@ -457,6 +462,7 @@ mod tests { errors: out.errors, contracts: Default::default(), sources: Default::default(), + metadata: Default::default(), }; let v = Version::new(0, 8, 12); diff --git a/crates/compilers/src/compilers/vyper/mod.rs b/crates/compilers/src/compilers/vyper/mod.rs index 1b351124..a9cc7f3b 100644 --- a/crates/compilers/src/compilers/vyper/mod.rs +++ b/crates/compilers/src/compilers/vyper/mod.rs @@ -2,7 +2,7 @@ use self::{input::VyperVersionedInput, parser::VyperParsedSource}; use super::{Compiler, CompilerOutput, Language}; pub use crate::artifacts::vyper::{VyperCompilationError, VyperInput, VyperOutput, VyperSettings}; use core::fmt; -use foundry_compilers_artifacts::sources::Source; +use foundry_compilers_artifacts::{sources::Source, Contract}; use foundry_compilers_core::error::{Result, SolcError}; use semver::Version; use serde::{de::DeserializeOwned, Serialize}; @@ -197,8 +197,12 @@ impl Compiler for Vyper { type ParsedSource = VyperParsedSource; type Input = VyperVersionedInput; type Language = VyperLanguage; + type CompilerContract = Contract; - fn compile(&self, input: &Self::Input) -> Result> { + fn compile( + &self, + input: &Self::Input, + ) -> Result> { self.compile(input).map(Into::into) } diff --git a/crates/compilers/src/compilers/vyper/output.rs b/crates/compilers/src/compilers/vyper/output.rs index c4f739dd..822891c5 100644 --- a/crates/compilers/src/compilers/vyper/output.rs +++ b/crates/compilers/src/compilers/vyper/output.rs @@ -1,6 +1,8 @@ +use foundry_compilers_artifacts::Contract; + use crate::artifacts::vyper::{VyperCompilationError, VyperOutput}; -impl From for super::CompilerOutput { +impl From for super::CompilerOutput { fn from(output: VyperOutput) -> Self { Self { errors: output.errors, @@ -10,6 +12,7 @@ impl From for super::CompilerOutput { .map(|(k, v)| (k, v.into_iter().map(|(k, v)| (k, v.into())).collect())) .collect(), sources: output.sources.into_iter().map(|(k, v)| (k, v.into())).collect(), + metadata: Default::default(), } } } diff --git a/crates/compilers/src/flatten.rs b/crates/compilers/src/flatten.rs index e1fdcc4b..12bb0145 100644 --- a/crates/compilers/src/flatten.rs +++ b/crates/compilers/src/flatten.rs @@ -2,7 +2,7 @@ use crate::{ compilers::{Compiler, ParsedSource}, filter::MaybeSolData, resolver::parse::SolData, - CompilerSettings, Graph, Project, ProjectPathsConfig, + ArtifactOutput, CompilerSettings, Graph, Project, ProjectPathsConfig, }; use foundry_compilers_artifacts::{ ast::{visitor::Visitor, *}, @@ -204,8 +204,8 @@ pub struct Flattener { impl Flattener { /// Compiles the target file and prepares AST and analysis data for flattening. - pub fn new( - mut project: Project, + pub fn new>( + mut project: Project, target: &Path, ) -> std::result::Result where diff --git a/crates/compilers/src/lib.rs b/crates/compilers/src/lib.rs index d273cbe8..0d50f39d 100644 --- a/crates/compilers/src/lib.rs +++ b/crates/compilers/src/lib.rs @@ -53,7 +53,7 @@ use foundry_compilers_artifacts::{ output_selection::OutputSelection, solc::{ sources::{Source, SourceCompilationKind, Sources}, - Contract, Severity, SourceFile, StandardJsonCompilerInput, + Severity, SourceFile, StandardJsonCompilerInput, }, }; use foundry_compilers_core::error::{Result, SolcError, SolcIoError}; @@ -69,7 +69,10 @@ use std::{ /// Represents a project workspace and handles `solc` compiling of all contracts in that workspace. #[derive(Clone, Derivative)] #[derivative(Debug)] -pub struct Project { +pub struct Project< + C: Compiler = MultiCompiler, + T: ArtifactOutput = ConfigurableArtifacts, +> { pub compiler: C, /// The layout of the project pub paths: ProjectPathsConfig, @@ -144,7 +147,7 @@ impl Project { } } -impl Project { +impl, C: Compiler> Project { /// Returns the handler that takes care of processing all artifacts pub fn artifacts_handler(&self) -> &T { &self.artifacts @@ -156,7 +159,7 @@ impl Project { } } -impl Project +impl> Project where C::Settings: Into, { @@ -202,7 +205,7 @@ where } } -impl Project { +impl, C: Compiler> Project { /// Returns the path to the artifacts directory pub fn artifacts_path(&self) -> &PathBuf { &self.paths.artifacts @@ -426,7 +429,10 @@ impl Project { } } -pub struct ProjectBuilder { +pub struct ProjectBuilder< + C: Compiler = MultiCompiler, + T: ArtifactOutput = ConfigurableArtifacts, +> { /// The layout of the paths: Option>, /// How solc invocation should be configured. @@ -457,7 +463,7 @@ pub struct ProjectBuilder>, } -impl ProjectBuilder { +impl> ProjectBuilder { /// Create a new builder with the given artifacts handler pub fn new(artifacts: T) -> Self { Self { @@ -619,7 +625,10 @@ impl ProjectBuilder { } /// Set arbitrary `ArtifactOutputHandler` - pub fn artifacts(self, artifacts: A) -> ProjectBuilder { + pub fn artifacts>( + self, + artifacts: A, + ) -> ProjectBuilder { let Self { paths, cached, @@ -705,18 +714,23 @@ impl ProjectBuilder { } } -impl Default for ProjectBuilder { +impl + Default> Default + for ProjectBuilder +{ fn default() -> Self { Self::new(T::default()) } } -impl ArtifactOutput for Project { +impl, C: Compiler> ArtifactOutput + for Project +{ type Artifact = T::Artifact; + type CompilerContract = C::CompilerContract; fn on_output( &self, - contracts: &VersionedContracts, + contracts: &VersionedContracts, sources: &VersionedSourceFiles, layout: &ProjectPathsConfig, ctx: OutputContext<'_>, @@ -726,7 +740,7 @@ impl ArtifactOutput for Project { fn handle_artifacts( &self, - contracts: &VersionedContracts, + contracts: &VersionedContracts, artifacts: &Artifacts, ) -> Result<()> { self.artifacts_handler().handle_artifacts(contracts, artifacts) @@ -773,7 +787,7 @@ impl ArtifactOutput for Project { &self, file: &Path, name: &str, - contract: Contract, + contract: C::CompilerContract, source_file: Option<&SourceFile>, ) -> Self::Artifact { self.artifacts_handler().contract_to_artifact(file, name, contract, source_file) @@ -781,7 +795,7 @@ impl ArtifactOutput for Project { fn output_to_artifacts( &self, - contracts: &VersionedContracts, + contracts: &VersionedContracts, sources: &VersionedSourceFiles, ctx: OutputContext<'_>, layout: &ProjectPathsConfig, diff --git a/crates/compilers/src/project_util/mod.rs b/crates/compilers/src/project_util/mod.rs index 5aaa406a..f8844aeb 100644 --- a/crates/compilers/src/project_util/mod.rs +++ b/crates/compilers/src/project_util/mod.rs @@ -31,14 +31,20 @@ pub mod mock; /// A [`Project`] wrapper that lives in a new temporary directory /// /// Once `TempProject` is dropped, the temp dir is automatically removed, see [`TempDir::drop()`] -pub struct TempProject { +pub struct TempProject< + C: Compiler = MultiCompiler, + T: ArtifactOutput = ConfigurableArtifacts, +> { /// temporary workspace root _root: TempDir, /// actual project workspace with the `root` tempdir as its root inner: Project, } -impl TempProject { +impl< + T: ArtifactOutput::CompilerContract> + Default, + > TempProject +{ /// Creates a new temp project using the provided paths and artifacts handler. /// sets the project root to a temp dir #[cfg(feature = "svm-solc")] @@ -64,7 +70,10 @@ impl TempProject { } } -impl TempProject { +impl< + T: ArtifactOutput::CompilerContract> + Default, + > TempProject +{ /// Creates a new temp project for the given `PathStyle` #[cfg(feature = "svm-solc")] pub fn with_style(prefix: &str, style: PathStyle) -> Result { @@ -76,7 +85,10 @@ impl TempProject { } } -impl fmt::Debug for TempProject { +impl< + T: ArtifactOutput::CompilerContract> + Default, + > fmt::Debug for TempProject +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TempProject").field("paths", &self.inner.paths).finish() } @@ -116,7 +128,11 @@ impl TempProject { } } -impl TempProject { +impl< + C: Compiler + Default, + T: ArtifactOutput + Default, + > TempProject +{ /// Makes sure all resources are created pub fn create_new( root: TempDir, @@ -461,8 +477,9 @@ impl TempProject { } } -impl AsRef> - for TempProject +impl< + T: ArtifactOutput::CompilerContract> + Default, + > AsRef> for TempProject { fn as_ref(&self) -> &Project { self.project() diff --git a/crates/compilers/src/resolver/mod.rs b/crates/compilers/src/resolver/mod.rs index 8f8e3ea2..d3b70d4e 100644 --- a/crates/compilers/src/resolver/mod.rs +++ b/crates/compilers/src/resolver/mod.rs @@ -473,7 +473,7 @@ impl> Graph { project: &Project, ) -> Result<(VersionedSources<'_, L, S>, GraphEdges)> where - T: ArtifactOutput, + T: ArtifactOutput, S: CompilerSettings, C: Compiler, { @@ -561,7 +561,11 @@ impl> Graph { /// path/to/c.sol () /// ... /// ``` - fn format_imports_list( + fn format_imports_list< + C: Compiler, + T: ArtifactOutput, + W: std::fmt::Write, + >( &self, idx: usize, incompatible: HashSet, @@ -590,7 +594,10 @@ impl> Graph { } /// Combines version requirement parsed from file and from project restrictions. - fn version_requirement( + fn version_requirement< + C: Compiler, + T: ArtifactOutput, + >( &self, idx: usize, project: &Project, @@ -615,7 +622,10 @@ impl> Graph { /// /// This returns an error if the file's version is invalid semver, or is not available such as /// 0.8.20, if the highest available version is `0.8.19` - fn check_available_version( + fn check_available_version< + C: Compiler, + T: ArtifactOutput, + >( &self, idx: usize, all_versions: &[&CompilerVersion], @@ -636,7 +646,10 @@ impl> Graph { /// Filters incompatible versions from the `candidates`. It iterates over node imports and in /// case if there is no compatible version it returns the latest seen node id. - fn retain_compatible_versions( + fn retain_compatible_versions< + C: Compiler, + T: ArtifactOutput, + >( &self, idx: usize, candidates: &mut Vec<&CompilerVersion>, @@ -707,7 +720,10 @@ impl> Graph { } /// Filters profiles incompatible with the given node and its imports. - fn retain_compatible_profiles( + fn retain_compatible_profiles< + C: Compiler, + T: ArtifactOutput, + >( &self, idx: usize, project: &Project, @@ -792,7 +808,10 @@ impl> Graph { /// /// This also attempts to prefer local installations over remote available. /// If `offline` is set to `true` then only already installed. - fn get_input_node_versions, T: ArtifactOutput>( + fn get_input_node_versions< + C: Compiler, + T: ArtifactOutput, + >( &self, project: &Project, ) -> Result>>> { @@ -889,7 +908,10 @@ impl> Graph { } #[allow(clippy::complexity)] - fn resolve_settings, T: ArtifactOutput>( + fn resolve_settings< + C: Compiler, + T: ArtifactOutput, + >( &self, project: &Project, input_nodes_versions: HashMap>>, diff --git a/crates/compilers/tests/project.rs b/crates/compilers/tests/project.rs index 1f9af8d8..4742cba5 100644 --- a/crates/compilers/tests/project.rs +++ b/crates/compilers/tests/project.rs @@ -22,8 +22,8 @@ use foundry_compilers::{ TestFileFilter, }; use foundry_compilers_artifacts::{ - output_selection::OutputSelection, remappings::Remapping, BytecodeHash, DevDoc, Error, - ErrorDoc, EventDoc, EvmVersion, Libraries, MethodDoc, ModelCheckerEngine::CHC, + output_selection::OutputSelection, remappings::Remapping, BytecodeHash, Contract, DevDoc, + Error, ErrorDoc, EventDoc, EvmVersion, Libraries, MethodDoc, ModelCheckerEngine::CHC, ModelCheckerSettings, Settings, Severity, SolcInput, UserDoc, UserDocNotice, }; use foundry_compilers_core::{ @@ -405,7 +405,8 @@ contract B { } let mut build_info_count = 0; for entry in fs::read_dir(info_dir).unwrap() { let _info = - BuildInfo::>::read(&entry.unwrap().path()).unwrap(); + BuildInfo::>::read(&entry.unwrap().path()) + .unwrap(); build_info_count += 1; } assert_eq!(build_info_count, 1); @@ -447,7 +448,8 @@ contract B { } let mut build_info_count = 0; for entry in fs::read_dir(info_dir).unwrap() { let _info = - BuildInfo::>::read(&entry.unwrap().path()).unwrap(); + BuildInfo::>::read(&entry.unwrap().path()) + .unwrap(); build_info_count += 1; } assert_eq!(build_info_count, 1);