Skip to content

Commit

Permalink
better error messages for slice in constants
Browse files Browse the repository at this point in the history
  • Loading branch information
xunilrj committed Jul 23, 2024
1 parent c4f0a91 commit 5741103
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 39 deletions.
58 changes: 55 additions & 3 deletions sway-core/src/language/ty/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ use sway_error::handler::{ErrorEmitted, Handler};
use sway_types::Span;

use crate::{
decl_engine::{DeclEngine, DeclRef, DeclRefFunction},
language::ModName,
language::{ty::*, HasModule, HasSubmodules},
decl_engine::{DeclEngine, DeclEngineGet, DeclRef, DeclRefFunction},
language::{ty::*, HasModule, HasSubmodules, ModName},
semantic_analysis::namespace,
transform::{self, AllowDeprecatedState},
Engines,
Expand All @@ -21,6 +20,59 @@ pub struct TyModule {
pub attributes: transform::AttributesMap,
}

impl TyModule {
/// Iter on all constants in this module, which means, globals constants and
/// local constants, but it does not enter into submodules.
pub fn iter_constants(&self, de: &DeclEngine) -> Vec<ConstantDecl> {
fn inside_code_block(de: &DeclEngine, block: &TyCodeBlock) -> Vec<ConstantDecl> {
block
.contents
.iter()
.flat_map(|node| inside_ast_node(de, node))
.collect::<Vec<_>>()
}

fn inside_ast_node(de: &DeclEngine, node: &TyAstNode) -> Vec<ConstantDecl> {
match &node.content {
TyAstNodeContent::Declaration(decl) => match decl {
TyDecl::ConstantDecl(decl) => {
vec![decl.clone()]
}
TyDecl::FunctionDecl(decl) => {
let decl = de.get(&decl.decl_id);
inside_code_block(de, &decl.body)
}
TyDecl::ImplSelfOrTrait(decl) => {
let decl = de.get(&decl.decl_id);
decl.items
.iter()
.flat_map(|item| match item {
TyTraitItem::Fn(decl) => {
let decl = de.get(decl.id());
inside_code_block(de, &decl.body)
}
TyTraitItem::Constant(decl) => {
vec![ConstantDecl {
decl_id: *decl.id(),
}]
}
_ => vec![],
})
.collect()
}
_ => vec![],
},
_ => vec![],
}
}

self.all_nodes
.iter()
.flat_map(|node| inside_ast_node(de, node))
.collect::<Vec<_>>()
}
}

#[derive(Clone, Debug)]
pub struct TySubmodule {
pub module: TyModule,
Expand Down
31 changes: 13 additions & 18 deletions sway-core/src/language/ty/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ impl TyProgram {
let decl_engine = engines.de();

// Validate all submodules
let mut non_configurables_constants = vec![];
let mut configurables = vec![];
for (_, submodule) in &root.submodules {
match Self::validate_root(
Expand Down Expand Up @@ -114,13 +113,6 @@ impl TyProgram {

declarations.push(TyDecl::FunctionDecl(FunctionDecl { decl_id: *decl_id }));
}
TyAstNodeContent::Declaration(TyDecl::ConstantDecl(ConstantDecl {
decl_id,
..
})) => {
let decl = (*decl_engine.get_constant(decl_id)).clone();
non_configurables_constants.push(decl);
}
TyAstNodeContent::Declaration(TyDecl::ConfigurableDecl(ConfigurableDecl {
decl_id,
..
Expand Down Expand Up @@ -404,23 +396,26 @@ impl TyProgram {
&c.type_ascription,
|t| match t {
TypeInfo::StringSlice => Some(TypeNotAllowedReason::StringSliceInConfigurables),
TypeInfo::Slice(_) => Some(TypeNotAllowedReason::SliceInConst),
_ => None,
},
) {
handler.emit_err(error);
}
}

for c in non_configurables_constants.iter() {
if let Some(error) = get_type_not_allowed_error(
engines,
c.return_type,
&c.type_ascription,
|t| match t {
TypeInfo::StringSlice => Some(TypeNotAllowedReason::StringSliceInConst),
_ => None,
},
) {
// verify all constants
for decl in root.iter_constants(decl_engine).iter() {
let decl = decl_engine.get_constant(&decl.decl_id);
let e =
get_type_not_allowed_error(engines, decl.return_type, &decl.type_ascription, |t| {
match t {
TypeInfo::StringSlice => Some(TypeNotAllowedReason::StringSliceInConst),
TypeInfo::Slice(_) => Some(TypeNotAllowedReason::SliceInConst),
_ => None,
}
});
if let Some(error) = e {
handler.emit_err(error);
}
}
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 @@ -2496,6 +2496,9 @@ pub enum TypeNotAllowedReason {

#[error("`str` or a type containing `str` on `const` is not allowed.")]
StringSliceInConst,

#[error("slices or types containing slices on `const` are not allowed.")]
SliceInConst,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[[package]]
name = "core"
source = "path+from-root-53D6DC514F06A250"

[[package]]
name = "slice_intrinsics"
source = "member"
dependencies = ["core"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[project]
authors = ["Fuel Labs <contact@fuel.sh>"]
entry = "main.sw"
license = "Apache-2.0"
name = "slice_intrinsics"

[dependencies]
core = { path = "../../../../../../../sway-lib-core" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"configurables": [],
"functions": [
{
"attributes": null,
"inputs": [],
"name": "main",
"output": {
"name": "",
"type": 0,
"typeArguments": null
}
}
],
"loggedTypes": [],
"messagesTypes": [],
"types": [
{
"components": null,
"type": "u64",
"typeId": 0,
"typeParameters": null
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"configurables": [],
"encoding": "1",
"functions": [
{
"attributes": null,
"inputs": [],
"name": "main",
"output": {
"name": "",
"type": 0,
"typeArguments": null
}
}
],
"loggedTypes": [],
"messagesTypes": [],
"types": [
{
"components": [],
"type": "()",
"typeId": 0,
"typeParameters": null
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
script;

// slice cannot be consts
const GLOBAL_ARRAY: [u64; 5] = [1, 2, 3, 4, 5];
const GLOBAL_SLICE: &__slice[u64] = __slice(GLOBAL_ARRAY, 0, 5);

fn main() {
// slice cannot be consts
const LOCAL_ARRAY: [u64; 5] = [1, 2, 3, 4, 5];
const LOCAL_SLICE: &__slice[u64] = __slice(LOCAL_ARRAY, 0, 5);

// Wrong start index
let a: [u64; 5] = [1, 2, 3, 4, 5];
let _ = __slice(a, 6, 7);

// Wrong end index
let a: [u64; 5] = [1, 2, 3, 4, 5];
let _ = __slice(a, 0, 6);

// Wrong first argument
__slice(0, 0, 0);

// Wrong start index
__slice(0, "", 0);

// Wrong end index
__slice(0, 0, "");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
category = "fail"

# check: let _ = __slice(a, 6, 7)
# nextln: $()Index out of bounds; the length is 5 but the index is 6.

# check: let _ = __slice(a, 0, 6)
# nextln: $()Index out of bounds; the length is 5 but the index is 6.

# check: __slice(0, 0, 0)
# nextln: $()Unsupported argument type to intrinsic "slice"

# check: __slice(0, "", 0)
# nextln: $()Mismatched types
# nextln: $()expected: u64
# nextln: $()found: str

# check: __slice(0, 0, "")
# nextln: $()Mismatched types
# nextln: $()expected: u64
# nextln: $()found: str

# check: &__slice[u64] = __slice(GLOBAL_ARRAY, 0, 5)
# nextln: $()slices or types containing slices on `const` are not allowed

# check: &__slice[u64] = __slice(LOCAL_ARRAY, 0, 5)
# nextln: $()slices or types containing slices on `const` are not allowed
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,22 @@ where
}

fn main() {
// slice arrays
let a: [u64; 5] = [1, 2, 3, 4, 5];
let s = __slice(a, 0, 5);
assert(1, *__slice_elem(s, 0));
assert(2, *__slice_elem(s, 1));
assert(3, *__slice_elem(s, 2));
assert(4, *__slice_elem(s, 3));
assert(5, *__slice_elem(s, 4));

// slice another slice
let s = __slice(a, 1, 4);
assert(2, *__slice_elem(s, 0));
assert(3, *__slice_elem(s, 1));
assert(4, *__slice_elem(s, 2));

// Vec impl using slices
let mut v: Vec<u64> = Vec::new();
v.push(1);
assert(v.get(0), 1);
Expand All @@ -132,22 +148,4 @@ fn main() {
assert(v.get(4), 5);
assert(v.get(5), 6);
assert(v.get(6), 7);

let a: [u64; 5] = [1, 2, 3, 4, 5];
let s = __slice(a, 0, 5);
assert(1, *__slice_elem(s, 0));
assert(2, *__slice_elem(s, 1));
assert(3, *__slice_elem(s, 2));
assert(4, *__slice_elem(s, 3));
assert(5, *__slice_elem(s, 4));

let s = __slice(a, 1, 4);
assert(2, *__slice_elem(s, 0));
assert(3, *__slice_elem(s, 1));
assert(4, *__slice_elem(s, 2));

const ARRAY: [u64; 5] = [1, 2, 3, 4, 5];
const SLICE: &__slice[u64] = __slice(ARRAY, 0, 5);
const ELEM: u64 = *__slice_elem(SLICE, 0);
assert(1, ELEM);
}

0 comments on commit 5741103

Please sign in to comment.