Skip to content

Commit 13542d2

Browse files
authored
impl trait for "const generics" (#6946)
## Description This PR is part of #6860. It implements "impl traits" for "const generics", which means syntax such as: ```sway trait A { fn my_len(self) -> u64; } impl<T, const N: u64> A for [T; N] { fn my_len(self) -> u64 { N } } ``` This also opens the space for simplifying our current implementation of `AbiEncode` for arrays. Today we implement for each size, which limits us to a specific size. With this one can have just one "impl item", and support arrays of arbitrary size. Both implementations will coexist in `codec.sw` until we stabilize "const generics". ```sway #[cfg(experimental_const_generics = true)] impl<T, const N: u64> AbiEncode for [T; N] where T: AbiEncode, { fn abi_encode(self, buffer: Buffer) -> Buffer { .... } } #[cfg(experimental_const_generics = false)] impl<T> AbiEncode for [T; 0] where T: AbiEncode, { fn abi_encode(self, buffer: Buffer) -> Buffer { ... } } ``` ## 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 8a3d8df commit 13542d2

Some content is hidden

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

64 files changed

+1125
-159
lines changed

sway-core/src/control_flow_analysis/analyze_return_paths.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ fn connect_declaration<'eng: 'cfg, 'cfg>(
218218
}
219219
Ok(Some(entry_node))
220220
}
221+
ty::TyDecl::ConstGenericDecl(_) => {
222+
todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
223+
}
221224
ty::TyDecl::FunctionDecl(ty::FunctionDecl { decl_id, .. }) => {
222225
let fn_decl = decl_engine.get_function(decl_id);
223226
let entry_node = graph.add_node(ControlFlowGraphNode::from_node(node));

sway-core/src/control_flow_analysis/dead_code_analysis.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,9 @@ fn connect_declaration<'eng: 'cfg, 'cfg>(
603603
Ok(leaves.to_vec())
604604
}
605605
}
606+
ty::TyDecl::ConstGenericDecl(_) => {
607+
todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860");
608+
}
606609
ty::TyDecl::FunctionDecl(ty::FunctionDecl { decl_id, .. }) => {
607610
let fn_decl = decl_engine.get_function(decl_id);
608611
connect_typed_fn_decl(
@@ -1514,6 +1517,17 @@ fn connect_expression<'eng: 'cfg, 'cfg>(
15141517

15151518
Ok(vec![node])
15161519
}
1520+
ConstGenericExpression { decl, .. } => {
1521+
let Some(node) = graph.namespace.get_const_generic(decl).cloned() else {
1522+
return Ok(leaves.to_vec());
1523+
};
1524+
1525+
for leaf in leaves {
1526+
graph.add_edge(*leaf, node, "".into());
1527+
}
1528+
1529+
Ok(vec![node])
1530+
}
15171531
EnumInstantiation {
15181532
enum_ref,
15191533
variant_name,
@@ -2552,6 +2566,9 @@ fn allow_dead_code_ast_node(decl_engine: &DeclEngine, node: &ty::TyAstNode) -> b
25522566
ty::TyDecl::ConfigurableDecl(ty::ConfigurableDecl { decl_id, .. }) => {
25532567
allow_dead_code(decl_engine.get_configurable(decl_id).attributes.clone())
25542568
}
2569+
ty::TyDecl::ConstGenericDecl(_) => {
2570+
todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
2571+
}
25552572
ty::TyDecl::TraitTypeDecl(ty::TraitTypeDecl { decl_id, .. }) => {
25562573
allow_dead_code(decl_engine.get_type(decl_id).attributes.clone())
25572574
}

sway-core/src/control_flow_analysis/flow_graph/namespace.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ use super::{EntryPoint, ExitPoint};
22
use crate::{
33
language::{
44
parsed::TreeType,
5-
ty::{self, TyConfigurableDecl, TyConstantDecl, TyFunctionDecl, TyFunctionSig},
5+
ty::{
6+
self, TyConfigurableDecl, TyConstGenericDecl, TyConstantDecl, TyFunctionDecl,
7+
TyFunctionSig,
8+
},
69
CallPath,
710
},
811
type_system::TypeInfo,
@@ -58,6 +61,7 @@ pub struct ControlFlowNamespace {
5861
pub(crate) struct_namespace: HashMap<String, StructNamespaceEntry>,
5962
pub(crate) const_namespace: HashMap<Ident, NodeIndex>,
6063
pub(crate) configurable_namespace: HashMap<Ident, NodeIndex>,
64+
pub(crate) const_generic_namespace: HashMap<Ident, NodeIndex>,
6165
pub(crate) storage: HashMap<Ident, NodeIndex>,
6266
pub(crate) code_blocks: Vec<ControlFlowCodeBlock>,
6367
pub(crate) alias: HashMap<IdentUnique, NodeIndex>,
@@ -93,6 +97,10 @@ impl ControlFlowNamespace {
9397
self.configurable_namespace.get(&decl.name().clone())
9498
}
9599

100+
pub(crate) fn get_const_generic(&self, decl: &TyConstGenericDecl) -> Option<&NodeIndex> {
101+
self.const_generic_namespace.get(&decl.name().clone())
102+
}
103+
96104
#[allow(dead_code)]
97105
pub(crate) fn insert_constant(
98106
&mut self,

sway-core/src/decl_engine/engine.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ use crate::{
1313
engine_threading::*,
1414
language::{
1515
parsed::{
16-
AbiDeclaration, ConfigurableDeclaration, ConstantDeclaration, Declaration,
17-
EnumDeclaration, FunctionDeclaration, ImplSelfOrTrait, StorageDeclaration,
16+
AbiDeclaration, ConfigurableDeclaration, ConstGenericDeclaration, ConstantDeclaration,
17+
Declaration, EnumDeclaration, FunctionDeclaration, ImplSelfOrTrait, StorageDeclaration,
1818
StructDeclaration, TraitDeclaration, TraitFn, TraitTypeDeclaration,
1919
TypeAliasDeclaration,
2020
},
2121
ty::{
22-
self, TyAbiDecl, TyConfigurableDecl, TyConstantDecl, TyDeclParsedType, TyEnumDecl,
23-
TyFunctionDecl, TyImplSelfOrTrait, TyStorageDecl, TyStructDecl, TyTraitDecl, TyTraitFn,
24-
TyTraitType, TyTypeAliasDecl,
22+
self, TyAbiDecl, TyConfigurableDecl, TyConstGenericDecl, TyConstantDecl,
23+
TyDeclParsedType, TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait, TyStorageDecl,
24+
TyStructDecl, TyTraitDecl, TyTraitFn, TyTraitType, TyTypeAliasDecl,
2525
},
2626
},
2727
};
@@ -39,6 +39,7 @@ pub struct DeclEngine {
3939
abi_slab: ConcurrentSlab<TyAbiDecl>,
4040
constant_slab: ConcurrentSlab<TyConstantDecl>,
4141
configurable_slab: ConcurrentSlab<TyConfigurableDecl>,
42+
const_generics_slab: ConcurrentSlab<TyConstGenericDecl>,
4243
enum_slab: ConcurrentSlab<TyEnumDecl>,
4344
type_alias_slab: ConcurrentSlab<TyTypeAliasDecl>,
4445

@@ -59,6 +60,8 @@ pub struct DeclEngine {
5960
RwLock<HashMap<DeclId<TyConstantDecl>, ParsedDeclId<ConstantDeclaration>>>,
6061
configurable_parsed_decl_id_map:
6162
RwLock<HashMap<DeclId<TyConfigurableDecl>, ParsedDeclId<ConfigurableDeclaration>>>,
63+
const_generics_parsed_decl_id_map:
64+
RwLock<HashMap<DeclId<TyConstGenericDecl>, ParsedDeclId<ConstGenericDeclaration>>>,
6265
enum_parsed_decl_id_map: RwLock<HashMap<DeclId<TyEnumDecl>, ParsedDeclId<EnumDeclaration>>>,
6366
type_alias_parsed_decl_id_map:
6467
RwLock<HashMap<DeclId<TyTypeAliasDecl>, ParsedDeclId<TypeAliasDeclaration>>>,
@@ -79,6 +82,7 @@ impl Clone for DeclEngine {
7982
abi_slab: self.abi_slab.clone(),
8083
constant_slab: self.constant_slab.clone(),
8184
configurable_slab: self.configurable_slab.clone(),
85+
const_generics_slab: self.const_generics_slab.clone(),
8286
enum_slab: self.enum_slab.clone(),
8387
type_alias_slab: self.type_alias_slab.clone(),
8488
function_parsed_decl_id_map: RwLock::new(
@@ -103,6 +107,9 @@ impl Clone for DeclEngine {
103107
configurable_parsed_decl_id_map: RwLock::new(
104108
self.configurable_parsed_decl_id_map.read().clone(),
105109
),
110+
const_generics_parsed_decl_id_map: RwLock::new(
111+
self.const_generics_parsed_decl_id_map.read().clone(),
112+
),
106113
enum_parsed_decl_id_map: RwLock::new(self.enum_parsed_decl_id_map.read().clone()),
107114
type_alias_parsed_decl_id_map: RwLock::new(
108115
self.type_alias_parsed_decl_id_map.read().clone(),
@@ -187,6 +194,7 @@ decl_engine_get!(storage_slab, ty::TyStorageDecl);
187194
decl_engine_get!(abi_slab, ty::TyAbiDecl);
188195
decl_engine_get!(constant_slab, ty::TyConstantDecl);
189196
decl_engine_get!(configurable_slab, ty::TyConfigurableDecl);
197+
decl_engine_get!(const_generics_slab, ty::TyConstGenericDecl);
190198
decl_engine_get!(enum_slab, ty::TyEnumDecl);
191199
decl_engine_get!(type_alias_slab, ty::TyTypeAliasDecl);
192200

@@ -258,6 +266,11 @@ decl_engine_insert!(
258266
configurable_parsed_decl_id_map,
259267
ty::TyConfigurableDecl
260268
);
269+
decl_engine_insert!(
270+
const_generics_slab,
271+
const_generics_parsed_decl_id_map,
272+
ty::TyConstGenericDecl
273+
);
261274
decl_engine_insert!(enum_slab, enum_parsed_decl_id_map, ty::TyEnumDecl);
262275
decl_engine_insert!(
263276
type_alias_slab,
@@ -695,6 +708,18 @@ impl DeclEngine {
695708
self.get(index)
696709
}
697710

711+
/// Friendly helper method for calling the `get` method from the
712+
/// implementation of [DeclEngineGet] for [DeclEngine]
713+
///
714+
/// Calling [DeclEngine][get] directly is equivalent to this method, but
715+
/// this method adds additional syntax that some users may find helpful.
716+
pub fn get_const_generic<I>(&self, index: &I) -> Arc<ty::TyConstGenericDecl>
717+
where
718+
DeclEngine: DeclEngineGet<I, ty::TyConstGenericDecl>,
719+
{
720+
self.get(index)
721+
}
722+
698723
/// Friendly helper method for calling the `get` method from the
699724
/// implementation of [DeclEngineGet] for [DeclEngine]
700725
///

sway-core/src/decl_engine/parsed_engine.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,18 @@ impl ParsedDeclEngine {
362362
self.get(index)
363363
}
364364

365+
/// Friendly helper method for calling the `get` method from the
366+
/// implementation of [ParsedDeclEngineGet] for [ParsedDeclEngine]
367+
///
368+
/// Calling [ParsedDeclEngine][get] directly is equivalent to this method, but
369+
/// this method adds additional syntax that some users may find helpful.
370+
pub fn get_const_generic<I>(&self, index: &I) -> Arc<ConstGenericDeclaration>
371+
where
372+
ParsedDeclEngine: ParsedDeclEngineGet<I, ConstGenericDeclaration>,
373+
{
374+
self.get(index)
375+
}
376+
365377
/// Friendly helper method for calling the `get` method from the
366378
/// implementation of [ParsedDeclEngineGet] for [ParsedDeclEngine]
367379
///

sway-core/src/decl_engine/replace_decls.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use sway_error::handler::{ErrorEmitted, Handler};
22

33
use crate::{
44
engine_threading::Engines,
5-
language::ty::{self, TyDecl},
5+
language::ty::{self, TyDecl, TyExpression},
66
semantic_analysis::TypeCheckContext,
77
};
88

@@ -37,3 +37,15 @@ pub(crate) trait ReplaceFunctionImplementingType {
3737
pub(crate) trait UpdateConstantExpression {
3838
fn update_constant_expression(&mut self, engines: &Engines, implementing_type: &TyDecl);
3939
}
40+
41+
// Iterate the tree searching for references to a const generic,
42+
// and initialize its value with the passed value
43+
pub(crate) trait MaterializeConstGenerics {
44+
fn materialize_const_generics(
45+
&mut self,
46+
engines: &Engines,
47+
handler: &Handler,
48+
name: &str,
49+
value: &TyExpression,
50+
) -> Result<(), ErrorEmitted>;
51+
}

sway-core/src/ir_generation/const_eval.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ fn const_eval_typed_expr(
296296
}
297297

298298
Ok(match &expr.expression {
299+
ty::TyExpressionVariant::ConstGenericExpression { .. } => {
300+
todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
301+
}
299302
ty::TyExpressionVariant::Literal(Literal::Numeric(n)) => {
300303
let implied_lit = match &*lookup.engines.te().get(expr.return_type) {
301304
TypeInfo::UnsignedInteger(IntegerBits::Eight) => Literal::U8(*n as u8),

sway-core/src/ir_generation/function.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ impl<'eng> FnCompiler<'eng> {
260260
ty::TyDecl::ConfigurableDecl(ty::ConfigurableDecl { .. }) => {
261261
unreachable!()
262262
}
263+
ty::TyDecl::ConstGenericDecl(_) => {
264+
todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
265+
}
263266
ty::TyDecl::EnumDecl(ty::EnumDecl { decl_id, .. }) => {
264267
let ted = self.engines.de().get_enum(decl_id);
265268
create_tagged_union_type(
@@ -546,6 +549,10 @@ impl<'eng> FnCompiler<'eng> {
546549
ty::TyExpressionVariant::ConfigurableExpression {
547550
decl: const_decl, ..
548551
} => self.compile_config_expr(context, const_decl, span_md_idx),
552+
ty::TyExpressionVariant::ConstGenericExpression { decl, .. } => {
553+
let value = decl.value.as_ref().unwrap();
554+
self.compile_expression(context, md_mgr, value)
555+
}
549556
ty::TyExpressionVariant::VariableExpression {
550557
name, call_path, ..
551558
} => self.compile_var_expr(context, call_path, name, span_md_idx),

sway-core/src/language/parsed/declaration.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ pub enum Declaration {
6161
TypeAliasDeclaration(ParsedDeclId<TypeAliasDeclaration>),
6262
TraitTypeDeclaration(ParsedDeclId<TraitTypeDeclaration>),
6363
TraitFnDeclaration(ParsedDeclId<TraitFn>),
64+
ConstGenericDeclaration(ParsedDeclId<ConstGenericDeclaration>),
6465
}
6566

6667
#[derive(Debug, Clone)]
@@ -100,6 +101,7 @@ impl Declaration {
100101
AbiDeclaration(_) => "abi",
101102
StorageDeclaration(_) => "contract storage",
102103
TypeAliasDeclaration(_) => "type alias",
104+
ConstGenericDeclaration(_) => "const generic",
103105
}
104106
}
105107

@@ -121,6 +123,9 @@ impl Declaration {
121123
TypeAliasDeclaration(decl_id) => pe.get_type_alias(decl_id).span(),
122124
TraitTypeDeclaration(decl_id) => pe.get_trait_type(decl_id).span(),
123125
TraitFnDeclaration(decl_id) => pe.get_trait_fn(decl_id).span(),
126+
ConstGenericDeclaration(_) => {
127+
todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
128+
}
124129
}
125130
}
126131

@@ -195,6 +200,9 @@ impl Declaration {
195200
| Declaration::AbiDeclaration(_)
196201
| Declaration::TraitTypeDeclaration(_)
197202
| Declaration::TraitFnDeclaration(_) => Visibility::Public,
203+
Declaration::ConstGenericDeclaration(_) => {
204+
todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
205+
}
198206
}
199207
}
200208
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::{
2+
ast_elements::type_parameter::ConstGenericParameter,
23
engine_threading::*,
34
language::{parsed::*, *},
45
transform::{self, AttributeKind},
@@ -25,6 +26,7 @@ pub struct FunctionDeclaration {
2526
pub span: Span,
2627
pub return_type: TypeArgument,
2728
pub type_parameters: Vec<TypeParameter>,
29+
pub const_generic_parameters: Vec<ConstGenericParameter>,
2830
pub where_clause: Vec<(Ident, Vec<TraitConstraint>)>,
2931
pub kind: FunctionDeclarationKind,
3032
pub implementing_type: Option<Declaration>,

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,25 @@ impl GetDeclIdent for TyAstNode {
139139
}
140140
}
141141

142+
impl MaterializeConstGenerics for TyAstNode {
143+
fn materialize_const_generics(
144+
&mut self,
145+
engines: &Engines,
146+
handler: &Handler,
147+
name: &str,
148+
value: &TyExpression,
149+
) -> Result<(), ErrorEmitted> {
150+
match self.content {
151+
TyAstNodeContent::Declaration(_) => Ok(()),
152+
TyAstNodeContent::Expression(ref mut expr) => {
153+
expr.materialize_const_generics(engines, handler, name, value)
154+
}
155+
TyAstNodeContent::SideEffect(_) => Ok(()),
156+
TyAstNodeContent::Error(_, _) => Ok(()),
157+
}
158+
}
159+
}
160+
142161
impl TyAstNode {
143162
/// Returns `true` if this AST node will be exported in a library, i.e. it is a public declaration.
144163
pub(crate) fn is_public(&self, decl_engine: &DeclEngine) -> bool {
@@ -226,6 +245,9 @@ impl TyAstNode {
226245
value.check_deprecated(engines, handler, allow_deprecated);
227246
}
228247
}
248+
TyDecl::ConstGenericDecl(_) => {
249+
todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
250+
}
229251
TyDecl::TraitTypeDecl(_) => {}
230252
TyDecl::FunctionDecl(decl) => {
231253
let decl = engines.de().get(&decl.decl_id);
@@ -285,6 +307,9 @@ impl TyAstNode {
285307
TyDecl::VariableDecl(_decl) => {}
286308
TyDecl::ConstantDecl(_decl) => {}
287309
TyDecl::ConfigurableDecl(_decl) => {}
310+
TyDecl::ConstGenericDecl(_decl) => {
311+
todo!("Will be implemented by https://github.com/FuelLabs/sway/issues/6860")
312+
}
288313
TyDecl::TraitTypeDecl(_) => {}
289314
TyDecl::FunctionDecl(decl) => {
290315
let fn_decl_id = decl.decl_id;

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,17 @@ impl UpdateConstantExpression for TyCodeBlock {
8181
.for_each(|x| x.update_constant_expression(engines, implementing_type));
8282
}
8383
}
84+
85+
impl MaterializeConstGenerics for TyCodeBlock {
86+
fn materialize_const_generics(
87+
&mut self,
88+
engines: &Engines,
89+
handler: &Handler,
90+
name: &str,
91+
value: &TyExpression,
92+
) -> Result<(), ErrorEmitted> {
93+
self.contents
94+
.iter_mut()
95+
.try_for_each(|x| x.materialize_const_generics(engines, handler, name, value))
96+
}
97+
}

0 commit comments

Comments
 (0)