Skip to content

Commit

Permalink
Const generic feature toggle, parser and errors. (#6926)
Browse files Browse the repository at this point in the history
## Description

This PR is part of #6860, and it
is officially introducing the `const_generic` feature toggle.

For the moment, it is parsing syntax such as `const N: u64` and it is
returning an error explaining that the feature is off; on the other
hand, it is also returning an error saying that const generics are still
not supported in impl traits when the feature is on. Future PRs will
replicate this error in all possible places.

Nothing else is implemented and it is reserved for future PRs.

## 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.

---------

Co-authored-by: IGI-111 <igi-111@protonmail.com>
  • Loading branch information
xunilrj and IGI-111 authored Feb 17, 2025
1 parent 1589951 commit d8854fa
Show file tree
Hide file tree
Showing 33 changed files with 577 additions and 136 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion forc-plugins/forc-doc/src/render/item/type_anchor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ pub(crate) fn render_type_anchor(
render_plan,
current_module_info,
)?;
let len_string = format!("{:?}", render_plan.engines.help_out(len));
Ok(box_html! {
: "[";
: inner;
: format!("; {}]", len.val());
: format!("; {}]", len_string);
})
}
TypeInfo::Slice(ty_arg) => {
Expand Down
8 changes: 7 additions & 1 deletion sway-ast/src/generics.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
use crate::priv_prelude::*;

#[derive(Clone, Debug, Serialize)]
pub enum GenericParam {
Trait { ident: Ident },
Const { ident: Ident, ty: Ident },
}

#[derive(Clone, Debug, Serialize)]
pub struct GenericParams {
pub parameters: AngleBrackets<Punctuated<Ident, CommaToken>>,
pub parameters: AngleBrackets<Punctuated<GenericParam, CommaToken>>,
}

#[derive(Clone, Debug, Serialize)]
Expand Down
15 changes: 9 additions & 6 deletions sway-core/src/abi_generation/abi_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,19 @@ impl TypeId {
.collect::<Vec<String>>();
format!("({})", field_strs.join(", "))
}
(TypeInfo::Array(_, count), TypeInfo::Array(type_arg, resolved_count)) => {
assert_eq!(count.val(), resolved_count.val());
(TypeInfo::Array(_, length), TypeInfo::Array(type_arg, resolved_length)) => {
assert_eq!(
length.as_literal_val().unwrap(),
resolved_length.as_literal_val().unwrap()
);
let inner_type = if ctx.abi_with_fully_specified_types {
type_engine
.get(type_arg.type_id)
.abi_str(ctx, engines, false)
} else {
"_".to_string()
};
format!("[{}; {}]", inner_type, count.val())
format!("[{}; {:?}]", inner_type, engines.help_out(length))
}
(TypeInfo::Slice(type_arg), TypeInfo::Slice(_)) => {
let inner_type = if ctx.abi_with_fully_specified_types {
Expand Down Expand Up @@ -92,7 +95,7 @@ impl TypeInfo {
Placeholder(_) => "_".to_string(),
TypeParam(n) => format!("typeparam({n})"),
StringSlice => "str".into(),
StringArray(x) => format!("str[{}]", x.val()),
StringArray(length) => format!("str[{}]", length.val()),
UnsignedInteger(x) => match x {
IntegerBits::Eight => "u8",
IntegerBits::Sixteen => "u16",
Expand Down Expand Up @@ -174,9 +177,9 @@ impl TypeInfo {
}
Array(elem_ty, length) => {
format!(
"[{}; {}]",
"[{}; {:?}]",
elem_ty.abi_str(ctx, engines, false),
length.val()
engines.help_out(length)
)
}
RawUntypedPtr => "raw untyped ptr".into(),
Expand Down
15 changes: 11 additions & 4 deletions sway-core/src/abi_generation/evm_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ fn get_type_str(type_id: &TypeId, engines: &Engines, resolved_type_id: TypeId) -
.collect::<Vec<String>>();
format!("({})", field_strs.join(", "))
}
(TypeInfo::Array(_, count), TypeInfo::Array(_, resolved_count)) => {
assert_eq!(count.val(), resolved_count.val());
format!("[_; {}]", count.val())
(TypeInfo::Array(_, length), TypeInfo::Array(_, resolved_length)) => {
assert_eq!(
length.as_literal_val().unwrap(),
resolved_length.as_literal_val().unwrap()
);
format!("[_; {:?}]", engines.help_out(length))
}
(TypeInfo::Slice(_), TypeInfo::Slice(_)) => "__slice[_]".into(),
(TypeInfo::Custom { .. }, _) => {
Expand Down Expand Up @@ -113,7 +116,11 @@ pub fn abi_str(type_info: &TypeInfo, engines: &Engines) -> String {
format!("contract caller {abi_name}")
}
Array(elem_ty, length) => {
format!("{}[{}]", abi_str_type_arg(elem_ty, engines), length.val())
format!(
"{}[{:?}]",
abi_str_type_arg(elem_ty, engines),
engines.help_out(length),
)
}
RawUntypedPtr => "raw untyped ptr".into(),
RawUntypedSlice => "raw untyped slice".into(),
Expand Down
10 changes: 7 additions & 3 deletions sway-core/src/decl_engine/parsed_engine.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::{
concurrent_slab::ConcurrentSlab,
language::parsed::{
AbiDeclaration, ConfigurableDeclaration, ConstantDeclaration, EnumDeclaration, EnumVariant,
FunctionDeclaration, ImplSelfOrTrait, StorageDeclaration, StructDeclaration,
TraitDeclaration, TraitFn, TraitTypeDeclaration, TypeAliasDeclaration, VariableDeclaration,
AbiDeclaration, ConfigurableDeclaration, ConstGenericDeclaration, ConstantDeclaration,
EnumDeclaration, EnumVariant, FunctionDeclaration, ImplSelfOrTrait, StorageDeclaration,
StructDeclaration, TraitDeclaration, TraitFn, TraitTypeDeclaration, TypeAliasDeclaration,
VariableDeclaration,
},
};

Expand All @@ -26,6 +27,7 @@ pub struct ParsedDeclEngine {
abi_slab: ConcurrentSlab<AbiDeclaration>,
constant_slab: ConcurrentSlab<ConstantDeclaration>,
configurable_slab: ConcurrentSlab<ConfigurableDeclaration>,
const_generic_slab: ConcurrentSlab<ConstGenericDeclaration>,
enum_slab: ConcurrentSlab<EnumDeclaration>,
enum_variant_slab: ConcurrentSlab<EnumVariant>,
type_alias_slab: ConcurrentSlab<TypeAliasDeclaration>,
Expand Down Expand Up @@ -70,6 +72,7 @@ decl_engine_get!(storage_slab, StorageDeclaration);
decl_engine_get!(abi_slab, AbiDeclaration);
decl_engine_get!(constant_slab, ConstantDeclaration);
decl_engine_get!(configurable_slab, ConfigurableDeclaration);
decl_engine_get!(const_generic_slab, ConstGenericDeclaration);
decl_engine_get!(enum_slab, EnumDeclaration);
decl_engine_get!(enum_variant_slab, EnumVariant);
decl_engine_get!(type_alias_slab, TypeAliasDeclaration);
Expand All @@ -95,6 +98,7 @@ decl_engine_insert!(storage_slab, StorageDeclaration);
decl_engine_insert!(abi_slab, AbiDeclaration);
decl_engine_insert!(constant_slab, ConstantDeclaration);
decl_engine_insert!(configurable_slab, ConfigurableDeclaration);
decl_engine_insert!(const_generic_slab, ConstGenericDeclaration);
decl_engine_insert!(enum_slab, EnumDeclaration);
decl_engine_insert!(enum_variant_slab, EnumVariant);
decl_engine_insert!(type_alias_slab, TypeAliasDeclaration);
Expand Down
12 changes: 9 additions & 3 deletions sway-core/src/ir_generation/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ fn convert_resolved_type_info(
TypeInfo::Boolean => Type::get_bool(context),
TypeInfo::B256 => Type::get_b256(context),
TypeInfo::StringSlice => Type::get_slice(context),
TypeInfo::StringArray(n) => Type::new_string_array(context, n.val() as u64),
TypeInfo::StringArray(length) => Type::new_string_array(context, length.val() as u64),
TypeInfo::Struct(decl_ref) => super::types::get_struct_for_types(
type_engine,
decl_engine,
Expand All @@ -121,15 +121,20 @@ fn convert_resolved_type_info(
context,
&decl_engine.get_enum(decl_ref).variants,
)?,
TypeInfo::Array(elem_type, length) => {
TypeInfo::Array(elem_type, length) if length.as_literal_val().is_some() => {
// SAFETY: Safe by the guard above
let len = length
.as_literal_val()
.expect("unexpected non literal array length");

let elem_type = convert_resolved_type_id(
type_engine,
decl_engine,
context,
elem_type.type_id,
span,
)?;
Type::new_array(context, elem_type, length.val() as u64)
Type::new_array(context, elem_type, len as u64)
}

TypeInfo::Tuple(fields) => {
Expand Down Expand Up @@ -185,5 +190,6 @@ fn convert_resolved_type_info(
TypeInfo::TypeParam(_) => reject_type!("TypeParam"),
TypeInfo::ErrorRecovery(_) => reject_type!("Error recovery"),
TypeInfo::TraitType { .. } => reject_type!("TraitType"),
TypeInfo::Array(..) => reject_type!("Array with non literal length"),
})
}
2 changes: 2 additions & 0 deletions sway-core/src/language/parsed/declaration.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod abi;
mod configurable;
mod const_generic;
mod constant;
mod r#enum;
pub mod function;
Expand All @@ -14,6 +15,7 @@ use std::fmt;

pub use abi::*;
pub use configurable::*;
pub use const_generic::*;
pub use constant::*;
pub use function::*;
pub use impl_trait::*;
Expand Down
9 changes: 9 additions & 0 deletions sway-core/src/language/parsed/declaration/const_generic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use crate::TypeId;
use sway_types::{Ident, Span};

#[derive(Debug, Clone)]
pub struct ConstGenericDeclaration {
pub name: Ident,
pub ty: TypeId,
pub span: Span,
}
5 changes: 4 additions & 1 deletion sway-core/src/language/parsed/declaration/impl_trait.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use super::{ConstantDeclaration, FunctionDeclaration, TraitTypeDeclaration};
use super::{
ConstGenericDeclaration, ConstantDeclaration, FunctionDeclaration, TraitTypeDeclaration,
};
use crate::{
decl_engine::{parsed_id::ParsedDeclId, ParsedInterfaceDeclId},
engine_threading::{
Expand Down Expand Up @@ -67,6 +69,7 @@ impl DebugWithEngines for ImplItem {
pub struct ImplSelfOrTrait {
pub is_self: bool,
pub impl_type_parameters: Vec<TypeParameter>,
pub impl_const_generics_parameters: Vec<ParsedDeclId<ConstGenericDeclaration>>,
pub trait_name: CallPath,
pub trait_type_arguments: Vec<TypeArgument>,
pub trait_decl_ref: Option<ParsedInterfaceDeclId>,
Expand Down
12 changes: 12 additions & 0 deletions sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ impl TyImplSelfOrTrait {

let ImplSelfOrTrait {
impl_type_parameters,
impl_const_generics_parameters,
trait_name,
mut trait_type_arguments,
trait_decl_ref: _,
Expand Down Expand Up @@ -138,6 +139,17 @@ impl TyImplSelfOrTrait {
.with_self_type(Some(self_type_id))
.allow_functions()
.scoped(handler, Some(block_span.clone()), |ctx| {
// Notify the user that const generic is still not supported here, but let the compilation
// continue
for const_generic_decl_id in impl_const_generics_parameters {
let decl = engines.pe().get(&const_generic_decl_id);
if ctx.experimental.const_generics {
handler.emit_err(CompileError::ConstGenericNotSupportedHere {
span: decl.span.clone(),
});
}
}

// Type check the type parameters
let new_impl_type_parameters = TypeParameter::type_check_type_params(
handler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,12 @@ fn type_check_slice(
referenced_type,
to_mutable_value,
} => match &*type_engine.get(referenced_type.type_id) {
TypeInfo::Array(elem_type_arg, array_len) => {
let array_len = array_len.val() as u64;
TypeInfo::Array(elem_type_arg, array_len) if array_len.as_literal_val().is_some() => {
// SAFETY: safe by the guard above
let array_len = array_len
.as_literal_val()
.expect("unexpected non literal array length")
as u64;

if let Some(v) = start_literal {
if v > array_len {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2676,7 +2676,7 @@ impl ty::TyExpression {
(
TypeInfo::Array(elem_ty, array_length),
ty::ProjectionKind::ArrayIndex { index, index_span },
) => {
) if array_length.as_literal_val().is_some() => {
parent_rover = symbol;
symbol = elem_ty.type_id;
symbol_span = index_span.clone();
Expand All @@ -2686,10 +2686,15 @@ impl ty::TyExpression {
.as_literal()
.and_then(|x| x.cast_value_to_u64())
{
if index_literal >= array_length.val() as u64 {
// SAFETY: safe by the guard above
let array_length = array_length
.as_literal_val()
.expect("unexpected non literal array length")
as u64;
if index_literal >= array_length {
return Err(handler.emit_err(CompileError::ArrayOutOfBounds {
index: index_literal,
count: array_length.val() as u64,
count: array_length,
span: index.span.clone(),
}));
}
Expand Down
4 changes: 2 additions & 2 deletions sway-core/src/semantic_analysis/namespace/trait_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ enum TypeRootFilter {
Enum(ParsedDeclId<EnumDeclaration>),
Struct(ParsedDeclId<StructDeclaration>),
ContractCaller(String),
Array(usize),
Array,
RawUntypedPtr,
RawUntypedSlice,
Ptr,
Expand Down Expand Up @@ -1509,7 +1509,7 @@ impl TraitMap {
TypeRootFilter::Struct(engines.de().get_parsed_decl_id(decl_id).unwrap())
}
ContractCaller { abi_name, .. } => TypeRootFilter::ContractCaller(abi_name.to_string()),
Array(_, length) => TypeRootFilter::Array(length.val()),
Array(_, _) => TypeRootFilter::Array,
RawUntypedPtr => TypeRootFilter::RawUntypedPtr,
RawUntypedSlice => TypeRootFilter::RawUntypedSlice,
Ptr(_) => TypeRootFilter::Ptr,
Expand Down
Loading

0 comments on commit d8854fa

Please sign in to comment.