diff --git a/crates/solidity-v2/outputs/cargo/ast/generated/public_api.txt b/crates/solidity-v2/outputs/cargo/ast/generated/public_api.txt index fcaa3477fc..287dc8fe4b 100644 --- a/crates/solidity-v2/outputs/cargo/ast/generated/public_api.txt +++ b/crates/solidity-v2/outputs/cargo/ast/generated/public_api.txt @@ -1443,16 +1443,16 @@ pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::references(&self) - impl slang_solidity_v2_ast::ast::ContractDefinitionStruct pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::compute_abi(&self) -> core::option::Option impl slang_solidity_v2_ast::ast::ContractDefinitionStruct -pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::compute_linearised_bases(&self) -> alloc::vec::Vec -pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::compute_linearised_errors(&self) -> alloc::vec::Vec -pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::compute_linearised_events(&self) -> alloc::vec::Vec -pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::compute_linearised_functions(&self) -> alloc::vec::Vec -pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::compute_linearised_state_variables(&self) -> alloc::vec::Vec pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::constructor(&self) -> core::option::Option pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::direct_bases(&self) -> alloc::vec::Vec pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::errors(&self) -> alloc::vec::Vec pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::events(&self) -> alloc::vec::Vec pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::functions(&self) -> alloc::vec::Vec +pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::linearised_bases(&self) -> alloc::vec::Vec +pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::linearised_errors(&self) -> alloc::vec::Vec +pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::linearised_events(&self) -> alloc::vec::Vec +pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::linearised_functions(&self) -> alloc::vec::Vec +pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::linearised_state_variables(&self) -> alloc::vec::Vec pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::modifiers(&self) -> alloc::vec::Vec pub fn slang_solidity_v2_ast::ast::ContractDefinitionStruct::state_variables(&self) -> alloc::vec::Vec impl serde_core::ser::Serialize for slang_solidity_v2_ast::ast::ContractDefinitionStruct diff --git a/crates/solidity-v2/outputs/cargo/ast/src/abi/node_extensions/contract_definition.rs b/crates/solidity-v2/outputs/cargo/ast/src/abi/node_extensions/contract_definition.rs index d5a1eb2f6d..f42137a021 100644 --- a/crates/solidity-v2/outputs/cargo/ast/src/abi/node_extensions/contract_definition.rs +++ b/crates/solidity-v2/outputs/cargo/ast/src/abi/node_extensions/contract_definition.rs @@ -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()?); } @@ -63,7 +63,7 @@ impl ContractDefinitionStruct { /// Computes the layouts of both permanent and transient state variables fn compute_storage_layout(&self) -> Option<(Vec, Vec)> { - 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 diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/contract_definition.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/contract_definition.rs index f82fc647e3..0e0e11b35a 100644 --- a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/contract_definition.rs +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/contract_definition.rs @@ -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, @@ -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 { + pub fn linearised_bases(&self) -> Vec { let Some(base_node_ids) = self .semantic .binder() @@ -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 { - 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 { + 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 { @@ -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 { - let mut functions: Vec = 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::>(); - - 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 { + 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 { self.members().iter_error_definitions().collect() } - pub fn compute_linearised_errors(&self) -> Vec { - 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 { + 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 { self.members().iter_event_definitions().collect() } - pub fn compute_linearised_events(&self) -> Vec { - 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 { + self.semantic + .linearised_events(self.ir_node.id()) + .iter() + .map(|ir_node| create_event_definition(ir_node, &self.semantic)) + .collect() } } diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/function_definition.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/function_definition.rs deleted file mode 100644 index 11f1a1ef78..0000000000 --- a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/function_definition.rs +++ /dev/null @@ -1,39 +0,0 @@ -use super::super::{FunctionDefinition, FunctionDefinitionStruct}; - -impl FunctionDefinitionStruct { - pub(crate) fn overrides(&self, other: &FunctionDefinition) -> bool { - let name_matches = match (&self.ir_node.name, &other.ir_node.name) { - (None, None) => { - // for unnamed functions, we check the kind because `receive` - // and `fallback` may have the same parameters but they are - // different functions - self.ir_node.kind == other.ir_node.kind - } - (Some(name), Some(other_name)) => name.unparse() == other_name.unparse(), - _ => false, - }; - if !name_matches { - return false; - } - let type_id = self - .semantic - .binder() - .node_typing(self.ir_node.id()) - .as_type_id(); - let other_type_id = self - .semantic - .binder() - .node_typing(other.ir_node.id()) - .as_type_id(); - - match (type_id, other_type_id) { - (Some(type_id), Some(other_type_id)) => self - .semantic - .types() - .type_id_is_function_and_overrides(type_id, other_type_id), - _ => false, - } - - // TODO(validation) SDR[6]: check also that the function mutability is stricter than other's - } -} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/interface_definition.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/interface_definition.rs deleted file mode 100644 index 9229d87ec6..0000000000 --- a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/interface_definition.rs +++ /dev/null @@ -1,23 +0,0 @@ -use super::super::{ContractMember, ErrorDefinition, EventDefinition, InterfaceMembersStruct}; - -impl InterfaceMembersStruct { - pub(crate) fn iter_error_definitions(&self) -> impl Iterator + use<'_> { - self.iter().filter_map(|member| { - if let ContractMember::ErrorDefinition(error_definition) = member { - Some(error_definition) - } else { - None - } - }) - } - - pub(crate) fn iter_event_definitions(&self) -> impl Iterator + use<'_> { - self.iter().filter_map(|member| { - if let ContractMember::EventDefinition(event_definition) = member { - Some(event_definition) - } else { - None - } - }) - } -} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/mod.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/mod.rs index 59b273dc50..2f012d89b4 100644 --- a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/mod.rs +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/mod.rs @@ -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; diff --git a/crates/solidity-v2/outputs/cargo/semantic/generated/public_api.txt b/crates/solidity-v2/outputs/cargo/semantic/generated/public_api.txt index 86abf75960..c3a0b02298 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/generated/public_api.txt +++ b/crates/solidity-v2/outputs/cargo/semantic/generated/public_api.txt @@ -263,17 +263,22 @@ pub struct slang_solidity_v2_semantic::context::SemanticContext impl slang_solidity_v2_semantic::context::SemanticContext pub const slang_solidity_v2_semantic::context::SemanticContext::SLOT_SIZE: usize pub fn slang_solidity_v2_semantic::context::SemanticContext::file_id_from_node_id(&self, node_id: slang_solidity_v2_common::nodes::NodeId) -> &str +pub fn slang_solidity_v2_semantic::context::SemanticContext::linearised_errors(&self, contract_id: slang_solidity_v2_common::nodes::NodeId) -> &[slang_solidity_v2_ir::ir::nodes::ErrorDefinition] +pub fn slang_solidity_v2_semantic::context::SemanticContext::linearised_events(&self, contract_id: slang_solidity_v2_common::nodes::NodeId) -> &[slang_solidity_v2_ir::ir::nodes::EventDefinition] +pub fn slang_solidity_v2_semantic::context::SemanticContext::linearised_functions(&self, contract_id: slang_solidity_v2_common::nodes::NodeId) -> &[slang_solidity_v2_ir::ir::nodes::FunctionDefinition] +pub fn slang_solidity_v2_semantic::context::SemanticContext::linearised_state_variables(&self, contract_id: slang_solidity_v2_common::nodes::NodeId) -> &[slang_solidity_v2_ir::ir::nodes::StateVariableDefinition] pub fn slang_solidity_v2_semantic::context::SemanticContext::resolve_reference_identifier_to_definition_id(&self, node_id: slang_solidity_v2_common::nodes::NodeId) -> core::option::Option pub fn slang_solidity_v2_semantic::context::SemanticContext::resolve_reference_identifier_to_immediate_definition_id(&self, node_id: slang_solidity_v2_common::nodes::NodeId) -> core::option::Option pub fn slang_solidity_v2_semantic::context::SemanticContext::storage_size_of_type_id(&self, type_id: slang_solidity_v2_semantic::types::TypeId) -> core::option::Option pub fn slang_solidity_v2_semantic::context::SemanticContext::type_canonical_name(&self, type_id: slang_solidity_v2_semantic::types::TypeId) -> core::option::Option pub fn slang_solidity_v2_semantic::context::SemanticContext::type_internal_name(&self, type_id: slang_solidity_v2_semantic::types::TypeId) -> alloc::string::String impl slang_solidity_v2_semantic::context::SemanticContext +pub fn slang_solidity_v2_semantic::context::SemanticContext::all_contracts(&self) -> impl core::iter::traits::iterator::Iterator + use<'_> pub fn slang_solidity_v2_semantic::context::SemanticContext::all_definitions(&self) -> impl core::iter::traits::iterator::Iterator + use<'_> pub fn slang_solidity_v2_semantic::context::SemanticContext::all_references(&self) -> impl core::iter::traits::iterator::Iterator + use<'_> pub fn slang_solidity_v2_semantic::context::SemanticContext::binder(&self) -> &slang_solidity_v2_semantic::binder::Binder pub fn slang_solidity_v2_semantic::context::SemanticContext::build_from(language_version: slang_solidity_v2_common::versions::version::LanguageVersion, files: &[impl slang_solidity_v2_semantic::context::SemanticFile], diagnostics: &mut slang_solidity_v2_common::diagnostics::collection::DiagnosticCollection) -> Self -pub fn slang_solidity_v2_semantic::context::SemanticContext::find_contract_by_name(&self, name: &str) -> core::option::Option +pub fn slang_solidity_v2_semantic::context::SemanticContext::find_contract_by_name<'a, 'b>(&'a self, name: &'b str) -> impl core::iter::traits::iterator::Iterator + use<'a> where 'b: 'a pub fn slang_solidity_v2_semantic::context::SemanticContext::types(&self) -> &slang_solidity_v2_semantic::types::TypeRegistry pub trait slang_solidity_v2_semantic::context::SemanticFile pub fn slang_solidity_v2_semantic::context::SemanticFile::id(&self) -> &str diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/context/contract_data.rs b/crates/solidity-v2/outputs/cargo/semantic/src/context/contract_data.rs new file mode 100644 index 0000000000..d6c988eb2f --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/semantic/src/context/contract_data.rs @@ -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, + pub(crate) state_variables: Vec, + pub(crate) errors: Vec, + pub(crate) events: Vec, +} + +/// Cache of derived data about contracts stored on the `SemanticContext`. Every +/// contract's `NodeId` has an entry in `data`. +pub(crate) struct ContractData { + /// All contract definitions in this compilation unit, in registration + /// order (deterministic iteration for `all_contracts`). + contracts: Vec, + /// Per-contract linearised members, keyed by contract `NodeId`. + linearisations: HashMap, +} + +impl ContractData { + pub(crate) fn new( + contracts: Vec, + data: HashMap, + ) -> 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 { + self.contracts.iter() + } + + pub(super) fn find_contract_by_name<'a>( + &'a self, + name: &'a str, + ) -> impl Iterator + 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 + } +} diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/context/mod.rs b/crates/solidity-v2/outputs/cargo/semantic/src/context/mod.rs index 197ca36a19..4c06ce3514 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/context/mod.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/context/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use std::sync::Arc; +pub(crate) use contract_data::{ContractData, ContractLinearisations}; use file_node_mapper::FileNodeMapper; use slang_solidity_v2_common::diagnostics::DiagnosticCollection; use slang_solidity_v2_common::nodes::NodeId; @@ -10,7 +10,8 @@ use slang_solidity_v2_ir::ir; use crate::binder::{Binder, Definition, Reference}; use crate::passes::{ - p1_collect_definitions, p2_linearise_contracts, p3_type_definitions, p4_resolve_references, + p1_collect_definitions, p2_linearise_contracts, p3_type_definitions, p4_compute_linearisations, + p5_resolve_references, }; use crate::types::{ ArrayType, ByteArrayType, ContractType, EnumType, FixedPointNumberType, FixedSizeArrayType, @@ -18,6 +19,7 @@ use crate::types::{ TypeRegistry, UserDefinedValueType, }; +mod contract_data; mod file_node_mapper; /// Trait for files that can be used as input to the semantic analysis passes. @@ -60,6 +62,7 @@ pub struct SemanticContext { binder: Binder, types: TypeRegistry, file_node_mapper: FileNodeMapper, + contract_data: ContractData, } impl SemanticContext { @@ -74,7 +77,8 @@ impl SemanticContext { p1_collect_definitions::run(files, &mut binder, diagnostics); p2_linearise_contracts::run(files, &mut binder, diagnostics); p3_type_definitions::run(files, &mut binder, &mut types, language_version); - p4_resolve_references::run(files, &mut binder, &mut types, language_version); + let contract_data = p4_compute_linearisations::run(&binder, &types); + p5_resolve_references::run(files, &mut binder, &mut types, language_version); let file_node_mapper = FileNodeMapper::build_from(files); @@ -82,6 +86,7 @@ impl SemanticContext { binder, types, file_node_mapper, + contract_data, } } @@ -103,17 +108,19 @@ impl SemanticContext { self.binder.references().values() } - pub fn find_contract_by_name(&self, name: &str) -> Option { - self.binder().definitions().values().find_map(|definition| { - let Definition::Contract(contract) = definition else { - return None; - }; - if definition.identifier().unparse() == name { - Some(Arc::clone(&contract.ir_node)) - } else { - None - } - }) + /// Iterates over every contract definition in this compilation unit. + pub fn all_contracts(&self) -> impl Iterator + use<'_> { + self.contract_data.all_contracts() + } + + pub fn find_contract_by_name<'a, 'b>( + &'a self, + name: &'b str, + ) -> impl Iterator + use<'a> + where + 'b: 'a, + { + self.contract_data.find_contract_by_name(name) } } @@ -122,6 +129,40 @@ impl SemanticContext { self.file_node_mapper.file_id_from_node_id(node_id) } + /// Returns the pre-computed list of functions visible in the given + /// contract's hierarchy (per C3 linearisation), with overrides resolved and + /// sorted by name. `contract_id` must be a registered contract definition. + pub fn linearised_functions(&self, contract_id: NodeId) -> &[ir::FunctionDefinition] { + self.contract_data.linearised_functions(contract_id) + } + + /// Returns the pre-computed list of state variables visible in the given + /// contract's hierarchy, in storage-layout order (most-base first, then + /// each contract's own variables). `contract_id` must be a registered + /// contract definition. + pub fn linearised_state_variables( + &self, + contract_id: NodeId, + ) -> &[ir::StateVariableDefinition] { + self.contract_data.linearised_state_variables(contract_id) + } + + /// Returns the pre-computed list of errors visible in the given contract's + /// hierarchy (including base contracts and interfaces, in reverse + /// linearisation order). `contract_id` must be a registered contract + /// definition. + pub fn linearised_errors(&self, contract_id: NodeId) -> &[ir::ErrorDefinition] { + self.contract_data.linearised_errors(contract_id) + } + + /// Returns the pre-computed list of events visible in the given contract's + /// hierarchy (including base contracts and interfaces, in reverse + /// linearisation order). `contract_id` must be a registered contract + /// definition. + pub fn linearised_events(&self, contract_id: NodeId) -> &[ir::EventDefinition] { + self.contract_data.linearised_events(contract_id) + } + pub fn resolve_reference_identifier_to_definition_id(&self, node_id: NodeId) -> Option { let reference = self .binder() diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/mod.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/mod.rs index 59177c3130..460a41aa40 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/mod.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/mod.rs @@ -2,7 +2,8 @@ mod common; pub(crate) mod p1_collect_definitions; pub(crate) mod p2_linearise_contracts; pub(crate) mod p3_type_definitions; -pub(crate) mod p4_resolve_references; +pub(crate) mod p4_compute_linearisations; +pub(crate) mod p5_resolve_references; #[cfg(test)] mod tests; diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_compute_linearisations/mod.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_compute_linearisations/mod.rs new file mode 100644 index 0000000000..e95b1867e5 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_compute_linearisations/mod.rs @@ -0,0 +1,201 @@ +use std::cmp::Ordering; +use std::collections::HashMap; +use std::sync::Arc; + +use slang_solidity_v2_common::nodes::NodeId; +use slang_solidity_v2_ir::ir; + +use crate::binder::{Binder, Definition}; +use crate::context::{ContractData, ContractLinearisations}; +use crate::types::TypeRegistry; + +/// In this pass we walk every contract's linearised bases and pre-compute the +/// collections of functions, state variables, errors and events visible in the +/// contract's hierarchy, storing them in a `ContractDataCache`. +pub fn run(binder: &Binder, types: &TypeRegistry) -> ContractData { + let mut contracts = Vec::new(); + let mut data = HashMap::new(); + + for (contract_id, definition) in binder.definitions() { + let Definition::Contract(contract) = definition else { + continue; + }; + let contract_id = *contract_id; + + let ir_node = Arc::clone(&contract.ir_node); + contracts.push(ir_node); + + let linearisations = compute_linearised_members(binder, types, contract_id); + data.insert(contract_id, linearisations); + } + + ContractData::new(contracts, data) +} + +fn compute_linearised_members( + binder: &Binder, + types: &TypeRegistry, + contract_id: NodeId, +) -> ContractLinearisations { + let functions = collect_linearised_functions(binder, types, contract_id); + let state_variables = collect_linearised_state_variables(binder, contract_id); + let errors = collect_linearised_errors(binder, contract_id); + let events = collect_linearised_events(binder, contract_id); + + // TODO(validation): check that there is no redefinition of identifiers among all contracts in the hierarchy + + ContractLinearisations { + functions, + state_variables, + errors, + events, + } +} + +fn collect_linearised_functions( + binder: &Binder, + types: &TypeRegistry, + contract_id: NodeId, +) -> Vec { + let Some(linearised_bases) = binder.get_linearised_bases(contract_id) else { + return Vec::new(); + }; + + let mut functions: Vec = Vec::new(); + for base_id in linearised_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 Some(Definition::Contract(base)) = binder.find_definition_by_id(*base_id) else { + continue; + }; + + for member in &base.ir_node.members { + let ir::ContractMember::FunctionDefinition(function) = member else { + continue; + }; + if !matches!( + function.kind, + ir::FunctionKind::Regular | ir::FunctionKind::Fallback | ir::FunctionKind::Receive + ) { + continue; + } + let overridden = functions + .iter() + .any(|existing| function_overrides(binder, types, existing, function)); + if !overridden { + functions.push(Arc::clone(function)); + } + // TODO(validation): if overriding, function must have the `override` specifier and the overriden functions must be marked `virtual` + // TODO(validation): if overriding multiple ancestors, the function needs to specify the bases in a specifier + } + } + + 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.unparse().cmp(b.unparse()), + }); + functions +} + +fn function_overrides( + binder: &Binder, + types: &TypeRegistry, + function: &ir::FunctionDefinition, + other: &ir::FunctionDefinition, +) -> bool { + let name_matches = match (&function.name, &other.name) { + (None, None) => function.kind == other.kind, + (Some(name), Some(other_name)) => name.unparse() == other_name.unparse(), + _ => false, + }; + if !name_matches { + return false; + } + let type_id = binder.node_typing(function.id()).as_type_id(); + let other_type_id = binder.node_typing(other.id()).as_type_id(); + match (type_id, other_type_id) { + (Some(type_id), Some(other_type_id)) => { + types.type_id_is_function_and_overrides(type_id, other_type_id) + } + _ => false, + } + // TODO(validation) SDR[6]: check also that the function mutability is stricter than other's +} + +/// Walks the linearised bases in reverse (most-base first) and concatenates +/// every contract's state-variable members in source order. Interfaces don't +/// contribute state variables in Solidity. +fn collect_linearised_state_variables( + binder: &Binder, + contract_id: NodeId, +) -> Vec { + let mut state_variables = Vec::new(); + let Some(linearised_bases) = binder.get_linearised_bases(contract_id) else { + return state_variables; + }; + for base_id in linearised_bases.iter().rev() { + let Some(Definition::Contract(base)) = binder.find_definition_by_id(*base_id) else { + continue; + }; + for member in &base.ir_node.members { + if let ir::ContractMember::StateVariableDefinition(state_variable) = member { + state_variables.push(Arc::clone(state_variable)); + } + // TODO(validation): check for duplicate declarations + // TODO(validation): if the state variable is `public`, check if it + // overrides a function and validate the presence of `override` (in + // the variable) and `virtual` (in the function) modifiers + } + } + state_variables +} + +/// Walks the linearised bases in reverse and concatenates every contract / +/// interface error definition. +fn collect_linearised_errors(binder: &Binder, contract_id: NodeId) -> Vec { + let mut errors = Vec::new(); + let Some(linearised_bases) = binder.get_linearised_bases(contract_id) else { + return errors; + }; + for base_id in linearised_bases.iter().rev() { + let members = match binder.find_definition_by_id(*base_id) { + Some(Definition::Contract(base)) => &base.ir_node.members, + Some(Definition::Interface(base)) => &base.ir_node.members, + _ => continue, + }; + for member in members { + if let ir::ContractMember::ErrorDefinition(error) = member { + errors.push(Arc::clone(error)); + } + // TODO(validation): check for duplicate declarations + } + } + errors +} + +/// Walks the linearised bases in reverse and concatenates every contract / +/// interface event definition. +fn collect_linearised_events(binder: &Binder, contract_id: NodeId) -> Vec { + let mut events = Vec::new(); + let Some(linearised_bases) = binder.get_linearised_bases(contract_id) else { + return events; + }; + for base_id in linearised_bases.iter().rev() { + let members = match binder.find_definition_by_id(*base_id) { + Some(Definition::Contract(base)) => &base.ir_node.members, + Some(Definition::Interface(base)) => &base.ir_node.members, + _ => continue, + }; + for member in members { + if let ir::ContractMember::EventDefinition(event) = member { + events.push(Arc::clone(event)); + } + // TODO(validation): check for duplicate declarations, considering + // the full signature since events can be overloaded + } + } + events +} diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/disambiguation.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p5_resolve_references/disambiguation.rs similarity index 100% rename from crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/disambiguation.rs rename to crates/solidity-v2/outputs/cargo/semantic/src/passes/p5_resolve_references/disambiguation.rs diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/mod.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p5_resolve_references/mod.rs similarity index 100% rename from crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/mod.rs rename to crates/solidity-v2/outputs/cargo/semantic/src/passes/p5_resolve_references/mod.rs diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/resolution.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p5_resolve_references/resolution.rs similarity index 100% rename from crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/resolution.rs rename to crates/solidity-v2/outputs/cargo/semantic/src/passes/p5_resolve_references/resolution.rs diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/typing.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p5_resolve_references/typing.rs similarity index 100% rename from crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/typing.rs rename to crates/solidity-v2/outputs/cargo/semantic/src/passes/p5_resolve_references/typing.rs diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/visitor.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p5_resolve_references/visitor.rs similarity index 100% rename from crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/visitor.rs rename to crates/solidity-v2/outputs/cargo/semantic/src/passes/p5_resolve_references/visitor.rs diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/tests/binder.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/tests/binder.rs index 2c7f0c3d2c..322a9eabee 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/tests/binder.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/tests/binder.rs @@ -9,7 +9,7 @@ use slang_solidity_v2_ir::ir::NodeIdGenerator; use super::build_file; use crate::binder::{Binder, Resolution}; use crate::passes::{ - p1_collect_definitions, p2_linearise_contracts, p3_type_definitions, p4_resolve_references, + p1_collect_definitions, p2_linearise_contracts, p3_type_definitions, p5_resolve_references, }; use crate::types::TypeRegistry; @@ -278,7 +278,7 @@ contract Test is Base { "Semantic diagnostics: {diagnostics:?}" ); p3_type_definitions::run(&files, &mut binder, &mut types, language_version); - p4_resolve_references::run(&files, &mut binder, &mut types, language_version); + p5_resolve_references::run(&files, &mut binder, &mut types, language_version); // Verify that references were created and most are resolved let references = binder.references(); diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/tests/typing.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/tests/typing.rs index 563b9b9d0a..d602a1baee 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/tests/typing.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/tests/typing.rs @@ -9,7 +9,7 @@ use crate::binder::Binder; use crate::context::SemanticFile; use crate::passes::common::node_id_for_expression_typing; use crate::passes::{ - p1_collect_definitions, p2_linearise_contracts, p3_type_definitions, p4_resolve_references, + p1_collect_definitions, p2_linearise_contracts, p3_type_definitions, p5_resolve_references, }; use crate::types::{ ByteArrayType, BytesType, ContractType, DataLocation, FixedSizeArrayType, IntegerType, @@ -38,7 +38,7 @@ fn analyze(language_version: LanguageVersion, source: &str) -> TypeAnalysis { "Semantic diagnostics: {diagnostics:?}" ); p3_type_definitions::run(&files, &mut binder, &mut types, language_version); - p4_resolve_references::run(&files, &mut binder, &mut types, language_version); + p5_resolve_references::run(&files, &mut binder, &mut types, language_version); TypeAnalysis { file: files.into_iter().next().unwrap(), diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/generated/public_api.txt b/crates/solidity-v2/outputs/cargo/slang_solidity/generated/public_api.txt index 28e73ad944..68a6d11f20 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/generated/public_api.txt +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/generated/public_api.txt @@ -20,6 +20,7 @@ pub fn slang_solidity_v2::compilation::CompilationBuilder::build(self) -> sla pub fn slang_solidity_v2::compilation::CompilationBuilder::create(language_version: slang_solidity_v2_common::versions::version::LanguageVersion, config: C) -> slang_solidity_v2::compilation::CompilationBuilder pub struct slang_solidity_v2::compilation::CompilationUnit impl slang_solidity_v2::compilation::CompilationUnit +pub fn slang_solidity_v2::compilation::CompilationUnit::all_contracts(&self) -> impl core::iter::traits::iterator::Iterator + use<'_> pub fn slang_solidity_v2::compilation::CompilationUnit::all_definitions(&self) -> impl core::iter::traits::iterator::Iterator + use<'_> pub fn slang_solidity_v2::compilation::CompilationUnit::all_references(&self) -> impl core::iter::traits::iterator::Iterator + use<'_> pub fn slang_solidity_v2::compilation::CompilationUnit::compute_contracts_abi(&self) -> alloc::vec::Vec @@ -27,7 +28,7 @@ pub fn slang_solidity_v2::compilation::CompilationUnit::diagnostics(&self) -> &s pub fn slang_solidity_v2::compilation::CompilationUnit::file(&self, id: &str) -> core::option::Option pub fn slang_solidity_v2::compilation::CompilationUnit::file_ids(&self) -> alloc::vec::Vec pub fn slang_solidity_v2::compilation::CompilationUnit::files(&self) -> impl core::iter::traits::iterator::Iterator + use<'_> -pub fn slang_solidity_v2::compilation::CompilationUnit::find_contract_by_name(&self, name: &str) -> core::option::Option +pub fn slang_solidity_v2::compilation::CompilationUnit::find_contract_by_name<'a, 'b>(&'a self, name: &'b str) -> impl core::iter::traits::iterator::Iterator + use<'a> where 'b: 'a pub fn slang_solidity_v2::compilation::CompilationUnit::language_version(&self) -> slang_solidity_v2_common::versions::version::LanguageVersion pub struct slang_solidity_v2::compilation::FileStruct impl slang_solidity_v2::compilation::FileStruct diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/unit.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/unit.rs index 586b24c908..c25802d74f 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/unit.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/unit.rs @@ -74,12 +74,25 @@ impl CompilationUnit { }) } - pub fn find_contract_by_name(&self, name: &str) -> Option { + pub fn find_contract_by_name<'a, 'b>( + &'a self, + name: &'b str, + ) -> impl Iterator + use<'a> + where + 'b: 'a, + { self.semantic .find_contract_by_name(name) .map(|contract| ast::create_contract_definition(&contract, &self.semantic)) } + /// Iterates over every contract definition in this compilation unit. + pub fn all_contracts(&self) -> impl Iterator + use<'_> { + self.semantic + .all_contracts() + .map(|contract| ast::create_contract_definition(contract, &self.semantic)) + } + pub fn compute_contracts_abi(&self) -> Vec { self.files .values() diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi/internal_signature.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi/internal_signature.rs index 52e9e676eb..da25837861 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi/internal_signature.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi/internal_signature.rs @@ -4,11 +4,12 @@ fn test_compute_internal_signature() { let test_contract = unit .find_contract_by_name("Test") + .next() .expect("Test contract can be found"); // Functions are linearised in alphabetical order, with the unnamed // `receive`/`fallback` functions sorted first. - let functions = test_contract.compute_linearised_functions(); + let functions = test_contract.linearised_functions(); assert_eq!(functions.len(), 3); assert_eq!( @@ -35,7 +36,7 @@ fn test_compute_internal_signature() { // State variables are linearised in storage layout order (bases first). // Only the public variables defines a getter with an internal signature. - let state_variables = test_contract.compute_linearised_state_variables(); + let state_variables = test_contract.linearised_state_variables(); assert_eq!(state_variables.len(), 3); assert_eq!( state_variables[0].compute_internal_signature(), @@ -48,7 +49,7 @@ fn test_compute_internal_signature() { ); // Errors and events are linearised with base contracts first. - let errors = test_contract.compute_linearised_errors(); + let errors = test_contract.linearised_errors(); assert_eq!(errors.len(), 2); assert_eq!( errors[0].compute_internal_signature(), @@ -59,7 +60,7 @@ fn test_compute_internal_signature() { Some("InsufficientBalance(uint256,uint256)".to_string()) ); - let events = test_contract.compute_linearised_events(); + let events = test_contract.linearised_events(); assert_eq!(events.len(), 2); assert_eq!( events[0].compute_internal_signature(), diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi/selectors.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi/selectors.rs index c62bf8a661..0cba5d7877 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi/selectors.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi/selectors.rs @@ -6,9 +6,10 @@ fn test_function_selector() { let counter = unit .find_contract_by_name("Counter") + .next() .expect("contract can be found"); - let functions = counter.compute_linearised_functions(); + let functions = counter.linearised_functions(); assert_eq!(functions.len(), 5); // all the functions in the contract are public @@ -18,7 +19,7 @@ fn test_function_selector() { assert_eq!(functions[3].compute_selector(), Some(0x7cf5_dab0_u32)); // increment(uint256) assert_eq!(functions[4].compute_selector(), Some(0x6aa6_33b6_u32)); // isEnabled() - let state_variables = counter.compute_linearised_state_variables(); + let state_variables = counter.linearised_state_variables(); assert_eq!(state_variables.len(), 4); // for state variables, selectors only make sense for public getters @@ -34,6 +35,7 @@ fn test_events_and_errors_selectors() { let test_contract = unit .find_contract_by_name("Test") + .next() .expect("Test contract can be found"); let events = test_contract.events(); @@ -51,6 +53,7 @@ fn test_selectors_for_functions_with_tuple_parameters() { let test = unit .find_contract_by_name("Test") + .next() .expect("contract is found"); let functions = test.functions(); diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi/storage_layout.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi/storage_layout.rs index 6c1504b1f8..f2955dfb1c 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi/storage_layout.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi/storage_layout.rs @@ -73,6 +73,7 @@ fn test_storage_layout() { let counter = unit .find_contract_by_name("C") + .next() .expect("contract can be found"); let counter_abi = counter.compute_abi().expect("can compute ABI"); let layout = counter_abi.storage_layout(); @@ -102,6 +103,7 @@ fn test_transient_and_custom_storage_layout() { let d_contract = unit .find_contract_by_name("D") + .next() .expect("contract can be found"); let d_abi = d_contract.compute_abi().expect("can compute ABI"); let d_layout = d_abi.storage_layout(); @@ -112,6 +114,7 @@ fn test_transient_and_custom_storage_layout() { let e_contract = unit .find_contract_by_name("E") + .next() .expect("contract can be found"); let e_abi = e_contract.compute_abi().expect("can compute ABI"); let e_layout = e_abi.storage_layout(); @@ -132,6 +135,7 @@ fn test_erc7201_storage_layout() { let f_contract = unit .find_contract_by_name("F") + .next() .expect("contract can be found"); let f_abi = f_contract.compute_abi().expect("can compute ABI"); let f_layout = f_abi.storage_layout(); diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/definition_references.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/definition_references.rs index 54fb14c93d..4d4c758be1 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/definition_references.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/definition_references.rs @@ -7,6 +7,7 @@ fn test_definition_references() { let ownable = unit .find_contract_by_name("Ownable") + .next() .expect("can find Ownable contract"); // find the `onlyOwner` modifier defined in the `Ownable` contract diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/identifier_path_resolution.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/identifier_path_resolution.rs index 50b79724ea..b8c8fe0a7c 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/identifier_path_resolution.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/identifier_path_resolution.rs @@ -28,6 +28,7 @@ fn test_identifier_path_resolve_to_immediate_definition() { let counter = unit .find_contract_by_name("Counter") + .next() .expect("contract is found"); let counter_bases: Vec<_> = counter .inheritance_types() @@ -61,7 +62,10 @@ fn test_identifier_path_resolve_to_immediate_definition() { fn test_identifier_path_resolve_to_immediate_resolves_to_direct_definition() { let unit = ChainedImports::build_compilation_unit(); - let a1 = unit.find_contract_by_name("A1").expect("contract is found"); + let a1 = unit + .find_contract_by_name("A1") + .next() + .expect("contract is found"); let i1_typename = a1 .inheritance_types() .iter() @@ -86,7 +90,10 @@ fn test_identifier_path_resolve_to_immediate_resolves_to_direct_definition() { fn test_chained_imports_resolution() { let unit = ChainedImports::build_compilation_unit(); - let a1 = unit.find_contract_by_name("A1").expect("contract is found"); + let a1 = unit + .find_contract_by_name("A1") + .next() + .expect("contract is found"); let b1_typename = a1 .inheritance_types() .iter() diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/linearisations.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/linearisations.rs index 7b058c07e4..64f8dbfe73 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/linearisations.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/linearisations.rs @@ -32,8 +32,9 @@ fn test_contract_compute_linearised_bases() { let counter = unit .find_contract_by_name("Counter") + .next() .expect("can find Counter contract"); - let bases = counter.compute_linearised_bases(); + let bases = counter.linearised_bases(); assert_eq!(bases.len(), 3); let ContractBase::Contract(counter) = &bases[0] else { @@ -56,9 +57,10 @@ fn test_contract_compute_linearised_state_variables() { let counter = unit .find_contract_by_name("Counter") + .next() .expect("can find Counter contract"); - let state_variables = counter.compute_linearised_state_variables(); + let state_variables = counter.linearised_state_variables(); assert_eq!(state_variables.len(), 4); assert_eq!(state_variables[0].name().name(), "_owner"); @@ -73,9 +75,10 @@ fn test_contract_compute_linearised_functions() { let counter = unit .find_contract_by_name("Counter") + .next() .expect("can find Counter contract"); - let functions = counter.compute_linearised_functions(); + let functions = counter.linearised_functions(); assert_eq!(functions.len(), 5); assert!(functions[0] @@ -101,8 +104,9 @@ fn test_contract_compute_linearised_functions_with_overrides() { let inherited = unit .find_contract_by_name("Inherited") + .next() .expect("can find contract"); - let functions = inherited.compute_linearised_functions(); + let functions = inherited.linearised_functions(); assert_eq!(functions.len(), 3); assert!(functions[0] .name() diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/members.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/members.rs index cd6459c228..fcf14170b7 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/members.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/members.rs @@ -7,6 +7,7 @@ fn test_contract_direct_bases() { let counter = unit .find_contract_by_name("Counter") + .next() .expect("can find Counter contract"); let bases = counter.direct_bases(); assert_eq!(bases.len(), 2); @@ -27,6 +28,7 @@ fn test_contract_constructor_and_modifiers() { let counter = unit .find_contract_by_name("Counter") + .next() .expect("can find Counter contract"); let constructor = counter.constructor(); diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/node_location.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/node_location.rs index e44dd80078..77cea9f371 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/node_location.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/node_location.rs @@ -7,6 +7,7 @@ fn test_get_file_id_and_text_range() { let ownable = unit .find_contract_by_name("Ownable") + .next() .expect("contract is found"); assert_eq!(ownable.get_file_id(), "ownable.sol"); @@ -30,11 +31,13 @@ fn test_get_file_id_and_text_range() { let activatable = unit .find_contract_by_name("Activatable") + .next() .expect("contract is found"); assert_eq!(activatable.get_file_id(), "activatable.sol"); let counter = unit .find_contract_by_name("Counter") + .next() .expect("contract is found"); assert_eq!(counter.get_file_id(), "main.sol"); } diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/typing.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/typing.rs index fcb5d46943..d37227ea0f 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/typing.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast/typing.rs @@ -7,6 +7,7 @@ fn test_get_type() { let ownable = unit .find_contract_by_name("Ownable") + .next() .expect("contract is found"); let state_variables = ownable @@ -37,6 +38,7 @@ fn test_function_get_type() { let counter = unit .find_contract_by_name("Counter") + .next() .expect("contract is found"); let increment = counter diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/unit.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/unit.rs index 185ba4affe..f63ac072c7 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/unit.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/unit.rs @@ -71,12 +71,15 @@ fn test_find_contract_by_name() { let counter = unit .find_contract_by_name("Counter") + .next() .expect("Counter contract is found"); let ownable = unit .find_contract_by_name("Ownable") + .next() .expect("Ownable contract is found"); let activatable = unit .find_contract_by_name("Activatable") + .next() .expect("Activatable contract is found"); assert_eq!(counter.name().name(), "Counter");