Skip to content

Commit 5667de6

Browse files
xunilrjzees-dev
authored andcommitted
AbiDecode for arrays using const_generics (#7008)
## Description This is part of #6860. This completes abi encoding for arrays. Allowing arrays of any size as inputs and outputs in predicates/scripts/contracts. This PR also allows arrays to be initialized with "const generics" such as: ```sway #[cfg(experimental_const_generics = true)] impl<T, const N: u64> AbiDecode for [T; N] where T: AbiDecode, { fn abi_decode(ref mut buffer: BufferReader) -> [T; N] { let first: T = buffer.decode::<T>(); let mut array = [first; N]; // <-------------------- This can used now ... array } } ```` ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [ ] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers.
1 parent f296a69 commit 5667de6

File tree

12 files changed

+150
-38
lines changed

12 files changed

+150
-38
lines changed

sway-core/src/ir_generation/const_eval.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,9 @@ fn const_eval_typed_expr(
308308
}
309309

310310
Ok(match &expr.expression {
311-
ty::TyExpressionVariant::ConstGenericExpression { .. } => {
312-
todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
311+
ty::TyExpressionVariant::ConstGenericExpression { decl, .. } => {
312+
assert!(decl.value.is_some());
313+
const_eval_typed_expr(lookup, known_consts, decl.value.as_ref().unwrap())?
313314
}
314315
ty::TyExpressionVariant::Literal(Literal::Numeric(n)) => {
315316
let implied_lit = match &*lookup.engines.te().get(expr.return_type) {

sway-core/src/ir_generation/function.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3679,8 +3679,8 @@ impl<'eng> FnCompiler<'eng> {
36793679
context: &mut Context,
36803680
md_mgr: &mut MetadataManager,
36813681
elem_type: TypeId,
3682-
value: &ty::TyExpression,
3683-
length: &ty::TyExpression,
3682+
value_expr: &ty::TyExpression,
3683+
length_expr: &ty::TyExpression,
36843684
span_md_idx: Option<MetadataIndex>,
36853685
) -> Result<TerminatorValue, CompileError> {
36863686
let elem_type = convert_resolved_typeid_no_span(
@@ -3690,7 +3690,17 @@ impl<'eng> FnCompiler<'eng> {
36903690
elem_type,
36913691
)?;
36923692

3693-
let length_as_u64 = length.as_literal_u64().unwrap();
3693+
let length_as_u64 = compile_constant_expression_to_constant(
3694+
self.engines,
3695+
context,
3696+
md_mgr,
3697+
self.module,
3698+
None,
3699+
Some(self),
3700+
length_expr,
3701+
)?;
3702+
// SAFETY: Safe by the type-checking, that only allows u64 as the array length
3703+
let length_as_u64 = length_as_u64.get_content(context).as_uint().unwrap();
36943704
let array_type = Type::new_array(context, elem_type, length_as_u64);
36953705

36963706
let temp_name = self.lexical_map.insert_anon();
@@ -3705,7 +3715,7 @@ impl<'eng> FnCompiler<'eng> {
37053715
.add_metadatum(context, span_md_idx);
37063716

37073717
let value_value = return_on_termination_or_extract!(
3708-
self.compile_expression_to_value(context, md_mgr, value)?
3718+
self.compile_expression_to_value(context, md_mgr, value_expr)?
37093719
);
37103720

37113721
if length_as_u64 > 5 {

sway-core/src/language/ty/ast_node.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,14 @@ impl MaterializeConstGenerics for TyAstNode {
147147
name: &str,
148148
value: &TyExpression,
149149
) -> Result<(), ErrorEmitted> {
150-
match self.content {
151-
TyAstNodeContent::Declaration(_) => Ok(()),
152-
TyAstNodeContent::Expression(ref mut expr) => {
150+
match &mut self.content {
151+
TyAstNodeContent::Declaration(TyDecl::VariableDecl(decl)) => decl
152+
.body
153+
.materialize_const_generics(engines, handler, name, value),
154+
TyAstNodeContent::Expression(expr) => {
153155
expr.materialize_const_generics(engines, handler, name, value)
154156
}
155-
TyAstNodeContent::SideEffect(_) => Ok(()),
156-
TyAstNodeContent::Error(_, _) => Ok(()),
157+
_ => Ok(()),
157158
}
158159
}
159160
}

sway-core/src/language/ty/declaration/const_generic.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
use crate::{
2-
//decl_engine::MaterializeConstGenerics,
32
decl_engine::MaterializeConstGenerics,
43
language::{parsed::ConstGenericDeclaration, ty::TyExpression, CallPath},
54
semantic_analysis::{TypeCheckAnalysis, TypeCheckAnalysisContext},
6-
SubstTypes,
7-
TypeId,
5+
SubstTypes, TypeId,
86
};
97
use serde::{Deserialize, Serialize};
108
use sway_error::handler::{ErrorEmitted, Handler};

sway-core/src/language/ty/declaration/function.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,9 @@ impl MaterializeConstGenerics for TyFunctionDecl {
150150
.type_id
151151
.materialize_const_generics(engines, handler, name, value)?;
152152
}
153-
153+
self.return_type
154+
.type_id
155+
.materialize_const_generics(engines, handler, name, value)?;
154156
self.body
155157
.materialize_const_generics(engines, handler, name, value)
156158
}

sway-core/src/language/ty/expression/expression.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,18 @@ impl MaterializeConstGenerics for TyExpression {
416416
TyExpressionVariant::Literal(_) | TyExpressionVariant::VariableExpression { .. } => {
417417
Ok(())
418418
}
419+
TyExpressionVariant::ArrayRepeat {
420+
elem_type,
421+
value: elem_value,
422+
length,
423+
} => {
424+
elem_type.materialize_const_generics(engines, handler, name, value)?;
425+
elem_value.materialize_const_generics(engines, handler, name, value)?;
426+
length.materialize_const_generics(engines, handler, name, value)
427+
}
428+
TyExpressionVariant::Ref(r) => {
429+
r.materialize_const_generics(engines, handler, name, value)
430+
}
419431
_ => Err(handler.emit_err(
420432
sway_error::error::CompileError::ConstGenericNotSupportedHere {
421433
span: self.span.clone(),
@@ -730,13 +742,6 @@ impl TyExpression {
730742
}
731743
}
732744

733-
pub(crate) fn as_literal_u64(&self) -> Option<u64> {
734-
match &self.expression {
735-
TyExpressionVariant::Literal(Literal::U64(v)) => Some(*v),
736-
_ => None,
737-
}
738-
}
739-
740745
pub fn as_intrinsic(&self) -> Option<&TyIntrinsicFunctionKind> {
741746
match &self.expression {
742747
TyExpressionVariant::IntrinsicFunction(v) => Some(v),

sway-core/src/language/ty/expression/expression_variant.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub enum TyExpressionVariant {
5252
ConstGenericExpression {
5353
span: Span,
5454
decl: Box<TyConstGenericDecl>,
55-
call_path: Option<CallPath>,
55+
call_path: CallPath,
5656
},
5757
VariableExpression {
5858
name: Ident,

sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -703,11 +703,11 @@ impl ty::TyExpression {
703703
expression: ty::TyExpressionVariant::ConstGenericExpression {
704704
decl: Box::new(decl),
705705
span: name.span(),
706-
call_path: Some(CallPath {
706+
call_path: CallPath {
707707
prefixes: vec![],
708708
suffix: name.clone(),
709709
callpath_type: CallPathType::Ambiguous,
710-
}),
710+
},
711711
},
712712
span,
713713
}
@@ -2046,6 +2046,12 @@ impl ty::TyExpression {
20462046
_ => TypeInfo::Unknown,
20472047
};
20482048
let elem_type = type_engine.insert(engines, elem_type, None);
2049+
let elem_type_arg = TypeArgument {
2050+
type_id: elem_type,
2051+
initial_type_id: elem_type,
2052+
span: span.clone(),
2053+
call_path_tree: None,
2054+
};
20492055

20502056
let value_ctx = ctx
20512057
.by_ref()
@@ -2058,17 +2064,27 @@ impl ty::TyExpression {
20582064
.by_ref()
20592065
.with_help_text("")
20602066
.with_type_annotation(type_engine.id_of_u64());
2061-
let length = Self::type_check(handler, length_ctx, length)
2067+
let length_expr = Self::type_check(handler, length_ctx, length)
20622068
.unwrap_or_else(|err| ty::TyExpression::error(err, span.clone(), engines));
2063-
let length_u64 = length.as_literal_u64().unwrap() as usize;
2069+
let length = match &length_expr.expression {
2070+
TyExpressionVariant::Literal(Literal::U64(val)) => Length::Literal {
2071+
val: *val as usize,
2072+
span: span.clone(),
2073+
},
2074+
TyExpressionVariant::ConstGenericExpression { call_path, .. } => {
2075+
Length::AmbiguousVariableExpression {
2076+
ident: call_path.suffix.clone(),
2077+
}
2078+
}
2079+
_ => return Err(handler.emit_err(CompileError::ConstGenericNotSupportedHere { span })),
2080+
};
20642081

2065-
let return_type =
2066-
type_engine.insert_array_without_annotations(engines, elem_type, length_u64);
2082+
let return_type = type_engine.insert_array(engines, elem_type_arg, length);
20672083
Ok(ty::TyExpression {
20682084
expression: ty::TyExpressionVariant::ArrayRepeat {
20692085
elem_type,
20702086
value: Box::new(value),
2071-
length: Box::new(length),
2087+
length: Box::new(length_expr),
20722088
},
20732089
return_type,
20742090
span,

sway-lib-std/generate.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ remove_generated_code "ARRAY_DECODE"
2121
START=1
2222
END=64
2323
for ((i=END;i>=START;i--)); do
24-
CODE="impl<T> AbiDecode for [T; $i] where T: AbiDecode { fn abi_decode(ref mut buffer: BufferReader) -> [T; $i] { let first: T = buffer.decode::<T>(); let mut array = [first; $i]; let mut i = 1; while i < $i { array[i] = buffer.decode::<T>(); i += 1; }; array } }"
24+
CODE="#[cfg(experimental_const_generics = false)]\nimpl<T> AbiDecode for [T; $i] where T: AbiDecode { fn abi_decode(ref mut buffer: BufferReader) -> [T; $i] { let first: T = buffer.decode::<T>(); let mut array = [first; $i]; let mut i = 1; while i < $i { array[i] = buffer.decode::<T>(); i += 1; }; array } }"
2525
sed -i "s/\/\/ BEGIN ARRAY_DECODE/\/\/ BEGIN ARRAY_DECODE\n$CODE/g" ./src/codec.sw
2626
done
2727

0 commit comments

Comments
 (0)