Skip to content

Commit

Permalink
Error out when Vec is used in a storage block (FuelLabs#3777)
Browse files Browse the repository at this point in the history
This PR creates an error when `Vec` is used in a `storage` block by
checking for instances in `raw_ptr`. Right now there is only one simple
test, so I can add more if you feel it necessary.

Closes FuelLabs#3305

Co-authored-by: emilyaherbert <[email protected]>
  • Loading branch information
emilyaherbert and emilyaherbert authored Jan 14, 2023
1 parent 22ffb20 commit 7c95013
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 3 deletions.
12 changes: 12 additions & 0 deletions sway-ast/src/item/item_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,15 @@ pub struct StorageField {
pub eq_token: EqToken,
pub initializer: Expr,
}

impl Spanned for StorageField {
fn span(&self) -> Span {
Span::join_all([
self.name.span(),
self.colon_token.span(),
self.ty.span(),
self.eq_token.span(),
self.initializer.span(),
])
}
}
1 change: 1 addition & 0 deletions sway-core/src/language/parsed/declaration/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ pub struct StorageField {
pub attributes: transform::AttributesMap,
pub type_info: TypeInfo,
pub type_info_span: Span,
pub span: Span,
pub initializer: Expression,
}
32 changes: 31 additions & 1 deletion sway-core/src/language/ty/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,37 @@ impl TyProgram {

// Perform other validation based on the tree type.
let typed_program_kind = match kind {
parsed::TreeType::Contract => TyProgramKind::Contract { abi_entries },
parsed::TreeType::Contract => {
// Types containing raw_ptr are not allowed in storage (e.g Vec)
for decl in declarations.iter() {
if let TyDeclaration::StorageDeclaration(decl_id) = decl {
if let Ok(storage_decl) =
decl_engine.get_storage(decl_id.clone(), &decl_id.span())
{
for field in storage_decl.fields.iter() {
let type_info = ty_engine.get(field.type_id);
let type_info_str = engines.help_out(&type_info).to_string();
let raw_ptr_type = type_info
.extract_nested_types(ty_engine, &field.span)
.value
.and_then(|value| {
value
.into_iter()
.find(|ty| matches!(ty, TypeInfo::RawUntypedPtr))
});
if raw_ptr_type.is_some() {
errors.push(CompileError::TypeNotAllowedInContractStorage {
ty: type_info_str,
span: field.span.clone(),
});
}
}
}
}
}

TyProgramKind::Contract { abi_entries }
}
parsed::TreeType::Library { name } => TyProgramKind::Library { name },
parsed::TreeType::Predicate => {
// A predicate must have a main function and that function must return a boolean.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ impl ty::TyDeclaration {
initializer,
type_info_span,
attributes,
span: field_span,
..
} in fields
{
Expand Down Expand Up @@ -336,7 +337,7 @@ impl ty::TyDeclaration {
type_id,
type_span: type_info_span,
initializer,
span: span.clone(),
span: field_span,
attributes,
});
}
Expand Down
2 changes: 2 additions & 0 deletions sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1864,11 +1864,13 @@ fn storage_field_to_storage_field(
} else {
storage_field.ty.span()
};
let span = storage_field.span();
let storage_field = StorageField {
attributes,
name: storage_field.name,
type_info: ty_to_type_info(handler, engines, storage_field.ty)?,
type_info_span,
span,
initializer: expr_to_expression(handler, engines, storage_field.initializer)?,
};
Ok(storage_field)
Expand Down
3 changes: 3 additions & 0 deletions sway-error/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,8 @@ pub enum CompileError {
ConfigTimeConstantNotAConstDecl { span: Span },
#[error("Configuration-time constant value is not a literal.")]
ConfigTimeConstantNotALiteral { span: Span },
#[error("The type \"{ty}\" is not allowed in storage.")]
TypeNotAllowedInContractStorage { ty: String, span: Span },
#[error("ref mut parameter not allowed for main()")]
RefMutableNotAllowedInMain { param_name: Ident },
#[error("Returning a `raw_ptr` from `main()` is not allowed.")]
Expand Down Expand Up @@ -889,6 +891,7 @@ impl Spanned for CompileError {
ContinueOutsideLoop { span } => span.clone(),
ConfigTimeConstantNotAConstDecl { span } => span.clone(),
ConfigTimeConstantNotALiteral { span } => span.clone(),
TypeNotAllowedInContractStorage { span, .. } => span.clone(),
RefMutableNotAllowedInMain { param_name } => param_name.span(),
PointerReturnNotAllowedInMain { span } => span.clone(),
NestedSliceReturnNotAllowedInMain { span } => span.clone(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ storage {
v: StorageVec<u64> = StorageVec {},
u: StorageVec<StorageVec<u64>> = StorageVec {},
map1: StorageMap<u32, u32> = StorageMap{},
bad_type: StorageVec<Vec<bool>> = StorageVec {},
}

abi MyContract {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@ category = "fail"

# check: $()error
# check: $()fn insert(mapping: StorageMap<u64, u64>) {
# nextln: $()Type StorageMap<u64, u64> can only be declared directly as a storage field
# nextln: $()Type StorageMap<u64, u64> can only be declared directly as a storage field

# check: $()error
# check: $()bad_type: StorageVec<Vec<bool>> = StorageVec {},
# nextln: $()The type "StorageVec<Vec<bool>>" is not allowed in storage.

0 comments on commit 7c95013

Please sign in to comment.