Skip to content

Commit 23270b5

Browse files
committed
Implement ABI alias handling in Fuel ABI emitter.
1 parent 2592130 commit 23270b5

23 files changed

+1505
-26
lines changed

forc-pkg/src/pkg.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1813,7 +1813,7 @@ pub fn compile(
18131813
unique_names: HashMap::new(),
18141814
metadata_declaration_cache: HashMap::new(),
18151815
concrete_declaration_cache: HashMap::new(),
1816-
type_cache_enabled: false,
1816+
type_cache_enabled: experimental.abi_type_aliases,
18171817
experimental,
18181818
},
18191819
engines,

sway-core/src/abi_generation/abi_str.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ impl TypeId {
3838
| (TypeInfo::Custom { .. }, TypeInfo::Enum { .. }) => type_engine
3939
.get(resolved_type_id)
4040
.abi_str(handler, ctx, engines, true),
41-
(_, TypeInfo::Alias { ty, .. }) => ty
41+
(_, TypeInfo::Alias { ty, .. }) if !ctx.abi_type_aliases => ty
4242
.type_id
4343
.get_abi_type_str(handler, ctx, engines, ty.type_id),
44+
(_, TypeInfo::Alias { .. }) => Ok(self_abi_str),
4445
(TypeInfo::Tuple(fields), TypeInfo::Tuple(resolved_fields)) => {
4546
assert_eq!(fields.len(), resolved_fields.len());
4647
let field_strs = resolved_fields
@@ -205,7 +206,13 @@ impl TypeInfo {
205206
"__slice {}",
206207
ty.abi_str(handler, ctx, engines, false)?
207208
)),
208-
Alias { ty, .. } => Ok(ty.abi_str(handler, ctx, engines, false)?),
209+
Alias { name, ty } => {
210+
if ctx.abi_type_aliases {
211+
Ok(name.to_string())
212+
} else {
213+
ty.abi_str(handler, ctx, engines, false)
214+
}
215+
}
209216
TraitType {
210217
name,
211218
implemented_in: _,

sway-core/src/abi_generation/fuel_abi.rs

Lines changed: 147 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl AbiContext<'_> {
5757
AbiStrContext {
5858
program_name: self.program.namespace.current_package_name().to_string(),
5959
abi_with_callpaths: self.abi_with_callpaths,
60-
abi_with_fully_specified_types: false,
60+
abi_with_fully_specified_types: self.experimental.abi_type_aliases,
6161
abi_root_type_without_generic_type_parameters: true,
6262
abi_type_aliases: self.experimental.abi_type_aliases,
6363
}
@@ -68,13 +68,31 @@ impl AbiContext<'_> {
6868
pub struct TypeCacheKey(u64);
6969

7070
impl TypeCacheKey {
71-
fn from_type_id(engines: &Engines, type_id: TypeId) -> Self {
71+
fn from_type_id(engines: &Engines, abi_type_aliases_enabled: bool, type_id: TypeId) -> Self {
7272
let type_engine = engines.te();
7373
let type_info = &*type_engine.get(type_id);
74-
Self::from_type_info(type_info, engines)
74+
Self::from_type_info(type_info, engines, abi_type_aliases_enabled)
7575
}
7676

77-
fn from_type_info(type_info: &TypeInfo, engines: &Engines) -> Self {
77+
fn from_type_info(
78+
type_info: &TypeInfo,
79+
engines: &Engines,
80+
abi_type_aliases_enabled: bool,
81+
) -> Self {
82+
if abi_type_aliases_enabled {
83+
if let TypeInfo::Alias { name, ty } = type_info {
84+
let mut hasher = DefaultHasher::new();
85+
name.hash(&mut hasher);
86+
87+
let target_type_id = engines.te().get_unaliased_type_id(ty.type_id);
88+
let target_key =
89+
TypeCacheKey::from_type_id(engines, abi_type_aliases_enabled, target_type_id);
90+
target_key.0.hash(&mut hasher);
91+
92+
return TypeCacheKey(hasher.finish());
93+
}
94+
}
95+
7896
let mut hasher = DefaultHasher::new();
7997
type_info.hash(&mut hasher, engines);
8098
TypeCacheKey(hasher.finish())
@@ -481,6 +499,7 @@ fn standardize_json_abi_types(json_abi_program: &mut program_abi::ProgramABI) {
481499
d.type_field == decl.type_field
482500
&& decl.components.is_none()
483501
&& decl.type_parameters.is_none()
502+
&& decl.alias_of.is_none()
484503
}) {
485504
old_to_new_id.insert(
486505
decl.metadata_type_id.clone(),
@@ -492,6 +511,7 @@ fn standardize_json_abi_types(json_abi_program: &mut program_abi::ProgramABI) {
492511
d.type_field == decl.type_field
493512
&& d.components == decl.components
494513
&& d.type_parameters == decl.type_parameters
514+
&& d.alias_of == decl.alias_of
495515
}) {
496516
old_to_new_id.insert(
497517
decl.metadata_type_id.clone(),
@@ -603,6 +623,14 @@ fn update_json_type_metadata_declaration(
603623
update_json_type_application(component, old_to_new_id);
604624
}
605625
}
626+
627+
if let Some(alias_of) = &mut type_declaration.alias_of {
628+
if let Some(fuel_abi_types::abi::program::TypeId::Metadata(new_id)) =
629+
old_to_new_id.get(alias_of)
630+
{
631+
*alias_of = new_id.clone();
632+
}
633+
}
606634
}
607635

608636
/// Updates the metadata type IDs used in a `program_abi::TypeConcreteDeclaration` given a HashMap from
@@ -629,7 +657,8 @@ fn generate_concrete_type_declaration(
629657
type_id: TypeId,
630658
resolved_type_id: TypeId,
631659
) -> Result<ConcreteTypeId, ErrorEmitted> {
632-
let cache_key = TypeCacheKey::from_type_id(engines, resolved_type_id);
660+
let cache_key =
661+
TypeCacheKey::from_type_id(engines, ctx.experimental.abi_type_aliases, resolved_type_id);
633662
if ctx.type_cache_enabled {
634663
if let Some(cached_decl) = ctx.concrete_declaration_cache.get(&cache_key) {
635664
return Ok(cached_decl.concrete_type_id.clone());
@@ -653,6 +682,7 @@ fn generate_concrete_type_declaration(
653682

654683
let metadata_type_id = if type_metadata_decl.type_parameters.is_some()
655684
|| type_metadata_decl.components.is_some()
685+
|| type_metadata_decl.alias_of.is_some()
656686
{
657687
Some(type_metadata_decl.metadata_type_id.clone())
658688
} else {
@@ -704,13 +734,39 @@ fn generate_type_metadata_declaration(
704734
resolved_type_id: TypeId,
705735
metadata_types_to_add: &mut Vec<program_abi::TypeMetadataDeclaration>,
706736
) -> Result<program_abi::TypeMetadataDeclaration, ErrorEmitted> {
707-
let cache_key = TypeCacheKey::from_type_id(engines, resolved_type_id);
737+
let cache_key =
738+
TypeCacheKey::from_type_id(engines, ctx.experimental.abi_type_aliases, resolved_type_id);
708739
if ctx.type_cache_enabled {
709740
if let Some(cached_decl) = ctx.metadata_declaration_cache.get(&cache_key) {
710741
return Ok(cached_decl.clone());
711742
}
712743
}
713744

745+
let mut alias_metadata_types_to_add = Vec::<program_abi::TypeMetadataDeclaration>::new();
746+
747+
let type_engine = engines.te();
748+
let alias_of_metadata_decl = if ctx.experimental.abi_type_aliases {
749+
match &*type_engine.get(resolved_type_id) {
750+
TypeInfo::Alias { ty, .. } => {
751+
let dealiased_ty = fully_dealias_type_id(engines, ty.type_id);
752+
let dealiased_metadata_decl = generate_type_metadata_declaration(
753+
handler,
754+
ctx,
755+
engines,
756+
metadata_types,
757+
concrete_types,
758+
dealiased_ty,
759+
dealiased_ty,
760+
&mut alias_metadata_types_to_add,
761+
)?;
762+
Some(dealiased_metadata_decl)
763+
}
764+
_ => None,
765+
}
766+
} else {
767+
None
768+
};
769+
714770
let mut new_metadata_types_to_add = Vec::<program_abi::TypeMetadataDeclaration>::new();
715771

716772
let components = type_id.get_abi_type_components(
@@ -735,22 +791,87 @@ fn generate_type_metadata_declaration(
735791
let type_field =
736792
type_id.get_abi_type_str(handler, &ctx.to_str_context(), engines, resolved_type_id)?;
737793

794+
let alias_of = alias_of_metadata_decl
795+
.as_ref()
796+
.map(|decl| decl.metadata_type_id.clone());
797+
738798
let type_metadata_decl = program_abi::TypeMetadataDeclaration {
739799
metadata_type_id: MetadataTypeId(type_id.index()),
740800
type_field,
741801
components,
742802
type_parameters,
743-
alias_of: None,
803+
alias_of,
744804
};
745805

746806
ctx.metadata_declaration_cache
747807
.insert(cache_key, type_metadata_decl.clone());
748808
metadata_types_to_add.push(type_metadata_decl.clone());
749809
metadata_types_to_add.extend(new_metadata_types_to_add);
810+
metadata_types_to_add.extend(alias_metadata_types_to_add);
750811

751812
Ok(type_metadata_decl)
752813
}
753814

815+
fn fully_dealias_type_id(engines: &Engines, type_id: TypeId) -> TypeId {
816+
fn inner(engines: &Engines, type_id: TypeId, visited: &mut HashSet<TypeId>) -> TypeId {
817+
if !visited.insert(type_id) {
818+
return type_id;
819+
}
820+
821+
let type_engine = engines.te();
822+
match &*type_engine.get(type_id) {
823+
TypeInfo::Alias { ty, .. } => inner(engines, ty.type_id, visited),
824+
TypeInfo::Tuple(fields) => type_engine.insert_tuple(
825+
engines,
826+
fields
827+
.iter()
828+
.map(|field| {
829+
let mut field_clone = field.clone();
830+
let dealiased = inner(engines, field_clone.type_id, visited);
831+
field_clone.type_id = dealiased;
832+
field_clone.initial_type_id = dealiased;
833+
field_clone
834+
})
835+
.collect(),
836+
),
837+
TypeInfo::Array(elem_ty, length) => {
838+
let mut elem_clone = elem_ty.clone();
839+
let dealiased = inner(engines, elem_clone.type_id, visited);
840+
elem_clone.type_id = dealiased;
841+
elem_clone.initial_type_id = dealiased;
842+
type_engine.insert_array(engines, elem_clone, length.clone())
843+
}
844+
TypeInfo::Slice(elem_ty) => {
845+
let mut elem_clone = elem_ty.clone();
846+
let dealiased = inner(engines, elem_clone.type_id, visited);
847+
elem_clone.type_id = dealiased;
848+
elem_clone.initial_type_id = dealiased;
849+
type_engine.insert_slice(engines, elem_clone)
850+
}
851+
TypeInfo::Ptr(elem_ty) => {
852+
let mut elem_clone = elem_ty.clone();
853+
let dealiased = inner(engines, elem_clone.type_id, visited);
854+
elem_clone.type_id = dealiased;
855+
elem_clone.initial_type_id = dealiased;
856+
type_engine.insert_ptr(engines, elem_clone)
857+
}
858+
TypeInfo::Ref {
859+
to_mutable_value,
860+
referenced_type,
861+
} => {
862+
let mut referenced_clone = referenced_type.clone();
863+
let dealiased = inner(engines, referenced_clone.type_id, visited);
864+
referenced_clone.type_id = dealiased;
865+
referenced_clone.initial_type_id = dealiased;
866+
type_engine.insert_ref(engines, *to_mutable_value, referenced_clone)
867+
}
868+
_ => type_id,
869+
}
870+
}
871+
872+
inner(engines, type_id, &mut HashSet::new())
873+
}
874+
754875
fn generate_logged_types(
755876
handler: &Handler,
756877
ctx: &mut AbiContext,
@@ -1294,16 +1415,20 @@ impl TypeId {
12941415
}
12951416
}
12961417
TypeInfo::Alias { .. } => {
1297-
if let TypeInfo::Alias { ty, .. } = &*type_engine.get(resolved_type_id) {
1298-
ty.initial_type_id.get_abi_type_components(
1299-
handler,
1300-
ctx,
1301-
engines,
1302-
metadata_types,
1303-
concrete_types,
1304-
ty.type_id,
1305-
metadata_types_to_add,
1306-
)?
1418+
if ctx.experimental.abi_type_aliases {
1419+
if let TypeInfo::Alias { ty, .. } = &*type_engine.get(resolved_type_id) {
1420+
ty.initial_type_id.get_abi_type_components(
1421+
handler,
1422+
ctx,
1423+
engines,
1424+
metadata_types,
1425+
concrete_types,
1426+
ty.type_id,
1427+
metadata_types_to_add,
1428+
)?
1429+
} else {
1430+
None
1431+
}
13071432
} else {
13081433
None
13091434
}
@@ -1680,7 +1805,11 @@ impl GenericTypeParameter {
16801805
concrete_types: &mut Vec<program_abi::TypeConcreteDeclaration>,
16811806
metadata_types_to_add: &mut Vec<program_abi::TypeMetadataDeclaration>,
16821807
) -> Result<MetadataTypeId, ErrorEmitted> {
1683-
let cache_key = TypeCacheKey::from_type_id(engines, self.initial_type_id);
1808+
let cache_key = TypeCacheKey::from_type_id(
1809+
engines,
1810+
ctx.experimental.abi_type_aliases,
1811+
self.initial_type_id,
1812+
);
16841813
if ctx.type_cache_enabled {
16851814
if let Some(cached) = ctx.metadata_declaration_cache.get(&cache_key) {
16861815
return Ok(cached.metadata_type_id.clone());

sway-core/src/type_system/id.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,13 @@ impl TypeId {
295295
..
296296
},
297297
TypeInfo::Alias { name, .. },
298-
) => call_path.call_path.suffix != name.clone(),
298+
) => {
299+
if abi_type_aliases_enabled {
300+
false
301+
} else {
302+
call_path.call_path.suffix != name.clone()
303+
}
304+
}
299305
(TypeInfo::Custom { .. }, _) => true,
300306
_ => false,
301307
}

test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/abi_with_alias/json_abi_oracle_new_encoding.debug.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
"concreteTypeId": "41bd1a98f0a59642d8f824c805b798a5f268d1f7d05808eb05c4189c493f1be0",
99
"metadataTypeId": 0,
1010
"type": "(u64, u64)"
11+
},
12+
{
13+
"concreteTypeId": "0c549b98c3db49207607c6f5f063b081b1a724bc479a2a1b353ff2c60f3f1d49",
14+
"type": "AliasedTuple"
1115
}
1216
],
1317
"configurables": [],
@@ -18,7 +22,7 @@
1822
"attributes": null,
1923
"inputs": [
2024
{
21-
"concreteTypeId": "41bd1a98f0a59642d8f824c805b798a5f268d1f7d05808eb05c4189c493f1be0",
25+
"concreteTypeId": "0c549b98c3db49207607c6f5f063b081b1a724bc479a2a1b353ff2c60f3f1d49",
2226
"name": "arg1"
2327
}
2428
],
@@ -52,7 +56,7 @@
5256
}
5357
],
5458
"metadataTypeId": 0,
55-
"type": "(_, _)"
59+
"type": "(u64, u64)"
5660
},
5761
{
5862
"metadataTypeId": 1,

test/src/e2e_vm_tests/test_programs/should_pass/test_contracts/abi_with_alias/json_abi_oracle_new_encoding.release.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
"concreteTypeId": "41bd1a98f0a59642d8f824c805b798a5f268d1f7d05808eb05c4189c493f1be0",
99
"metadataTypeId": 0,
1010
"type": "(u64, u64)"
11+
},
12+
{
13+
"concreteTypeId": "0c549b98c3db49207607c6f5f063b081b1a724bc479a2a1b353ff2c60f3f1d49",
14+
"type": "AliasedTuple"
1115
}
1216
],
1317
"configurables": [],
@@ -18,7 +22,7 @@
1822
"attributes": null,
1923
"inputs": [
2024
{
21-
"concreteTypeId": "41bd1a98f0a59642d8f824c805b798a5f268d1f7d05808eb05c4189c493f1be0",
25+
"concreteTypeId": "0c549b98c3db49207607c6f5f063b081b1a724bc479a2a1b353ff2c60f3f1d49",
2226
"name": "arg1"
2327
}
2428
],
@@ -52,7 +56,7 @@
5256
}
5357
],
5458
"metadataTypeId": 0,
55-
"type": "(_, _)"
59+
"type": "(u64, u64)"
5660
},
5761
{
5862
"metadataTypeId": 1,
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[[package]]
2+
name = "abi_with_alias_experimental"
3+
source = "member"
4+
dependencies = ["std"]
5+
6+
[[package]]
7+
name = "std"
8+
source = "path+from-root-95C0899893008D15"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[project]
2+
authors = ["Fuel Labs <[email protected]>"]
3+
entry = "main.sw"
4+
implicit-std = false
5+
license = "Apache-2.0"
6+
name = "abi_with_alias_experimental"
7+
8+
[dependencies]
9+
std = { path = "../../../../reduced_std_libs/sway-lib-std-core" }

0 commit comments

Comments
 (0)