Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions crates/solidity-v2/outputs/cargo/ast/generated/public_api.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,20 @@ impl ContractDefinitionStruct {
if let Some(constructor) = self.constructor() {
entries.push(constructor.compute_abi_entry()?);
}
for function in &self.compute_linearised_functions() {
for function in &self.linearised_functions() {
if function.is_externally_visible() {
entries.push(function.compute_abi_entry()?);
}
}
for state_variable in &self.compute_linearised_state_variables() {
for state_variable in &self.linearised_state_variables() {
if state_variable.is_externally_visible() {
entries.push(state_variable.compute_abi_entry()?);
}
}
for error in &self.compute_linearised_errors() {
for error in &self.linearised_errors() {
entries.push(error.compute_abi_entry()?);
}
for event in &self.compute_linearised_events() {
for event in &self.linearised_events() {
entries.push(event.compute_abi_entry()?);
}

Expand All @@ -63,7 +63,7 @@ impl ContractDefinitionStruct {

/// Computes the layouts of both permanent and transient state variables
fn compute_storage_layout(&self) -> Option<(Vec<StorageItem>, Vec<StorageItem>)> {
let all_state_variables = self.compute_linearised_state_variables();
let all_state_variables = self.linearised_state_variables();

// TODO(validation) SDR[2]: it is an error if any contract in the hierarchy
// other than the leaf has a custom offset layout
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::cmp::Ordering;

use super::super::nodes::{
create_error_definition, create_event_definition, create_function_definition,
create_state_variable_definition,
};
use super::super::{
ContractDefinitionStruct, Definition, ErrorDefinition, EventDefinition, FunctionDefinition,
FunctionKind, StateVariableDefinition,
Expand All @@ -20,7 +22,7 @@ impl ContractDefinitionStruct {
/// Returns the list of contracts/interfaces in the hierarchy (including
/// self) in the order given by the C3 linearisation, with self contract
/// always first
pub fn compute_linearised_bases(&self) -> Vec<ContractBase> {
pub fn linearised_bases(&self) -> Vec<ContractBase> {
let Some(base_node_ids) = self
.semantic
.binder()
Expand All @@ -47,16 +49,12 @@ impl ContractDefinitionStruct {
}

/// Returns the list of state variable definitions in the order laid out in storage
pub fn compute_linearised_state_variables(&self) -> Vec<StateVariableDefinition> {
let mut state_variables = Vec::new();
let bases = self.compute_linearised_bases();
for base in bases.iter().rev() {
let ContractBase::Contract(contract) = base else {
continue;
};
state_variables.extend(contract.members().iter_state_variable_definitions());
}
state_variables
pub fn linearised_state_variables(&self) -> Vec<StateVariableDefinition> {
self.semantic
.linearised_state_variables(self.ir_node.id())
.iter()
.map(|ir_node| create_state_variable_definition(ir_node, &self.semantic))
.collect()
}

pub fn functions(&self) -> Vec<FunctionDefinition> {
Expand Down Expand Up @@ -86,82 +84,35 @@ impl ContractDefinitionStruct {

/// Returns the list of functions defined in all the hierarchy of the
/// contract, in alphabetical order
pub fn compute_linearised_functions(&self) -> Vec<FunctionDefinition> {
let mut functions: Vec<FunctionDefinition> = Vec::new();
let bases = self.compute_linearised_bases();
for base in &bases {
// TODO(validation) SDR[3]: we don't pick up functions defined in
// interfaces because they should be implemented in inheriting
// contracts, but this is not yet enforced anywhere
let ContractBase::Contract(contract) = base else {
continue;
};

// Handle function overriding
let contract_functions = contract
.functions()
.into_iter()
.filter(|function| {
// check the existing functions and remove any duplicates
// because they should be overridden by them
let existing = functions
.iter()
.any(|linearised_function| linearised_function.overrides(function));
!existing
})
// collect to avoid holding the read-borrow on `functions`
.collect::<Vec<_>>();

functions.extend(contract_functions);
}

// sort returned functions by name
functions.sort_by(|a, b| match (a.name(), b.name()) {
(None, None) => Ordering::Equal,
(None, Some(_)) => Ordering::Less,
(Some(_), None) => Ordering::Greater,
(Some(a), Some(b)) => a.name().cmp(&b.name()),
});
functions
pub fn linearised_functions(&self) -> Vec<FunctionDefinition> {
self.semantic
.linearised_functions(self.ir_node.id())
.iter()
.map(|ir_node| create_function_definition(ir_node, &self.semantic))
.collect()
}

pub fn errors(&self) -> Vec<ErrorDefinition> {
self.members().iter_error_definitions().collect()
}

pub fn compute_linearised_errors(&self) -> Vec<ErrorDefinition> {
let mut errors = Vec::new();
let bases = self.compute_linearised_bases();
for base in bases.iter().rev() {
match base {
ContractBase::Contract(contract) => {
errors.extend(contract.members().iter_error_definitions());
}
ContractBase::Interface(interface) => {
errors.extend(interface.members().iter_error_definitions());
}
}
}
errors
pub fn linearised_errors(&self) -> Vec<ErrorDefinition> {
self.semantic
.linearised_errors(self.ir_node.id())
.iter()
.map(|ir_node| create_error_definition(ir_node, &self.semantic))
.collect()
}

pub fn events(&self) -> Vec<EventDefinition> {
self.members().iter_event_definitions().collect()
}

pub fn compute_linearised_events(&self) -> Vec<EventDefinition> {
let mut events = Vec::new();
let bases = self.compute_linearised_bases();
for base in bases.iter().rev() {
match base {
ContractBase::Contract(contract) => {
events.extend(contract.members().iter_event_definitions());
}
ContractBase::Interface(interface) => {
events.extend(interface.members().iter_event_definitions());
}
}
}
events
pub fn linearised_events(&self) -> Vec<EventDefinition> {
self.semantic
.linearised_events(self.ir_node.id())
.iter()
.map(|ir_node| create_event_definition(ir_node, &self.semantic))
.collect()
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ mod contract_definition;
mod contract_members;
mod decimal_number_expression;
mod hex_number_expression;
mod interface_definition;
pub use contract_base::ContractBase;

mod expression;
mod function_call_expression;
mod function_definition;
mod identifier;
mod identifier_path;
mod source_unit;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use std::collections::HashMap;

use slang_solidity_v2_common::nodes::NodeId;
use slang_solidity_v2_ir::ir;

/// Pre-computed member linearisations for a single contract.
#[allow(clippy::struct_field_names)]
pub(crate) struct ContractLinearisations {
pub(crate) functions: Vec<ir::FunctionDefinition>,
pub(crate) state_variables: Vec<ir::StateVariableDefinition>,
pub(crate) errors: Vec<ir::ErrorDefinition>,
pub(crate) events: Vec<ir::EventDefinition>,
}

/// Cache of derived data about contracts stored on the `SemanticContext`. Every
/// contract's `NodeId` has an entry in `data`.
pub(crate) struct ContractData {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't need to be on this PR, but it'd be interested to have a benchmark tracking how these values are used. For example, for some big benchmarks, iterate all linearised definitions for all contracts and use them trivially (compute the hash of their selectors)

/// All contract definitions in this compilation unit, in registration
/// order (deterministic iteration for `all_contracts`).
contracts: Vec<ir::ContractDefinition>,
/// Per-contract linearised members, keyed by contract `NodeId`.
linearisations: HashMap<NodeId, ContractLinearisations>,
}

impl ContractData {
pub(crate) fn new(
contracts: Vec<ir::ContractDefinition>,
data: HashMap<NodeId, ContractLinearisations>,
) -> Self {
Self {
contracts,
linearisations: data,
}
}

fn get(&self, contract_id: NodeId) -> &ContractLinearisations {
self.linearisations
.get(&contract_id)
.expect("contract_id is a registered contract")
}

pub(super) fn all_contracts(&self) -> impl Iterator<Item = &ir::ContractDefinition> {
self.contracts.iter()
}

pub(super) fn find_contract_by_name<'a>(
&'a self,
name: &'a str,
) -> impl Iterator<Item = ir::ContractDefinition> + use<'a> {
self.contracts
.iter()
.filter(move |contract| contract.name.unparse() == name)
.cloned()
}

pub(super) fn linearised_functions(&self, contract_id: NodeId) -> &[ir::FunctionDefinition] {
&self.get(contract_id).functions
}

pub(super) fn linearised_state_variables(
&self,
contract_id: NodeId,
) -> &[ir::StateVariableDefinition] {
&self.get(contract_id).state_variables
}

pub(super) fn linearised_errors(&self, contract_id: NodeId) -> &[ir::ErrorDefinition] {
&self.get(contract_id).errors
}

pub(super) fn linearised_events(&self, contract_id: NodeId) -> &[ir::EventDefinition] {
&self.get(contract_id).events
}
}
Loading