Skip to content

Commit b7e7d57

Browse files
committed
feat: allow multiple compiler configs
1 parent 67a46cf commit b7e7d57

File tree

9 files changed

+299
-100
lines changed

9 files changed

+299
-100
lines changed

crates/compilers/src/compile/project.rs

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -109,23 +109,23 @@ use crate::{
109109
output::{AggregatedCompilerOutput, Builds},
110110
report,
111111
resolver::GraphEdges,
112-
ArtifactOutput, Graph, Project, ProjectCompileOutput, Sources,
112+
ArtifactOutput, CompilerSettings, Graph, Project, ProjectCompileOutput, Sources,
113113
};
114114
use foundry_compilers_core::error::Result;
115115
use rayon::prelude::*;
116116
use semver::Version;
117117
use std::{collections::HashMap, path::PathBuf, time::Instant};
118118

119119
/// A set of different Solc installations with their version and the sources to be compiled
120-
pub(crate) type VersionedSources<L> = HashMap<L, HashMap<Version, Sources>>;
120+
pub(crate) type VersionedSources<L, S> = HashMap<L, Vec<(Version, Sources, S)>>;
121121

122122
#[derive(Debug)]
123123
pub struct ProjectCompiler<'a, T: ArtifactOutput, C: Compiler> {
124124
/// Contains the relationship of the source files and their imports
125125
edges: GraphEdges<C::ParsedSource>,
126126
project: &'a Project<C, T>,
127127
/// how to compile all the sources
128-
sources: CompilerSources<C::Language>,
128+
sources: CompilerSources<C::Language, C::Settings>,
129129
}
130130

