Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

better error and dca for configurables #6121

Merged
merged 12 commits into from
Jul 5, 2024
30 changes: 26 additions & 4 deletions sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::{
language::{
parsed::TreeType,
ty::{
self, ConstantDecl, FunctionDecl, ProjectionKind, StructDecl, TraitDecl, TyAstNode,
TyAstNodeContent, TyDecl, TyImplItem, TypeAliasDecl,
self, ConfigurableDecl, ConstantDecl, FunctionDecl, ProjectionKind, StructDecl,
TraitDecl, TyAstNode, TyAstNodeContent, TyDecl, TyImplItem, TypeAliasDecl,
},
CallPath, Visibility,
},
Expand Down Expand Up @@ -81,6 +81,11 @@ fn is_entry_point(node: &TyAstNode, decl_engine: &DeclEngine, tree_type: &TreeTy
let decl = decl_engine.get_constant(decl_id);
decl.visibility.is_public()
}
TyAstNode {
content:
TyAstNodeContent::Declaration(TyDecl::ConfigurableDecl(ConfigurableDecl { .. })),
..
} => false,
TyAstNode {
content:
TyAstNodeContent::Declaration(TyDecl::TypeAliasDecl(TypeAliasDecl {
Expand Down Expand Up @@ -567,19 +572,26 @@ fn connect_declaration<'eng: 'cfg, 'cfg>(
ty::TyDecl::ConfigurableDecl(ty::ConfigurableDecl { decl_id, .. }) => {
let config_decl = decl_engine.get_configurable(decl_id);
let ty::TyConfigurableDecl {
call_path, value, ..
call_path,
value,
type_ascription,
..
} = &*config_decl;

graph
.namespace
.insert_configurable(call_path.suffix.clone(), entry_node);

connect_type_id(engines, type_ascription.type_id, graph, entry_node)?;

if let Some(value) = &value {
connect_expression(
engines,
&value.expression,
graph,
&[entry_node],
exit_node,
"constant declaration expression",
"configurable declaration expression",
tree_type,
value.span.clone(),
options,
Expand Down Expand Up @@ -2308,6 +2320,16 @@ fn construct_dead_code_warning_from_node(
span: decl_engine.get_constant(decl_id).name().span(),
warning_content: Warning::DeadDeclaration,
},
ty::TyAstNode {
content:
ty::TyAstNodeContent::Declaration(ty::TyDecl::ConfigurableDecl(ty::ConfigurableDecl {
decl_id,
})),
..
} => CompileWarning {
span: decl_engine.get_configurable(decl_id).name().span(),
warning_content: Warning::DeadDeclaration,
},
ty::TyAstNode {
content: ty::TyAstNodeContent::Declaration(ty::TyDecl::VariableDecl(decl)),
span,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub struct ConfigurableDeclaration {
pub value: Option<Expression>,
pub visibility: Visibility,
pub span: Span,
pub block_keyword_span: Span,
}

impl Named for ConfigurableDeclaration {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::VecDeque;

use sway_error::{
error::CompileError,
handler::{ErrorEmitted, Handler},
warning::{CompileWarning, Warning},
};
Expand Down Expand Up @@ -33,6 +34,7 @@ impl ty::TyConfigurableDecl {
value,
attributes,
visibility,
block_keyword_span,
} = decl;

type_ascription.type_id = ctx
Expand Down Expand Up @@ -84,26 +86,43 @@ impl ty::TyConfigurableDecl {
.insert(engines, TypeInfo::RawUntypedSlice, None),
);

let (decode_fn_ref, _, _): (crate::decl_engine::DeclRefFunction, _, _) =
crate::TypeBinding::type_check(
&mut TypeBinding::<CallPath> {
inner: CallPath {
prefixes: vec![],
suffix: sway_types::Ident::new_no_span("abi_decode_in_place".into()),
is_absolute: false,
},
type_arguments: crate::TypeArgs::Regular(vec![TypeArgument {
type_id: type_ascription.type_id,
initial_type_id: type_ascription.type_id,
span: sway_types::Span::dummy(),
call_path_tree: None,
}]),
span: sway_types::Span::dummy(),
let value_span = value
.as_ref()
.map(|x| x.span.clone())
.unwrap_or_else(|| span.clone());
let abi_decode_in_place_handler = Handler::default();
let r = crate::TypeBinding::type_check(
&mut TypeBinding::<CallPath> {
inner: CallPath {
prefixes: vec![],
suffix: sway_types::Ident::new_with_override(
"abi_decode_in_place".into(),
value_span.clone(),
),
is_absolute: false,
},
handler,
ctx.by_ref(),
)
.unwrap();
type_arguments: crate::TypeArgs::Regular(vec![TypeArgument {
type_id: type_ascription.type_id,
initial_type_id: type_ascription.type_id,
span: sway_types::Span::dummy(),
call_path_tree: None,
}]),
span: value_span.clone(),
},
&abi_decode_in_place_handler,
ctx.by_ref(),
);

// Map expected errors to more understandable ones
handler.map_and_emit_errors_from(abi_decode_in_place_handler, |e| match e {
CompileError::SymbolNotFound { .. } => {
Some(CompileError::ConfigurableMissingAbiDecodeInPlace {
span: block_keyword_span.clone(),
})
}
e => Some(e),
})?;
let (decode_fn_ref, _, _): (crate::decl_engine::DeclRefFunction, _, _) = r?;

let mut decode_fn_decl = (*engines.de().get_function(&decode_fn_ref)).clone();
let decl_mapping = crate::TypeParameter::gather_decl_mapping_from_trait_constraints(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,17 +180,15 @@ impl TyDecl {
parsed::Declaration::ConfigurableDeclaration(decl_id) => {
let decl = engines.pe().get_configurable(&decl_id).as_ref().clone();
let span = decl.span.clone();
let config_decl =
let name = decl.name.clone();
let typed_const_decl =
match ty::TyConfigurableDecl::type_check(handler, ctx.by_ref(), decl) {
Ok(res) => res,
Err(err) => return Ok(ty::TyDecl::ErrorRecovery(span, err)),
Ok(config_decl) => {
ty::TyDecl::from(decl_engine.insert(config_decl.clone()))
}
Err(err) => ty::TyDecl::ErrorRecovery(span, err),
};
let typed_const_decl: ty::TyDecl = decl_engine.insert(config_decl.clone()).into();
ctx.insert_symbol(
handler,
config_decl.name().clone(),
typed_const_decl.clone(),
)?;
ctx.insert_symbol(handler, name, typed_const_decl.clone())?;
typed_const_decl
}
parsed::Declaration::TraitTypeDeclaration(decl_id) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,7 @@ fn item_configurable_to_configurable_declarations(
});
}

let item_configurable_keyword_span = item_configurable.configurable_token.span();
let declarations: Vec<ParsedDeclId<ConfigurableDeclaration>> = item_configurable
.fields
.into_inner()
Expand All @@ -1101,6 +1102,7 @@ fn item_configurable_to_configurable_declarations(
engines,
configurable_field.value,
attributes,
item_configurable_keyword_span.clone(),
)?))
})
.filter_map_ok(|decl| decl)
Expand Down Expand Up @@ -2571,6 +2573,7 @@ fn configurable_field_to_configurable_declaration(
engines: &Engines,
configurable_field: sway_ast::ConfigurableField,
attributes: AttributesMap,
item_configurable_keyword_span: Span,
) -> Result<ParsedDeclId<ConfigurableDeclaration>, ErrorEmitted> {
let span = configurable_field.name.span();

Expand Down Expand Up @@ -2606,6 +2609,7 @@ fn configurable_field_to_configurable_declaration(
visibility: Visibility::Public,
attributes,
span: span.clone(),
block_keyword_span: item_configurable_keyword_span,
};
Ok(engines.pe().insert(config_decl))
}
Expand Down
16 changes: 16 additions & 0 deletions sway-error/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,8 @@ pub enum CompileError {
CouldNotGenerateEntryMissingImpl { ty: String, span: Span },
#[error("Only bool, u8, u16, u32, u64, u256, b256, string arrays and string slices can be used here.")]
EncodingUnsupportedType { span: Span },
#[error("Configurables need a function named \"abi_decode_in_place\" to be in scope.")]
ConfigurableMissingAbiDecodeInPlace { span: Span },
}

impl std::convert::From<TypeError> for CompileError {
Expand Down Expand Up @@ -1175,6 +1177,7 @@ impl Spanned for CompileError {
CouldNotGenerateEntryMissingImpl { span, .. } => span.clone(),
CannotBeEvaluatedToConfigurableSizeUnknown { span } => span.clone(),
EncodingUnsupportedType { span } => span.clone(),
ConfigurableMissingAbiDecodeInPlace { span } => span.clone(),
}
}
}
Expand Down Expand Up @@ -2438,6 +2441,19 @@ impl ToDiagnostic for CompileError {
},
}
},
ConfigurableMissingAbiDecodeInPlace { span } => Diagnostic {
reason: Some(Reason::new(code(1), "Configurables need a function named \"abi_decode_in_place\" to be in scope".to_string())),
issue: Issue::error(
source_engine,
span.clone(),
String::new()
),
hints: vec![],
help: vec![
"The function \"abi_decode_in_place\" is usually defined in the standard library module \"core::codec\".".into(),
"Verify that you are using a version of the \"core\" standard library that contains this function.".into(),
],
},
_ => Diagnostic {
// TODO: Temporary we use self here to achieve backward compatibility.
// In general, self must not be used and will not be used once we
Expand Down
19 changes: 19 additions & 0 deletions sway-error/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,25 @@ impl Handler {
{
self.inner.borrow_mut().errors.retain(f)
}

// Map all errors from `other` into this handler. If any mapping returns `None` it is ignored. This
// method returns if any error was mapped or not.
pub fn map_and_emit_errors_from(
&self,
other: Handler,
mut f: impl FnMut(CompileError) -> Option<CompileError>,
) -> Result<(), ErrorEmitted> {
let mut emitted = Ok(());

let (errs, _) = other.consume();
for err in errs {
if let Some(err) = (f)(err) {
emitted = Err(self.emit_err(err));
}
}

emitted
}
}

/// Proof that an error was emitted through a `Handler`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[[package]]
name = 'configurable_consts'
source = 'member'
dependencies = ['std']
name = "configurable_consts"
source = "member"
dependencies = ["std"]

[[package]]
name = 'core'
source = 'path+from-root-7F58364AF9C32FE1'
name = "core"
source = "path+from-root-7F58364AF9C32FE1"

[[package]]
name = 'std'
source = 'path+from-root-7F58364AF9C32FE1'
dependencies = ['core']
name = "std"
source = "path+from-root-7F58364AF9C32FE1"
dependencies = ["core"]
Loading
Loading