Skip to content

Commit fb10b2f

Browse files
authored
Forbid const generics on abis (#7483)
## Description This PR forbids "const generics" on `abi`s. The reason is that to correctly support it, we will need to introduce changes to the ABI json. This will be reserved to the future. ## Checklist - [ ] 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] > <sup>[Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) is generating a summary for commit 1bf3210. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 886becb commit fb10b2f

File tree

8 files changed

+328
-73
lines changed

8 files changed

+328
-73
lines changed

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

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
use super::{TyDeclParsedType, TyTraitInterfaceItem, TyTraitItem};
22
use crate::{
3+
ast_elements::type_parameter::ConstGenericExpr,
4+
decl_engine::DeclEngineGet as _,
35
engine_threading::*,
46
language::parsed::{self, AbiDeclaration},
57
transform,
68
type_system::*,
79
};
810
use serde::{Deserialize, Serialize};
911
use std::hash::{Hash, Hasher};
12+
use sway_error::{
13+
error::CompileError,
14+
handler::{ErrorEmitted, Handler},
15+
};
1016
use sway_types::{Ident, Named, Span, Spanned};
1117

1218
/// A [TyAbiDecl] contains the type-checked version of the parse tree's
@@ -23,6 +29,133 @@ pub struct TyAbiDecl {
2329
pub attributes: transform::Attributes,
2430
}
2531

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+
96+
impl TyAbiDecl {
97+
pub(crate) fn forbid_const_generics(
98+
&self,
99+
handler: &Handler,
100+
engines: &Engines,
101+
) -> Result<(), ErrorEmitted> {
102+
for item in self.interface_surface.iter() {
103+
match item {
104+
TyTraitInterfaceItem::TraitFn(decl_ref) => {
105+
let decl = engines.de().get(decl_ref.id());
106+
107+
if has_const_generics(decl.return_type.type_id, engines) {
108+
let err = handler.emit_err(CompileError::ConstGenericNotSupportedHere {
109+
span: decl.return_type.span(),
110+
});
111+
return Err(err);
112+
}
113+
114+
for arg in decl.parameters.iter() {
115+
if has_const_generics(arg.type_argument.type_id, engines) {
116+
let err =
117+
handler.emit_err(CompileError::ConstGenericNotSupportedHere {
118+
span: arg.type_argument.span.clone(),
119+
});
120+
return Err(err);
121+
}
122+
}
123+
}
124+
TyTraitInterfaceItem::Constant(_) => {}
125+
TyTraitInterfaceItem::Type(_) => {}
126+
}
127+
}
128+
129+
for item in self.items.iter() {
130+
match item {
131+
TyTraitItem::Fn(decl_ref) => {
132+
let decl = engines.de().get(decl_ref.id());
133+
if has_const_generics(decl.return_type.type_id, engines) {
134+
let err = handler.emit_err(CompileError::ConstGenericNotSupportedHere {
135+
span: decl.return_type.span(),
136+
});
137+
return Err(err);
138+
}
139+
140+
for arg in decl.parameters.iter() {
141+
if has_const_generics(arg.type_argument.type_id, engines) {
142+
let err =
143+
handler.emit_err(CompileError::ConstGenericNotSupportedHere {
144+
span: arg.type_argument.span.clone(),
145+
});
146+
return Err(err);
147+
}
148+
}
149+
}
150+
TyTraitItem::Constant(_) => {}
151+
TyTraitItem::Type(_) => {}
152+
}
153+
}
154+
155+
Ok(())
156+
}
157+
}
158+
26159
impl TyDeclParsedType for TyAbiDecl {
27160
type ParsedType = AbiDeclaration;
28161
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ impl ty::TyAbiDecl {
233233
span,
234234
attributes,
235235
};
236+
237+
abi_decl.forbid_const_generics(handler, engines)?;
238+
236239
Ok(abi_decl)
237240
})
238241
}

