Skip to content

Commit dc81a40

Browse files
xunilrjJoshuaBattyironcev
authored
Forbid types with const generics on configurables (#7494)
## Description This PR is continuation of #7483. ## 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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Blocks types with const generics in configurables and ABI method args/returns via new `TypeId::has_const_generics`, and adds tests to enforce errors. > > - **Type system**: > - Add `TypeId::has_const_generics(engines)` to detect const generics in nested types (`sway-core/src/type_system/id.rs`). > - **Compiler/semantics**: > - Enforce no const generics in configurables via `TyConfigurableDecl::forbid_const_generics()` and invoke during type check (`semantic_analysis/.../configurable.rs`, `.../declaration.rs`). > - Enforce no const generics in ABI method parameters/returns using `TypeId::has_const_generics` and remove ad-hoc checker (`language/ty/declaration/abi.rs`). > - **Tests**: > - Extend `should_fail/unsupported_const_generics` to cover configurables and ABI cases; update snapshot (`test/.../stdout.snap`). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit eb61590. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Joshua Batty <joshpbatty@gmail.com> Co-authored-by: Igor Rončević <ironcev@hotmail.com>
1 parent 8103f0d commit dc81a40

File tree

6 files changed

+180
-144
lines changed

6 files changed

+180
-144
lines changed

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

Lines changed: 4 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use super::{TyDeclParsedType, TyTraitInterfaceItem, TyTraitItem};
22
use crate::{
3-
ast_elements::type_parameter::ConstGenericExpr,
43
decl_engine::DeclEngineGet as _,
54
engine_threading::*,
65
language::parsed::{self, AbiDeclaration},
@@ -29,70 +28,6 @@ pub struct TyAbiDecl {
2928
pub attributes: transform::Attributes,
3029
}
3130

32-
fn has_const_generics(type_id: TypeId, engines: &Engines) -> bool {
33-
let types = type_id.extract_any_including_self(engines, &|_| true, vec![], 0);
34-
35-
for (t, _) in types {
36-
let t = engines.te().get(t);
37-
match &*t {
38-
TypeInfo::StringArray(length) => match length.expr() {
39-
ConstGenericExpr::Literal { .. } => {}
40-
ConstGenericExpr::AmbiguousVariableExpression { .. } => return true,
41-
},
42-
TypeInfo::Enum(decl_id) => {
43-
let decl = engines.de().get(decl_id);
44-
let any_const_generics = decl
45-
.generic_parameters
46-
.iter()
47-
.any(|x| x.as_const_parameter().is_some());
48-
if any_const_generics {
49-
return true;
50-
}
51-
}
52-
TypeInfo::Struct(decl_id) => {
53-
let decl = engines.de().get(decl_id);
54-
let any_const_generics = decl
55-
.generic_parameters
56-
.iter()
57-
.any(|x| x.as_const_parameter().is_some());
58-
if any_const_generics {
59-
return true;
60-
}
61-
62-
for field in decl.fields.iter() {
63-
let any_const_generics =
64-
has_const_generics(field.type_argument.type_id, engines);
65-
if any_const_generics {
66-
return true;
67-
}
68-
}
69-
}
70-
TypeInfo::Tuple(items) => {
71-
for item in items {
72-
let any_const_generics = has_const_generics(item.type_id, engines);
73-
if any_const_generics {
74-
return true;
75-
}
76-
}
77-
}
78-
TypeInfo::Array(item, length) => {
79-
let any_const_generics = has_const_generics(item.type_id, engines);
80-
if any_const_generics {
81-
return true;
82-
}
83-
84-
match length.expr() {
85-
ConstGenericExpr::Literal { .. } => {}
86-
ConstGenericExpr::AmbiguousVariableExpression { .. } => return true,
87-
}
88-
}
89-
_ => {}
90-
}
91-
}
92-
93-
false
94-
}
95-
9631
impl TyAbiDecl {
9732
pub(crate) fn forbid_const_generics(
9833
&self,
@@ -104,15 +39,15 @@ impl TyAbiDecl {
10439
TyTraitInterfaceItem::TraitFn(decl_ref) => {
10540
let decl = engines.de().get(decl_ref.id());
10641

107-
if has_const_generics(decl.return_type.type_id, engines) {
42+
if decl.return_type.type_id.has_const_generics(engines) {
10843
let err = handler.emit_err(CompileError::ConstGenericNotSupportedHere {
10944
span: decl.return_type.span(),
11045
});
11146
return Err(err);
11247
}
11348

11449
for arg in decl.parameters.iter() {
115-
if has_const_generics(arg.type_argument.type_id, engines) {
50+
if arg.type_argument.type_id.has_const_generics(engines) {
11651
let err =
11752
handler.emit_err(CompileError::ConstGenericNotSupportedHere {
11853
span: arg.type_argument.span.clone(),
@@ -130,15 +65,15 @@ impl TyAbiDecl {
13065
match item {
13166
TyTraitItem::Fn(decl_ref) => {
13267
let decl = engines.de().get(decl_ref.id());
133-
if has_const_generics(decl.return_type.type_id, engines) {
68+
if decl.return_type.type_id.has_const_generics(engines) {
13469
let err = handler.emit_err(CompileError::ConstGenericNotSupportedHere {
13570
span: decl.return_type.span(),
13671
});
13772
return Err(err);
13873
}
13974

14075
for arg in decl.parameters.iter() {
141-
if has_const_generics(arg.type_argument.type_id, engines) {
76+
if arg.type_argument.type_id.has_const_generics(engines) {
14277
let err =
14378
handler.emit_err(CompileError::ConstGenericNotSupportedHere {
14479
span: arg.type_argument.span.clone(),

sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,22 @@ impl ty::TyConfigurableDecl {
188188
visibility,
189189
})
190190
}
191+
192+
pub(crate) fn forbid_const_generics(
193+
&self,
194+
handler: &Handler,
195+
engines: &Engines,
196+
) -> Result<(), ErrorEmitted> {
197+
if self.type_ascription.type_id.has_const_generics(engines) {
198+
Err(
199+
handler.emit_err(CompileError::ConstGenericNotSupportedHere {
200+
span: self.type_ascription.span.clone(),
201+
}),
202+
)
203+
} else {
204+
Ok(())
205+
}
206+
}
191207
}
192208

193209
impl TypeCheckAnalysis for TyConfigurableDecl {

sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,10 @@ impl TyDecl {
120120
let name = decl.name.clone();
121121
let typed_const_decl =
122122
match ty::TyConfigurableDecl::type_check(handler, ctx.by_ref(), decl) {
123-
Ok(config_decl) => ty::TyDecl::from(
124-
decl_engine.insert(config_decl.clone(), Some(&decl_id)),
125-
),
123+
Ok(config_decl) => {
124+
config_decl.forbid_const_generics(handler, engines)?;
125+
ty::TyDecl::from(decl_engine.insert(config_decl, Some(&decl_id)))
126+
}
126127
Err(err) => ty::TyDecl::ErrorRecovery(span, err),
127128
};
128129
ctx.insert_symbol(handler, name, typed_const_decl.clone())?;

sway-core/src/type_system/id.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1484,4 +1484,68 @@ impl TypeId {
14841484
pub fn get_type_str(&self, engines: &Engines) -> String {
14851485
engines.te().get(*self).get_type_str(engines)
14861486
}
1487+
1488+
pub fn has_const_generics(&self, engines: &Engines) -> bool {
1489+
let types = self.extract_any_including_self(engines, &|_| true, vec![], 0);
1490+
1491+
for (t, _) in types {
1492+
let t = engines.te().get(t);
1493+
match &*t {
1494+
TypeInfo::StringArray(length) => match length.expr() {
1495+
ConstGenericExpr::Literal { .. } => {}
1496+
ConstGenericExpr::AmbiguousVariableExpression { .. } => return true,
1497+
},
1498+
TypeInfo::Enum(decl_id) => {
1499+
let decl = engines.de().get(decl_id);
1500+
let any_const_generics = decl
1501+
.generic_parameters
1502+
.iter()
1503+
.any(|x| x.as_const_parameter().is_some());
1504+
if any_const_generics {
1505+
return true;
1506+
}
1507+
}
1508+
TypeInfo::Struct(decl_id) => {
1509+
let decl = engines.de().get(decl_id);
1510+
let any_const_generics = decl
1511+
.generic_parameters
1512+
.iter()
1513+
.any(|x| x.as_const_parameter().is_some());
1514+
if any_const_generics {
1515+
return true;
1516+
}
1517+
1518+
for field in decl.fields.iter() {
1519+
let any_const_generics =
1520+
field.type_argument.type_id.has_const_generics(engines);
1521+
if any_const_generics {
1522+
return true;
1523+
}
1524+
}
1525+
}
1526+
TypeInfo::Tuple(items) => {
1527+
for item in items {
1528+
let any_const_generics = item.type_id.has_const_generics(engines);
1529+
if any_const_generics {
1530+
return true;
1531+
}
1532+
}
1533+
}
1534+
TypeInfo::Array(item, length) => {
1535+
let any_const_generics = item.type_id.has_const_generics(engines);
1536+
if any_const_generics {
1537+
return true;
1538+
}
1539+
1540+
match length.expr() {
1541+
ConstGenericExpr::Literal { .. } => {}
1542+
ConstGenericExpr::AmbiguousVariableExpression { .. } => return true,
1543+
}
1544+
}
1545+
_ => {}
1546+
}
1547+
}
1548+
1549+
false
1550+
}
14871551
}

test/src/e2e_vm_tests/test_programs/should_fail/unsupported_const_generics/src/main.sw

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ impl<const N: u64> A for CrazyEnum<N> {
4242
}
4343
}
4444

45+
// abi cannot have const generics
46+
4547
abi NoConstGenericsOnArgs {
4648
fn f(a: CrazyStruct<1>);
4749
}
@@ -66,6 +68,12 @@ abi NoConstGenericsIndirectEnum {
6668
fn f() -> EnumWithConstGenericInside;
6769
}
6870

71+
// configurable cannot have const generics
72+
73+
configurable {
74+
A: CrazyStruct<1> = CrazyStruct { },
75+
}
76+
6977
fn main() {
7078
let _: CrazyStruct<UNKNOWN> = CrazyStruct { };
7179
let _: CrazyEnum<UNKNOWN> = CrazyEnum::A;

0 commit comments

Comments
 (0)