diff --git a/sway-core/src/control_flow_analysis/dead_code_analysis.rs b/sway-core/src/control_flow_analysis/dead_code_analysis.rs index e15c6f84ef0..6d355f34e56 100644 --- a/sway-core/src/control_flow_analysis/dead_code_analysis.rs +++ b/sway-core/src/control_flow_analysis/dead_code_analysis.rs @@ -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, }, @@ -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 { @@ -567,11 +572,18 @@ 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, @@ -579,7 +591,7 @@ fn connect_declaration<'eng: 'cfg, 'cfg>( graph, &[entry_node], exit_node, - "constant declaration expression", + "configurable declaration expression", tree_type, value.span.clone(), options, @@ -2305,6 +2317,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, diff --git a/sway-core/src/language/parsed/declaration/configurable.rs b/sway-core/src/language/parsed/declaration/configurable.rs index 9a269e64680..c28eb1c2122 100644 --- a/sway-core/src/language/parsed/declaration/configurable.rs +++ b/sway-core/src/language/parsed/declaration/configurable.rs @@ -13,6 +13,7 @@ pub struct ConfigurableDeclaration { pub value: Option, pub visibility: Visibility, pub span: Span, + pub block_keyword_span: Span, } impl Named for ConfigurableDeclaration { diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs b/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs index 7056a0a2988..f8ab7a73f67 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/configurable.rs @@ -1,6 +1,7 @@ use std::collections::VecDeque; use sway_error::{ + error::CompileError, handler::{ErrorEmitted, Handler}, warning::{CompileWarning, Warning}, }; @@ -33,6 +34,7 @@ impl ty::TyConfigurableDecl { value, attributes, visibility, + block_keyword_span, } = decl; type_ascription.type_id = ctx @@ -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:: { - 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:: { + 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( diff --git a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs index 10c4bb9894c..8514f96d469 100644 --- a/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs +++ b/sway-core/src/semantic_analysis/ast_node/declaration/declaration.rs @@ -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) => { diff --git a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs index 8d24ef5760d..655b4be620c 100644 --- a/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs +++ b/sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs @@ -1085,6 +1085,7 @@ fn item_configurable_to_configurable_declarations( }); } + let item_configurable_keyword_span = item_configurable.configurable_token.span(); let declarations: Vec> = item_configurable .fields .into_inner() @@ -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) @@ -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, ErrorEmitted> { let span = configurable_field.name.span(); @@ -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)) } diff --git a/sway-error/src/error.rs b/sway-error/src/error.rs index 97a1a159e5a..33b17ea500e 100644 --- a/sway-error/src/error.rs +++ b/sway-error/src/error.rs @@ -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 for CompileError { @@ -1175,6 +1177,7 @@ impl Spanned for CompileError { CouldNotGenerateEntryMissingImpl { span, .. } => span.clone(), CannotBeEvaluatedToConfigurableSizeUnknown { span } => span.clone(), EncodingUnsupportedType { span } => span.clone(), + ConfigurableMissingAbiDecodeInPlace { span } => span.clone(), } } } @@ -2430,6 +2433,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 diff --git a/sway-error/src/handler.rs b/sway-error/src/handler.rs index a9485d89c9a..e9bd370f1ef 100644 --- a/sway-error/src/handler.rs +++ b/sway-error/src/handler.rs @@ -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, + ) -> 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`. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/Forc.lock index 842942b25da..17cc4b10427 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/Forc.lock +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/Forc.lock @@ -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"] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json index b6a290205a9..32f83d32de0 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/json_abi_oracle_new_encoding.json @@ -1,139 +1,13 @@ { "configurables": [ - { - "configurableType": { - "name": "", - "type": 5, - "typeArguments": null - }, - "name": "BOOL", - "offset": 6912 - }, - { - "configurableType": { - "name": "", - "type": 13, - "typeArguments": null - }, - "name": "U8", - "offset": 7048 - }, - { - "configurableType": { - "name": "", - "type": 13, - "typeArguments": null - }, - "name": "ANOTHER_U8", - "offset": 6840 - }, - { - "configurableType": { - "name": "", - "type": 9, - "typeArguments": null - }, - "name": "U16", - "offset": 6992 - }, - { - "configurableType": { - "name": "", - "type": 11, - "typeArguments": null - }, - "name": "U32", - "offset": 7032 - }, - { - "configurableType": { - "name": "", - "type": 11, - "typeArguments": null - }, - "name": "U64", - "offset": 7040 - }, - { - "configurableType": { - "name": "", - "type": 10, - "typeArguments": null - }, - "name": "U256", - "offset": 7000 - }, - { - "configurableType": { - "name": "", - "type": 4, - "typeArguments": null - }, - "name": "B256", - "offset": 6880 - }, - { - "configurableType": { - "name": "", - "type": 8, - "typeArguments": [] - }, - "name": "CONFIGURABLE_STRUCT", - "offset": 6952 - }, - { - "configurableType": { - "name": "", - "type": 6, - "typeArguments": [] - }, - "name": "CONFIGURABLE_ENUM_A", - "offset": 6920 - }, - { - "configurableType": { - "name": "", - "type": 6, - "typeArguments": [] - }, - "name": "CONFIGURABLE_ENUM_B", - "offset": 6936 - }, - { - "configurableType": { - "name": "", - "type": 2, - "typeArguments": null - }, - "name": "ARRAY_BOOL", - "offset": 6848 - }, - { - "configurableType": { - "name": "", - "type": 3, - "typeArguments": null - }, - "name": "ARRAY_U64", - "offset": 6856 - }, { "configurableType": { "name": "", "type": 1, "typeArguments": null }, - "name": "TUPLE_BOOL_U64", - "offset": 6976 - }, - { - "configurableType": { - "name": "", - "type": 7, - "typeArguments": null - }, - "name": "STR_4", - "offset": 6968 + "name": "BOOL", + "offset": 360 } ], "encoding": "1", @@ -158,127 +32,10 @@ "typeId": 0, "typeParameters": null }, - { - "components": [ - { - "name": "__tuple_element", - "type": 5, - "typeArguments": null - }, - { - "name": "__tuple_element", - "type": 12, - "typeArguments": null - } - ], - "type": "(_, _)", - "typeId": 1, - "typeParameters": null - }, - { - "components": [ - { - "name": "__array_element", - "type": 5, - "typeArguments": null - } - ], - "type": "[_; 3]", - "typeId": 2, - "typeParameters": null - }, - { - "components": [ - { - "name": "__array_element", - "type": 12, - "typeArguments": null - } - ], - "type": "[_; 3]", - "typeId": 3, - "typeParameters": null - }, - { - "components": null, - "type": "b256", - "typeId": 4, - "typeParameters": null - }, { "components": null, "type": "bool", - "typeId": 5, - "typeParameters": null - }, - { - "components": [ - { - "name": "A", - "type": 5, - "typeArguments": null - }, - { - "name": "B", - "type": 12, - "typeArguments": null - } - ], - "type": "enum ConfigurableEnum", - "typeId": 6, - "typeParameters": null - }, - { - "components": null, - "type": "str[4]", - "typeId": 7, - "typeParameters": null - }, - { - "components": [ - { - "name": "a", - "type": 5, - "typeArguments": null - }, - { - "name": "b", - "type": 12, - "typeArguments": null - } - ], - "type": "struct ConfigurableStruct", - "typeId": 8, - "typeParameters": null - }, - { - "components": null, - "type": "u16", - "typeId": 9, - "typeParameters": null - }, - { - "components": null, - "type": "u256", - "typeId": 10, - "typeParameters": null - }, - { - "components": null, - "type": "u32", - "typeId": 11, - "typeParameters": null - }, - { - "components": null, - "type": "u64", - "typeId": 12, - "typeParameters": null - }, - { - "components": null, - "type": "u8", - "typeId": 13, + "typeId": 1, "typeParameters": null } ] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/src/main.sw index 6e0e94ba5e1..59a4d92df27 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/src/main.sw @@ -1,78 +1,9 @@ - script; - -use std::hash::*; - -struct ConfigurableStruct { - a: bool, - b: u64, -} - -enum ConfigurableEnum { - A: bool, - B: u64, -} +script; -impl core::ops::Eq for ConfigurableEnum { - fn eq(self, other: ConfigurableEnum) -> bool { - match (self, other) { - (ConfigurableEnum::A(inner1), ConfigurableEnum::A(inner2)) => inner1 == inner2, - (ConfigurableEnum::B(inner1), ConfigurableEnum::B(inner2)) => inner1 == inner2, - _ => false, - } - } +configurable { + BOOL: bool = true, } - -type AnotherU8 = u8; - - configurable { - BOOL: bool = true, - U8: u8 = 1, - ANOTHER_U8: AnotherU8 = 3, - U16: u16 = 2, - U32: u32 = 3, - U64: u32 = 4, - U256: u256 = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAu256, - B256: b256 = 0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB, - CONFIGURABLE_STRUCT: ConfigurableStruct = ConfigurableStruct { - a: true, - b: 5, - }, - CONFIGURABLE_ENUM_A: ConfigurableEnum = ConfigurableEnum::A(true), - CONFIGURABLE_ENUM_B: ConfigurableEnum = ConfigurableEnum::B(12), - ARRAY_BOOL: [bool; 3] = [true, false, true], - ARRAY_U64: [u64; 3] = [9, 8, 7], - TUPLE_BOOL_U64: (bool, u64) = (true, 11), - STR_4: str[4] = __to_str_array("abcd"), - } - fn main() { - assert(BOOL == true); - assert(U8 == 1); - assert(ANOTHER_U8 == 3); - assert(U16 == 2); - assert(U64 == 4); - assert(U256 == 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAu256); - assert(B256 == 0xBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB); - assert(CONFIGURABLE_STRUCT.a == true); - assert(CONFIGURABLE_STRUCT.b == 5); - assert(CONFIGURABLE_ENUM_A == ConfigurableEnum::A(true)); - assert(CONFIGURABLE_ENUM_B == ConfigurableEnum::B(12)); - assert(ARRAY_BOOL[0] == true); - assert(ARRAY_BOOL[1] == false); - assert(ARRAY_BOOL[2] == true); - assert(ARRAY_U64[0] == 9); - assert(ARRAY_U64[1] == 8); - assert(ARRAY_U64[2] == 7); - assert(TUPLE_BOOL_U64.0 == true); - assert(TUPLE_BOOL_U64.1 == 11); - assert(sha256_str_array(STR_4) == sha256("abcd")); - - // Assert address do not change - let addr_1 = asm(addr: __addr_of(&BOOL)) { - addr: u64 - }; - let addr_2 = asm(addr: __addr_of(&BOOL)) { - addr: u64 - }; - assert(addr_1 == addr_2); - } \ No newline at end of file +fn main() { + assert(BOOL == true); +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/test.toml index be5373ea994..69ed91a1f33 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/test.toml +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/configurable_consts/test.toml @@ -4,3 +4,6 @@ expected_result_new_encoding = { action = "return_data", value = "" } validate_abi = true expected_warnings = 6 unsupported_profiles = ["debug"] + +# check: $()NOT_USED: u8 = 1 +# nextln: $()This declaration is never used