Skip to content

Commit

Permalink
Implement decoding for nested struct types
Browse files Browse the repository at this point in the history
  • Loading branch information
Y-Nak committed Jun 6, 2022
1 parent e8dc1fb commit 6a7c648
Show file tree
Hide file tree
Showing 19 changed files with 619 additions and 73 deletions.
12 changes: 7 additions & 5 deletions crates/abi/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,15 @@ impl AbiType {
match self {
Self::UInt(_) | Self::Int(_) | Self::Address | Self::Bool | Self::Function => 32,
Self::Array { elem_ty, len } => elem_ty.header_size() * len,
Self::Tuple(fields) => fields.iter().fold(0, |acc, field| {
if field.ty.is_static() {
field.ty.header_size() + acc
Self::Tuple(fields) => {
if self.is_static() {
fields
.iter()
.fold(0, |acc, field| field.ty.header_size() + acc)
} else {
32 + acc
32
}
}),
}
Self::Bytes | Self::String => 32,
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/analyzer/tests/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ test_analysis! { guest_book, "demos/guest_book.fe"}
test_analysis! { simple_open_auction, "demos/simple_open_auction.fe"}
test_analysis! { uniswap, "demos/uniswap.fe"}
test_analysis! { address_bytes10_map, "features/address_bytes10_map.fe"}
test_analysis! { abi_decode_complex, "features/abi_decode_complex.fe"}
test_analysis! { assert, "features/assert.fe"}
test_analysis! { associated_fns, "features/associated_fns.fe"}
test_analysis! { aug_assign, "features/aug_assign.fe"}
Expand Down
211 changes: 211 additions & 0 deletions crates/analyzer/tests/snapshots/analysis__abi_decode_complex.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
---
source: crates/analyzer/tests/analysis.rs
expression: "build_snapshot(&db, module)"
---
note:
┌─ abi_decode_complex.fe:2:5
2 │ ╭ pub fn decode_static_complex(s: StaticComplex) -> StaticComplex {
3 │ │ return s
4 │ │ }
│ ╰─────^ attributes hash: 13546101684275548970
= FunctionSignature {
self_decl: None,
ctx_decl: None,
params: [
FunctionParam {
label: None,
name: "s",
typ: Ok(
Struct(
Struct {
name: "StaticComplex",
field_count: 2,
},
),
),
},
],
return_type: Ok(
Struct(
Struct {
name: "StaticComplex",
field_count: 2,
},
),
),
}

note:
┌─ abi_decode_complex.fe:3:16
3return s
^ StaticComplex: Memory

note:
┌─ abi_decode_complex.fe:6:5
6 │ ╭ pub fn decode_string_complex(s: StringComplex) -> StringComplex {
7 │ │ return s
8 │ │ }
│ ╰─────^ attributes hash: 9213499526282989909
= FunctionSignature {
self_decl: None,
ctx_decl: None,
params: [
FunctionParam {
label: None,
name: "s",
typ: Ok(
Struct(
Struct {
name: "StringComplex",
field_count: 2,
},
),
),
},
],
return_type: Ok(
Struct(
Struct {
name: "StringComplex",
field_count: 2,
},
),
),
}

note:
┌─ abi_decode_complex.fe:7:16
7return s
^ StringComplex: Memory

note:
┌─ abi_decode_complex.fe:10:5
10 │ ╭ pub fn decode_bytes_complex(s: BytesComplex) -> BytesComplex {
11 │ │ return s
12 │ │ }
│ ╰─────^ attributes hash: 9262156959297131687
= FunctionSignature {
self_decl: None,
ctx_decl: None,
params: [
FunctionParam {
label: None,
name: "s",
typ: Ok(
Struct(
Struct {
name: "BytesComplex",
field_count: 2,
},
),
),
},
],
return_type: Ok(
Struct(
Struct {
name: "BytesComplex",
field_count: 2,
},
),
),
}

note:
┌─ abi_decode_complex.fe:11:16
11return s
^ BytesComplex: Memory

note:
┌─ abi_decode_complex.fe:14:5
14 │ ╭ pub fn decode_nested_dynamic_complex(s: NestedDynamicComplex) -> NestedDynamicComplex {
15 │ │ return s
16 │ │ }
│ ╰─────^ attributes hash: 3503331736540589795
= FunctionSignature {
self_decl: None,
ctx_decl: None,
params: [
FunctionParam {
label: None,
name: "s",
typ: Ok(
Struct(
Struct {
name: "NestedDynamicComplex",
field_count: 3,
},
),
),
},
],
return_type: Ok(
Struct(
Struct {
name: "NestedDynamicComplex",
field_count: 3,
},
),
),
}

note:
┌─ abi_decode_complex.fe:15:16
15return s
^ NestedDynamicComplex: Memory

note:
┌─ abi_decode_complex.fe:20:5
20pub inner_x: i32
^^^^^^^^^^^^^^^^ i32
21pub inner_y: i32
^^^^^^^^^^^^^^^^ i32

note:
┌─ abi_decode_complex.fe:25:5
25pub inner: StaticInner
^^^^^^^^^^^^^^^^^^^^^^ StaticInner
26pub outer_x: i256
^^^^^^^^^^^^^^^^^ i256

note:
┌─ abi_decode_complex.fe:30:5
30pub string: String<8>
^^^^^^^^^^^^^^^^^^^^^ String<8>
31pub outer_x: i32
^^^^^^^^^^^^^^^^ i32

note:
┌─ abi_decode_complex.fe:35:5
35pub bytes: Array<u8, 8>
^^^^^^^^^^^^^^^^^^^^^^^ Array<u8, 8>
36pub outer_x: i32
^^^^^^^^^^^^^^^^ i32

note:
┌─ abi_decode_complex.fe:40:5
40pub bytes_complex: BytesComplex
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ BytesComplex
41pub static_complex: StaticComplex
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ StaticComplex
42pub string_complex: StringComplex
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ StringComplex


2 changes: 2 additions & 0 deletions crates/codegen/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub trait CodegenDb: MirDb + Upcast<dyn MirDb> + UpcastMut<dyn MirDb> {
fn codegen_abi_contract(&self, contract: ContractId) -> AbiContract;
#[salsa::invoke(queries::abi::abi_type_maximum_size)]
fn codegen_abi_type_maximum_size(&self, ty: TypeId) -> usize;
#[salsa::invoke(queries::abi::abi_type_minimum_size)]
fn codegen_abi_type_minimum_size(&self, ty: TypeId) -> usize;
#[salsa::invoke(queries::abi::abi_function_argument_maximum_size)]
fn codegen_abi_function_argument_maximum_size(&self, contract: FunctionId) -> usize;
#[salsa::invoke(queries::abi::abi_function_return_maximum_size)]
Expand Down
34 changes: 34 additions & 0 deletions crates/codegen/src/db/queries/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,40 @@ pub fn abi_type_maximum_size(db: &dyn CodegenDb, ty: TypeId) -> usize {
abi_type.header_size() + 32 + ceil_32(def.len)
}
ir::TypeKind::String(len) => abi_type.header_size() + 32 + ceil_32(*len),
_ if ty.is_aggregate(db.upcast()) => {
let mut maximum = 0;
for i in 0..ty.aggregate_field_num(db.upcast()) {
let field_ty = ty.projection_ty_imm(db.upcast(), i);
maximum += db.codegen_abi_type_maximum_size(field_ty)
}
maximum + 32
}
_ => unreachable!(),
}
}
}

pub fn abi_type_minimum_size(db: &dyn CodegenDb, ty: TypeId) -> usize {
let abi_type = db.codegen_abi_type(ty);
if abi_type.is_static() {
abi_type.header_size()
} else {
match &ty.data(db.upcast()).kind {
ir::TypeKind::Array(def) => {
debug_assert! {matches!(def.elem_ty.data
(db.upcast()).kind, ir::TypeKind::U8),
}
abi_type.header_size() + 32
}
ir::TypeKind::String(_) => abi_type.header_size() + 32,
_ if ty.is_aggregate(db.upcast()) => {
let mut minimum = 0;
for i in 0..ty.aggregate_field_num(db.upcast()) {
let field_ty = ty.projection_ty_imm(db.upcast(), i);
minimum += db.codegen_abi_type_minimum_size(field_ty)
}
minimum + 32
}
_ => unreachable!(),
}
}
Expand Down
Loading

0 comments on commit 6a7c648

Please sign in to comment.