sway-core/src/type_system/substitute/subst_map.rs

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -198,18 +198,18 @@ impl TypeSubstMap {
198198
(TypeInfo::Enum(decl_ref_params), TypeInfo::Enum(decl_ref_args)) => {
199199
let decl_params = decl_engine.get_enum(decl_ref_params);
200200
let decl_args = decl_engine.get_enum(decl_ref_args);
201-
let type_parameters = decl_params.generic_parameters.iter().map(|x| {
202-
let x = x
203-
.as_type_parameter()
204-
.expect("will only work with type parameters");
205-
x.type_id
206-
});
207-
let type_arguments = decl_args.generic_parameters.iter().map(|x| {
208-
let x = x
209-
.as_type_parameter()
210-
.expect("will only work with type parameters");
211-
x.type_id
212-
});
201+
202+
let type_parameters = decl_params
203+
.generic_parameters
204+
.iter()
205+
.filter_map(|x| x.as_type_parameter())
206+
.map(|x| x.type_id);
207+
let type_arguments = decl_args
208+
.generic_parameters
209+
.iter()
210+
.filter_map(|x| x.as_type_parameter())
211+
.map(|x| x.type_id);
212+
213213
TypeSubstMap::from_superset_and_subset_helper(
214214
engines,
215215
type_parameters,
@@ -220,18 +220,17 @@ impl TypeSubstMap {
220220
let decl_params = decl_engine.get_struct(decl_ref_params);
221221
let decl_args = decl_engine.get_struct(decl_ref_args);
222222

223-
let type_parameters = decl_params.generic_parameters.iter().map(|x| {
224-
let x = x
225-
.as_type_parameter()
226-
.expect("only works with type parameters");
227-
x.type_id
228-
});
229-
let type_arguments = decl_args.generic_parameters.iter().map(|x| {
230-
let x = x
231-
.as_type_parameter()
232-
.expect("only works with type parameters");
233-
x.type_id
234-
});
223+
let type_parameters = decl_params
224+
.generic_parameters
225+
.iter()
226+
.filter_map(|x| x.as_type_parameter())
227+
.map(|x| x.type_id);
228+
let type_arguments = decl_args
229+
.generic_parameters
230+
.iter()
231+
.filter_map(|x| x.as_type_parameter())
232+
.map(|x| x.type_id);
233+
235234
TypeSubstMap::from_superset_and_subset_helper(
236235
engines,
237236
type_parameters,
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[[package]]
2-
name = "const_generics"
3-
source = "member"
4-
dependencies = ["std"]
2+
name = "std"
3+
source = "path+from-root-73072EFA61E741F9"
54

65
[[package]]
7-
name = "std"
8-
source = "path+from-root-04B19932ACF7269D"
6+
name = "unsupported_const_generics"
7+
source = "member"
8+
dependencies = ["std"]

test/src/e2e_vm_tests/test_programs/should_fail/const_generics/Forc.toml renamed to test/src/e2e_vm_tests/test_programs/should_fail/unsupported_const_generics/Forc.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
authors = ["Fuel Labs <[email protected]>"]
33
entry = "main.sw"
44
license = "Apache-2.0"
5-
name = "const_generics"
5+
name = "unsupported_const_generics"
66

77
[dependencies]
88
std = { path = "../../../../../../sway-lib-std" }

test/src/e2e_vm_tests/test_programs/should_fail/const_generics/src/main.sw renamed to test/src/e2e_vm_tests/test_programs/should_fail/unsupported_const_generics/src/main.sw

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

45+
abi NoConstGenericsOnArgs {
46+
fn f(a: CrazyStruct<1>);
47+
}
48+
49+
abi NoConstGenericsOnReturn {
50+
fn f() -> CrazyEnum<1>;
51+
}
52+
53+
struct StructWithConstGenericInside {
54+
a: CrazyStruct<1>,
55+
}
56+
57+
abi NoConstGenericsIndirectStruct {
58+
fn f() -> StructWithConstGenericInside;
59+
}
60+
61+
enum EnumWithConstGenericInside {
62+
A: CrazyStruct<1>,
63+
}
64+
65+
abi NoConstGenericsIndirectEnum {
66+
fn f() -> EnumWithConstGenericInside;
67+
}
68+
4569
fn main() {
4670
let _: CrazyStruct<UNKNOWN> = CrazyStruct { };
4771
let _: CrazyEnum<UNKNOWN> = CrazyEnum::A;

0 commit comments

Comments
 (0)