Skip to content

Commit 9c2b8b4

Browse files
authored
Add support for fixed-size arrays in the binder (#1518)
This PR adds a new type in the binder's `TypeRegistry` for fixed-size arrays. It also implements a basic compile-time constant evaluator to be able to compute the size of fixed-size arrays declared. This implementation only supports integers at the moment.
1 parent e495eb2 commit 9c2b8b4

File tree

47 files changed

+1460
-75
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1460
-75
lines changed

Cargo.lock

Lines changed: 29 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ logos = { version = "0.16.0" }
142142
lsp-positions = { version = "0.3.0" }
143143
markdown = { version = "0.3.0" }
144144
nom = { version = "7.1.3" }
145+
num-bigint = { version = "0.4.6" }
145146
num-format = { version = "0.4.4" }
147+
num-traits = { version = "0.2.18" }
146148
paste = { version = "1.0.15" }
147149
proc-macro2 = { version = "1.0.94" }
148150
public-api = { version = "0.47.1" }

crates/solidity/outputs/cargo/crate/Cargo.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@ categories = [
2727
[features]
2828
default = []
2929
__private_ariadne_errors = ["dep:ariadne"]
30-
__private_backend_api = ["dep:indexmap", "dep:paste", "dep:sha3"]
30+
__private_backend_api = [
31+
"dep:indexmap",
32+
"dep:paste",
33+
"dep:num-bigint",
34+
"dep:num-traits",
35+
"dep:sha3",
36+
]
3137
__private_wasm_apis = []
3238
__private_testing_utils = ["metaslang_bindings/__private_testing_utils"]
3339

@@ -36,6 +42,8 @@ ariadne = { workspace = true, optional = true }
3642
indexmap = { workspace = true, optional = true }
3743
metaslang_bindings = { workspace = true }
3844
metaslang_cst = { workspace = true }
45+
num-bigint = { workspace = true, optional = true }
46+
num-traits = { workspace = true, optional = true }
3947
paste = { workspace = true, optional = true }
4048
semver = { workspace = true }
4149
serde = { workspace = true }

crates/solidity/outputs/cargo/crate/src/backend/abi/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ impl ContractDefinitionStruct {
102102

103103
// check if we can pack the variable in the previous slot
104104
let remaining_bytes = SemanticAnalysis::SLOT_SIZE - (ptr % SemanticAnalysis::SLOT_SIZE);
105-
if variable_size > remaining_bytes {
105+
if remaining_bytes < SemanticAnalysis::SLOT_SIZE && variable_size > remaining_bytes {
106106
ptr += remaining_bytes;
107107
}
108108

crates/solidity/outputs/cargo/crate/src/backend/binder/definitions.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub enum Definition {
3939
#[derive(Debug)]
4040
pub struct ConstantDefinition {
4141
pub(crate) ir_node: output_ir::ConstantDefinition,
42+
pub scope_id: ScopeId,
4243
}
4344

4445
#[derive(Debug)]
@@ -301,9 +302,12 @@ impl Definition {
301302
}
302303
}
303304

304-
pub(crate) fn new_constant(ir_node: &output_ir::ConstantDefinition) -> Self {
305+
pub(crate) fn new_constant(ir_node: &output_ir::ConstantDefinition, scope_id: ScopeId) -> Self {
306+
// for constants we store the scope_id where it's defined to use for
307+
// evaluation of compile-time constants (eg. fixed arrays size)
305308
Self::Constant(ConstantDefinition {
306309
ir_node: Rc::clone(ir_node),
310+
scope_id,
307311
})
308312
}
309313

crates/solidity/outputs/cargo/crate/src/backend/built_ins.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,10 @@ impl<'a> BuiltInsResolver<'a> {
562562
}
563563
Type::Enum { .. } => None,
564564
Type::FixedPointNumber { .. } => None,
565+
Type::FixedSizeArray { .. } => match symbol {
566+
"length" => Some(BuiltIn::Length),
567+
_ => None,
568+
},
565569
Type::Function(FunctionType { external, .. }) => {
566570
// Solidity < 0.5.0 didn't require explicit visibility attributes
567571
if *external || self.language_version < VERSION_0_5_0 {

crates/solidity/outputs/cargo/crate/src/backend/ir/ast/node_extensions/types.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub enum Type {
1616
Bytes(BytesType),
1717
Contract(ContractType),
1818
Enum(EnumType),
19+
FixedSizeArray(FixedSizeArrayType),
1920
FixedPointNumber(FixedPointNumberType),
2021
Function(FunctionType),
2122
Integer(IntegerType),
@@ -55,6 +56,7 @@ define_type_variant!(ByteArray);
5556
define_type_variant!(Bytes);
5657
define_type_variant!(Contract);
5758
define_type_variant!(Enum);
59+
define_type_variant!(FixedSizeArray);
5860
define_type_variant!(FixedPointNumber);
5961
define_type_variant!(Function);
6062
define_type_variant!(Integer);
@@ -79,6 +81,9 @@ impl Type {
7981
types::Type::Bytes { .. } => Self::Bytes(BytesType { type_id, semantic }),
8082
types::Type::Contract { .. } => Self::Contract(ContractType { type_id, semantic }),
8183
types::Type::Enum { .. } => Self::Enum(EnumType { type_id, semantic }),
84+
types::Type::FixedSizeArray { .. } => {
85+
Self::FixedSizeArray(FixedSizeArrayType { type_id, semantic })
86+
}
8287
types::Type::FixedPointNumber { .. } => {
8388
Self::FixedPointNumber(FixedPointNumberType { type_id, semantic })
8489
}
@@ -106,6 +111,7 @@ impl Type {
106111
Type::Bytes(details) => details.type_id,
107112
Type::Contract(details) => details.type_id,
108113
Type::Enum(details) => details.type_id,
114+
Type::FixedSizeArray(details) => details.type_id,
109115
Type::FixedPointNumber(details) => details.type_id,
110116
Type::Function(details) => details.type_id,
111117
Type::Integer(details) => details.type_id,
@@ -183,6 +189,27 @@ impl EnumType {
183189
}
184190
}
185191

192+
impl FixedSizeArrayType {
193+
pub fn element_type(&self) -> Type {
194+
let types::Type::FixedSizeArray { element_type, .. } = self.internal_type() else {
195+
unreachable!("invalid fixed-size array type");
196+
};
197+
Type::create(*element_type, &self.semantic)
198+
}
199+
pub fn location(&self) -> DataLocation {
200+
let types::Type::FixedSizeArray { location, .. } = self.internal_type() else {
201+
unreachable!("invalid fixed-size array type");
202+
};
203+
*location
204+
}
205+
pub fn size(&self) -> usize {
206+
let types::Type::FixedSizeArray { size, .. } = self.internal_type() else {
207+
unreachable!("invalid fixed-size array type");
208+
};
209+
*size
210+
}
211+
}
212+
186213
impl FixedPointNumberType {
187214
pub fn signed(&self) -> bool {
188215
let types::Type::FixedPointNumber { signed, .. } = self.internal_type() else {

crates/solidity/outputs/cargo/crate/src/backend/passes/p1_flatten_contracts.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ pub fn run_file(language_version: &Version, source_unit: &input::SourceUnit) ->
1818
pass.transform_source_unit(source_unit)
1919
}
2020

21+
// We need this entry point to test the compile-time constant evaluator
22+
#[cfg(test)]
23+
pub(crate) fn transform_expression(
24+
language_version: &Version,
25+
expression: &input::Expression,
26+
) -> output::Expression {
27+
let mut pass = Pass {
28+
language_version: language_version.clone(),
29+
};
30+
pass.transform_expression(expression)
31+
}
32+
2133
struct Pass {
2234
language_version: Version,
2335
}

crates/solidity/outputs/cargo/crate/src/backend/passes/p2_collect_definitions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ impl Visitor for Pass<'_> {
416416
}
417417

418418
fn enter_constant_definition(&mut self, node: &input_ir::ConstantDefinition) -> bool {
419-
let definition = Definition::new_constant(node);
419+
let definition = Definition::new_constant(node, self.current_scope_id());
420420
self.insert_definition_in_current_scope(definition);
421421

422422
false

0 commit comments

Comments
 (0)