131131
impl<'a, T: ArtifactOutput, C: Compiler> ProjectCompiler<'a, T, C> {
@@ -146,11 +146,7 @@ impl<'a, T: ArtifactOutput, C: Compiler> ProjectCompiler<'a, T, C> {
146146
sources.retain(|f, _| filter.is_match(f))
147147
}
148148
let graph = Graph::resolve_sources(&project.paths, sources)?;
149-
let (sources, edges) = graph.into_sources_by_version(
150-
project.offline,
151-
&project.locked_versions,
152-
&project.compiler,
153-
)?;
149+
let (sources, edges) = graph.into_sources_by_version(project)?;
154150

155151
// If there are multiple different versions, and we can use multiple jobs we can compile
156152
// them in parallel.
@@ -218,7 +214,7 @@ impl<'a, T: ArtifactOutput, C: Compiler> ProjectCompiler<'a, T, C> {
218214
#[derive(Debug)]
219215
struct PreprocessedState<'a, T: ArtifactOutput, C: Compiler> {
220216
/// Contains all the sources to compile.
221-
sources: CompilerSources<C::Language>,
217+
sources: CompilerSources<C::Language, C::Settings>,
222218

223219
/// Cache that holds `CacheEntry` objects if caching is enabled and the project is recompiled
224220
cache: ArtifactsCache<'a, T, C>,
@@ -358,14 +354,14 @@ impl<'a, T: ArtifactOutput, C: Compiler> ArtifactsState<'a, T, C> {
358354

359355
/// Determines how the `solc <-> sources` pairs are executed.
360356
#[derive(Debug, Clone)]
361-
struct CompilerSources<L> {
357+
struct CompilerSources<L, S> {
362358
/// The sources to compile.
363-
sources: VersionedSources<L>,
359+
sources: VersionedSources<L, S>,
364360
/// The number of jobs to use for parallel compilation.
365361
jobs: Option<usize>,
366362
}
367363

368-
impl<L: Language> CompilerSources<L> {
364+
impl<L: Language, S: CompilerSettings> CompilerSources<L, S> {
369365
/// Converts all `\\` separators to `/`.
370366
///
371367
/// This effectively ensures that `solc` can find imported files like `/src/Cheats.sol` in the
@@ -395,7 +391,7 @@ impl<L: Language> CompilerSources<L> {
395391
) {
396392
cache.remove_dirty_sources();
397393
for versioned_sources in self.sources.values_mut() {
398-
for (version, sources) in versioned_sources {
394+
for (version, sources, _) in versioned_sources {
399395
trace!("Filtering {} sources for {}", sources.len(), version);
400396
cache.filter(sources, version);
401397
trace!(
@@ -408,7 +404,7 @@ impl<L: Language> CompilerSources<L> {
408404
}
409405

410406
/// Compiles all the files with `Solc`
411-
fn compile<C: Compiler<Language = L>, T: ArtifactOutput>(
407+
fn compile<C: Compiler<Language = L, Settings = S>, T: ArtifactOutput>(
412408
self,
413409
cache: &mut ArtifactsCache<'_, T, C>,
414410
) -> Result<AggregatedCompilerOutput<C>> {
@@ -425,7 +421,7 @@ impl<L: Language> CompilerSources<L> {
425421

426422
let mut jobs = Vec::new();
427423
for (language, versioned_sources) in self.sources {
428-
for (version, sources) in versioned_sources {
424+
for (version, sources, mut opt_settings) in versioned_sources {
429425
if sources.is_empty() {
430426
// nothing to compile
431427
trace!("skip {} for empty sources set", version);
@@ -434,7 +430,6 @@ impl<L: Language> CompilerSources<L> {
434430

435431
// depending on the composition of the filtered sources, the output selection can be
436432
// optimized
437-
let mut opt_settings = project.settings.clone();
438433
let actually_dirty =
439434
sparse_output.sparse_sources(&sources, &mut opt_settings, graph);
440435

@@ -677,7 +672,7 @@ mod tests {
677672
// single solc
678673
assert_eq!(len, 1);
679674

680-
let filtered = &sources.values().next().unwrap().values().next().unwrap();
675+
let filtered = &sources.values().next().unwrap()[0].1;
681676

682677
// 3 contracts total
683678
assert_eq!(filtered.0.len(), 3);

crates/compilers/src/compilers/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,18 @@ impl fmt::Display for CompilerVersion {
6161
}
6262
}
6363

64+
pub trait CompilerSettingsRestrictions: Debug + Sync + Send + Clone + Default {
65+
fn merge(&mut self, other: &Self);
66+
}
67+
6468
/// Compilation settings including evm_version, output_selection, etc.
6569
pub trait CompilerSettings:
6670
Default + Serialize + DeserializeOwned + Clone + Debug + Send + Sync + 'static
6771
{
72+
/// We allow configuring settings restrictions which might optionally contain specific
73+
/// requiremets for compiler configuration. e.g. min/max evm_version, optimizer runs
74+
type Restrictions: CompilerSettingsRestrictions;
75+
6876
/// Executes given fn with mutable reference to configured [OutputSelection].
6977
fn update_output_selection(&mut self, f: impl FnOnce(&mut OutputSelection) + Copy);
7078

@@ -74,6 +82,9 @@ pub trait CompilerSettings:
7482
/// Ensures that all settings fields are equal except for `output_selection` which is required
7583
/// to be a subset of `cached.output_selection`.
7684
fn can_use_cached(&self, other: &Self) -> bool;
85+
86+
/// Returns whether current settings satisfy given restrictions.
87+
fn satisfies_restrictions(&self, restrictions: &Self::Restrictions) -> bool;
7788
}
7889

7990
/// Input of a compiler, including sources and settings used for their compilation.

crates/compilers/src/compilers/multi.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ use super::{
1010
use crate::{
1111
artifacts::vyper::{VyperCompilationError, VyperSettings},
1212
resolver::parse::SolData,
13+
settings::VyperRestrictions,
14+
solc::SolcRestrictions,
15+
CompilerSettingsRestrictions,
1316
};
1417
use foundry_compilers_artifacts::{
1518
error::SourceLocation,
@@ -124,6 +127,19 @@ impl fmt::Display for MultiCompilerError {
124127
}
125128
}
126129

130+
#[derive(Clone, Copy, Debug, Default)]
131+
pub struct MultiCompilerRestrictions {
132+
pub solc: SolcRestrictions,
133+
pub vyper: VyperRestrictions,
134+
}
135+
136+
impl CompilerSettingsRestrictions for MultiCompilerRestrictions {
137+
fn merge(&mut self, other: &Self) {
138+
self.solc.merge(&other.solc);
139+
self.vyper.merge(&other.vyper);
140+
}
141+
}
142+
127143
/// Settings for the [MultiCompiler]. Includes settings for both Solc and Vyper compilers.
128144
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
129145
pub struct MultiCompilerSettings {
@@ -132,6 +148,8 @@ pub struct MultiCompilerSettings {
132148
}
133149

134150
impl CompilerSettings for MultiCompilerSettings {
151+
type Restrictions = MultiCompilerRestrictions;
152+
135153
fn can_use_cached(&self, other: &Self) -> bool {
136154
self.solc.can_use_cached(&other.solc) && self.vyper.can_use_cached(&other.vyper)
137155
}
@@ -140,6 +158,11 @@ impl CompilerSettings for MultiCompilerSettings {
140158
f(&mut self.solc.output_selection);
141159
f(&mut self.vyper.output_selection);
142160
}
161+
162+
fn satisfies_restrictions(&self, restrictions: &Self::Restrictions) -> bool {
163+
self.solc.satisfies_restrictions(&restrictions.solc)
164+
&& self.vyper.satisfies_restrictions(&restrictions.vyper)
165+
}
143166
}
144167

145168
impl From<MultiCompilerSettings> for SolcSettings {

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

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ use super::{
22
CompilationError, Compiler, CompilerInput, CompilerOutput, CompilerSettings, CompilerVersion,
33
Language, ParsedSource,
44
};
5-
use crate::resolver::parse::SolData;
5+
use crate::{resolver::parse::SolData, CompilerSettingsRestrictions};
66
pub use foundry_compilers_artifacts::SolcLanguage;
77
use foundry_compilers_artifacts::{
88
error::SourceLocation,
99
output_selection::OutputSelection,
1010
remappings::Remapping,
1111
sources::{Source, Sources},
12-
Error, Settings as SolcSettings, Severity, SolcInput,
12+
Error, EvmVersion, Settings as SolcSettings, Severity, SolcInput,
1313
};
1414
use foundry_compilers_core::error::Result;
1515
use itertools::Itertools;
@@ -178,7 +178,58 @@ impl CompilerInput for SolcVersionedInput {
178178
}
179179
}
180180

181+
#[derive(Debug, Clone, Copy, Default)]
182+
pub struct EvmVersionRestriction {
183+
pub min_evm_version: Option<EvmVersion>,
184+
pub max_evm_version: Option<EvmVersion>,
185+
}
186+
187+
impl EvmVersionRestriction {
188+
/// Returns true if the given version satisfies the restrictions
189+
///
190+
/// If given None, only returns true if no restrictions are set
191+
pub fn satisfies(&self, version: Option<EvmVersion>) -> bool {
192+
self.min_evm_version.map_or(true, |min| version.map_or(false, |v| v >= min))
193+
&& self.max_evm_version.map_or(true, |max| version.map_or(false, |v| v <= max))
194+
}
195+
196+
pub fn merge(&mut self, other: &Self) {
197+
let Self { min_evm_version, max_evm_version } = other;
198+
199+
if let Some(min_evm_version) = min_evm_version {
200+
if self.min_evm_version.map_or(true, |e| e < *min_evm_version) {
201+
self.min_evm_version.replace(*min_evm_version);
202+
}
203+
}
204+
205+
if let Some(max_evm_version) = max_evm_version {
206+
if self.max_evm_version.map_or(true, |e| e > *max_evm_version) {
207+
self.max_evm_version.replace(*max_evm_version);
208+
}
209+
}
210+
}
211+
}
212+
213+
#[derive(Debug, Clone, Copy, Default)]
214+
pub struct SolcRestrictions {
215+
pub evm_version: EvmVersionRestriction,
216+
pub via_ir: Option<bool>,
217+
}
218+
219+
impl CompilerSettingsRestrictions for SolcRestrictions {
220+
fn merge(&mut self, other: &Self) {
221+
self.evm_version.merge(&other.evm_version);
222+
223+
// Preserve true
224+
if self.via_ir.map_or(true, |via_ir| !via_ir) {
225+
self.via_ir = other.via_ir;
226+
}
227+
}
228+
}
229+
181230
impl CompilerSettings for SolcSettings {
231+
type Restrictions = SolcRestrictions;
232+
182233
fn update_output_selection(&mut self, f: impl FnOnce(&mut OutputSelection) + Copy) {
183234
f(&mut self.output_selection)
184235
}
@@ -208,6 +259,16 @@ impl CompilerSettings for SolcSettings {
208259
&& *libraries == other.libraries
209260
&& output_selection.is_subset_of(&other.output_selection)
210261
}
262+
263+
fn satisfies_restrictions(&self, restrictions: &Self::Restrictions) -> bool {
264+
let mut satisfies = true;
265+
266+
satisfies &= restrictions.evm_version.satisfies(self.evm_version);
267+
satisfies &=
268+
restrictions.via_ir.map_or(true, |via_ir| via_ir == self.via_ir.unwrap_or_default());
269+
270+
satisfies
271+
}
211272
}
212273

213274
impl ParsedSource for SolData {

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

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
11
pub use crate::artifacts::vyper::VyperSettings;
2-
use crate::compilers::CompilerSettings;
2+
use crate::{
3+
compilers::CompilerSettings, solc::EvmVersionRestriction, CompilerSettingsRestrictions,
4+
};
35
use foundry_compilers_artifacts::output_selection::OutputSelection;
46

7+
#[derive(Clone, Copy, Debug, Default)]
8+
pub struct VyperRestrictions {
9+
pub evm_version: EvmVersionRestriction,
10+
}
11+
12+
impl CompilerSettingsRestrictions for VyperRestrictions {
13+
fn merge(&mut self, other: &Self) {
14+
self.evm_version.merge(&other.evm_version);
15+
}
16+
}
17+
518
impl CompilerSettings for VyperSettings {
19+
type Restrictions = VyperRestrictions;
20+
621
fn update_output_selection(&mut self, f: impl FnOnce(&mut OutputSelection)) {
722
f(&mut self.output_selection)
823
}
@@ -16,4 +31,8 @@ impl CompilerSettings for VyperSettings {
1631
&& output_selection.is_subset_of(&other.output_selection)
1732
&& search_paths == &other.search_paths
1833
}
34+
35+
fn satisfies_restrictions(&self, restrictions: &Self::Restrictions) -> bool {
36+
restrictions.evm_version.satisfies(self.evm_version)
37+
}
1938
}

0 commit comments

Comments
 (0)