From 032cd3b3b76d8afc442839e12b6d56b665b1c623 Mon Sep 17 00:00:00 2001 From: bing Date: Fri, 17 Mar 2023 01:15:55 +0000 Subject: [PATCH] refactor: deprecate `ConfigTimeConstant`s (#4298) ## Description Closes #3681 I meant to tackle #3077 first, but tackling #3681 first cleans up a lot of the code needed to make #3077 easier. This PR is mostly cleanup: - Completely removes usage of `ConfigTimeConstant` everywhere (in forc-pkg, sway-core, sway-type) - **(BREAKING)** Completely removes support for `[constants]` table in the manifest, which was using the `ConfigTimeConstant` struct. This change is breaking for app devs ([open issue](https://github.com/FuelLabs/sway-applications/issues/375)) and from a [quick search](https://github.com/FuelLabs/sway-applications/search?l=TOML&q=%5Bconstants%5D) on our sway-applications repo, there's a number of manifests still using the old version of configuration time constants. Consequentially, the above change also allowed us to cut down on other constructs like `ConstInjectMap` within forc-pkg, since the only thing we need to inject now are const CONTRACT_IDs - this cuts down quite a bit of now-redundant code. - As a result of the removal of `ConfigTimeConstant`, a few tests using that feature were also deleted. - Also updated the `configurable` example to be known as `configurable_constants` instead of `config_time_constant`. **This PR does not:** - Fix the manual creation of `CONTRACT_ID` const. To create the const, we still undergo manual parsing and type-checking and finally inserting into a `SymbolMap` manually. This will be handled in a separate PR to tackle #3077 Other than removal of a lot of code to do with CTC, the main change here that allows contract dependencies to still work here is instead of relying on the `ConstInjectMap` which we used to inject both constants and contract dependencies, there is now only a single contract ID value that we require (this is abstracted as `ContractIdConst`) to inject into the contract for tests. ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [x] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] I have added tests that prove my fix is effective or that my feature works. - [x] 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. --- docs/book/src/basics/variables.md | 10 +- examples/Forc.lock | 2 +- examples/Forc.toml | 2 +- .../Forc.toml | 2 +- .../src/main.sw | 0 forc-pkg/src/manifest.rs | 6 - forc-pkg/src/pkg.rs | 104 ++++------- forc-plugins/forc-client/src/op/deploy.rs | 2 - forc-plugins/forc-client/src/op/run.rs | 2 - forc-test/src/lib.rs | 2 - forc/src/ops/forc_build.rs | 2 - .../src/semantic_analysis/namespace/module.rs | 161 +++++++++--------- sway-error/src/error.rs | 16 +- sway-types/src/lib.rs | 7 - .../config_time_constants/Forc.lock | 3 - .../config_time_constants/Forc.toml | 11 -- .../json_abi_oracle.json | 16 -- .../config_time_constants/src/main.sw | 7 - .../config_time_constants/test.toml | 3 - .../Forc.lock | 3 - .../Forc.toml | 10 -- .../json_abi_oracle.json | 16 -- .../src/main.sw | 9 - .../test.toml | 3 - .../language/config_time_constants/Forc.lock | 3 - .../language/config_time_constants/Forc.toml | 12 -- .../json_abi_oracle.json | 25 --- .../config_time_constants/src/main.sw | 7 - .../language/config_time_constants/test.toml | 3 - 29 files changed, 131 insertions(+), 318 deletions(-) rename examples/{config_time_constants => configurable_constants}/Forc.toml (80%) rename examples/{config_time_constants => configurable_constants}/src/main.sw (100%) delete mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/Forc.lock delete mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/Forc.toml delete mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/json_abi_oracle.json delete mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/src/main.sw delete mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/test.toml delete mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/Forc.lock delete mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/Forc.toml delete mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/json_abi_oracle.json delete mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/src/main.sw delete mode 100644 test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/test.toml delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/Forc.lock delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/Forc.toml delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/json_abi_oracle.json delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/src/main.sw delete mode 100644 test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/test.toml diff --git a/docs/book/src/basics/variables.md b/docs/book/src/basics/variables.md index 698c4db7e2f..c72d00e38e8 100644 --- a/docs/book/src/basics/variables.md +++ b/docs/book/src/basics/variables.md @@ -44,14 +44,14 @@ let baz: bool = true; If the value declared cannot be assigned to the declared type, there will be an error generated by the compiler. -## Configuration-time Constants +## Configurable Constants -Configuration-time constants (or configurable constants) are special constants that behave like regular constants in the sense that they cannot change during program execution, but they can be configured _after_ the Sway program has been built. The Rust and TS SDKs allow updating the values of these constants by injecting new values for them directly in the bytecode without having to build the program again. These are useful for contract factories and behave somewhat similarly to `immutable` variables from languages like Solidity. +Configurable constants are special constants that behave like regular constants in the sense that they cannot change during program execution, but they can be configured _after_ the Sway program has been built. The Rust and TS SDKs allow updating the values of these constants by injecting new values for them directly in the bytecode without having to build the program again. These are useful for contract factories and behave somewhat similarly to `immutable` variables from languages like Solidity. -Configuration-time constants are declared inside a `configurable` block and require a type ascription and an initializer as follows: +Configurable constants are declared inside a `configurable` block and require a type ascription and an initializer as follows: ```sway -{{#include ../../../../examples/config_time_constants/src/main.sw:configurable_block}} +{{#include ../../../../examples/configurable_constants/src/main.sw:configurable_block}} ``` At most one `configurable` block is allowed in a Sway project. Moreover, `configurable` blocks are not allowed in libraries. @@ -59,5 +59,5 @@ At most one `configurable` block is allowed in a Sway project. Moreover, `config Configurable constants can be read directly just like regular constants: ```sway -{{#include ../../../../examples/config_time_constants/src/main.sw:using_configurables}} +{{#include ../../../../examples/configurable_constants/src/main.sw:using_configurables}} ``` diff --git a/examples/Forc.lock b/examples/Forc.lock index 39662ec4a2b..550a3da3400 100644 --- a/examples/Forc.lock +++ b/examples/Forc.lock @@ -23,7 +23,7 @@ source = 'member' dependencies = ['std'] [[package]] -name = 'config_time_constants' +name = 'configurable_constants' source = 'member' [[package]] diff --git a/examples/Forc.toml b/examples/Forc.toml index 59777e49ae0..b5cd948ee91 100644 --- a/examples/Forc.toml +++ b/examples/Forc.toml @@ -8,7 +8,7 @@ members = [ "asm_return_tuple_pointer", "break_and_continue", "cei_analysis", - "config_time_constants", + "configurable_constants", "counter", "enums", "fizzbuzz", diff --git a/examples/config_time_constants/Forc.toml b/examples/configurable_constants/Forc.toml similarity index 80% rename from examples/config_time_constants/Forc.toml rename to examples/configurable_constants/Forc.toml index 470462e250a..77093087307 100644 --- a/examples/config_time_constants/Forc.toml +++ b/examples/configurable_constants/Forc.toml @@ -3,6 +3,6 @@ authors = ["Fuel Labs "] entry = "main.sw" implicit-std = false license = "Apache-2.0" -name = "config_time_constants" +name = "configurable_constants" [dependencies] diff --git a/examples/config_time_constants/src/main.sw b/examples/configurable_constants/src/main.sw similarity index 100% rename from examples/config_time_constants/src/main.sw rename to examples/configurable_constants/src/main.sw diff --git a/forc-pkg/src/manifest.rs b/forc-pkg/src/manifest.rs index e11f48b1684..d38b56b1cb1 100644 --- a/forc-pkg/src/manifest.rs +++ b/forc-pkg/src/manifest.rs @@ -10,7 +10,6 @@ use std::{ }; use sway_core::{fuel_prelude::fuel_tx, language::parsed::TreeType, parse_tree_type, BuildTarget}; -pub use sway_types::ConfigTimeConstant; use sway_utils::constants; /// The name of a workspace member package. @@ -142,7 +141,6 @@ pub struct PackageManifest { pub dependencies: Option>, pub patch: Option>, /// A list of [configuration-time constants](https://github.com/FuelLabs/sway/issues/1498). - pub constants: Option>, pub build_target: Option>, build_profile: Option>, pub contract_dependencies: Option>, @@ -350,10 +348,6 @@ impl PackageManifestFile { } }) } - /// Getter for the config time constants on the manifest. - pub fn config_time_constants(&self) -> BTreeMap { - self.constants.as_ref().cloned().unwrap_or_default() - } /// Returns the workspace manifest file if this `PackageManifestFile` is one of the members. pub fn workspace(&self) -> Result> { diff --git a/forc-pkg/src/pkg.rs b/forc-pkg/src/pkg.rs index 936bc795999..1734577d1f9 100644 --- a/forc-pkg/src/pkg.rs +++ b/forc-pkg/src/pkg.rs @@ -1,9 +1,6 @@ use crate::{ lock::Lock, - manifest::{ - BuildProfile, ConfigTimeConstant, Dependency, ManifestFile, MemberManifestFiles, - PackageManifestFile, - }, + manifest::{BuildProfile, Dependency, ManifestFile, MemberManifestFiles, PackageManifestFile}, source::{self, Source}, CORE, PRELUDE, STD, }; @@ -20,7 +17,7 @@ use petgraph::{ }; use serde::{Deserialize, Serialize}; use std::{ - collections::{hash_map, BTreeMap, BTreeSet, HashMap, HashSet}, + collections::{hash_map, BTreeSet, HashMap, HashSet}, fmt, fs::{self, File}, hash::{Hash, Hasher}, @@ -270,8 +267,8 @@ pub struct MinifyOpts { pub json_storage_slots: bool, } -type ConstName = String; -type ConstInjectionMap = HashMap>; +/// Represents a compiled contract ID as a pub const in a contract. +type ContractIdConst = String; /// The set of options provided to the `build` functions. #[derive(Default)] @@ -298,8 +295,6 @@ pub struct BuildOpts { pub error_on_warnings: bool, /// Include all test functions within the build. pub tests: bool, - /// List of constants to inject for each package. - pub const_inject_map: ConstInjectionMap, /// The set of options to filter by member project kind. pub member_filter: MemberFilter, } @@ -396,14 +391,6 @@ impl BuildOpts { ..self } } - - /// Return a `BuildOpts` with modified `injection_map` field. - pub fn const_injection_map(self, const_inject_map: ConstInjectionMap) -> Self { - Self { - const_inject_map, - ..self - } - } } impl Edge { @@ -1539,19 +1526,26 @@ pub const CONTRACT_ID_CONSTANT_NAME: &str = "CONTRACT_ID"; /// /// This function also ensures that if `std` exists in the graph, /// then the std prelude will also be added. +/// +/// `contract_id_value` should only be Some when producing the `dependency_namespace` for a contract with tests enabled. +/// This allows us to provide a contract's `CONTRACT_ID` constant to its own unit tests. pub fn dependency_namespace( lib_namespace_map: &HashMap, compiled_contract_deps: &CompiledContractDeps, graph: &Graph, node: NodeIx, - constants: BTreeMap, engines: Engines<'_>, + contract_id_value: Option, ) -> Result> { // TODO: Clean this up when config-time constants v1 are removed. let node_idx = &graph[node]; let name = Some(Ident::new_no_span(node_idx.name.clone())); - let mut namespace = - namespace::Module::default_with_constants(engines, constants, name.clone())?; + let mut namespace = if let Some(contract_id_value) = contract_id_value { + namespace::Module::default_with_contract_id(engines, name.clone(), contract_id_value)? + } else { + namespace::Module::default() + }; + namespace.is_external = true; namespace.name = name; @@ -1567,7 +1561,6 @@ pub fn dependency_namespace( .cloned() .expect("no namespace module"), DepKind::Contract { salt } => { - let mut constants = BTreeMap::default(); let dep_contract_id = compiled_contract_deps .get(&dep_node) .map(|dep| contract_id(dep.bytecode.clone(), dep.storage_slots.clone(), &salt)) @@ -1575,16 +1568,13 @@ pub fn dependency_namespace( .unwrap_or_default(); // Construct namespace with contract id let contract_id_value = format!("0x{dep_contract_id}"); - let contract_id_constant = ConfigTimeConstant { - r#type: "b256".to_string(), - value: contract_id_value, - public: true, - }; - constants.insert(CONTRACT_ID_CONSTANT_NAME.to_string(), contract_id_constant); let node_idx = &graph[dep_node]; let name = Some(Ident::new_no_span(node_idx.name.clone())); - let mut ns = - namespace::Module::default_with_constants(engines, constants, name.clone())?; + let mut ns = namespace::Module::default_with_contract_id( + engines, + name.clone(), + contract_id_value, + )?; ns.is_external = true; ns.name = name; ns @@ -2025,7 +2015,6 @@ pub fn build_with_options(build_options: BuildOpts) -> Result { binary_outfile, debug_outfile, pkg, - const_inject_map, build_target, member_filter, .. @@ -2067,13 +2056,7 @@ pub fn build_with_options(build_options: BuildOpts) -> Result { // Build it! let mut built_workspace = Vec::new(); let build_start = std::time::Instant::now(); - let built_packages = build( - &build_plan, - *build_target, - &build_profile, - &outputs, - const_inject_map, - )?; + let built_packages = build(&build_plan, *build_target, &build_profile, &outputs)?; let output_dir = pkg.output_directory.as_ref().map(PathBuf::from); let finished = ansi_term::Colour::Green.bold().paint("Finished"); @@ -2172,7 +2155,6 @@ pub fn build( target: BuildTarget, profile: &BuildProfile, outputs: &HashSet, - const_inject_map: &ConstInjectionMap, ) -> anyhow::Result> { let mut built_packages = Vec::new(); @@ -2185,7 +2167,10 @@ pub fn build( let decl_engine = DeclEngine::default(); let engines = Engines::new(&type_engine, &decl_engine); let include_tests = profile.include_tests; - let mut const_inject_map = const_inject_map.clone(); + + // This is the Contract ID of the current contract being compiled. + // We will need this for `forc test`. + let mut contract_id_value: Option = None; let mut lib_namespace_map = Default::default(); let mut compiled_contract_deps = HashMap::new(); @@ -2235,13 +2220,15 @@ pub fn build( ..profile.clone() }; + // `ContractIdConst` is a None here since we do not yet have a + // contract ID value at this point. let dep_namespace = match dependency_namespace( &lib_namespace_map, &compiled_contract_deps, plan.graph(), node, - manifest.config_time_constants().clone(), engines, + None, ) { Ok(o) => o, Err(errs) => return fail(&[], &errs), @@ -2254,8 +2241,10 @@ pub fn build( &mut source_map, )?; - // If this contract is built because tests are enabled we need to insert CONTRACT_ID - // for the contract. + // If this contract is built because: + // 1) it is a contract dependency, or + // 2) tests are enabled, + // we need to insert its CONTRACT_ID into a map for later use. if is_contract_dependency { let compiled_contract_dep = CompiledContractDependency { bytecode: compiled_without_tests.bytecode.bytes.clone(), @@ -2269,34 +2258,14 @@ pub fn build( compiled_without_tests.storage_slots, &fuel_tx::Salt::zeroed(), ); - let contract_id_constant_name = CONTRACT_ID_CONSTANT_NAME.to_string(); - let contract_id_value = format!("0x{contract_id}"); - let contract_id_constant = ConfigTimeConstant { - r#type: "b256".to_string(), - value: contract_id_value.clone(), - public: true, - }; - let constant_declarations = vec![(contract_id_constant_name, contract_id_constant)]; - const_inject_map.insert(pkg.clone(), constant_declarations); + // We finally set the contract ID value here to use for compilation later if tests are enabled. + contract_id_value = Some(format!("0x{contract_id}")); } Some(compiled_without_tests.bytecode) } else { None }; - let constants = const_inject_map - .get(pkg) - .map(|injected_ctc| { - let mut constants = manifest.config_time_constants(); - constants.extend( - injected_ctc - .iter() - .map(|(name, ctc)| (name.clone(), ctc.clone())), - ); - constants - }) - .unwrap_or_else(|| manifest.config_time_constants()); - // Build all non member nodes with tests disabled by overriding the current profile. let profile = if !plan.member_nodes().any(|member| member == node) { BuildProfile { @@ -2307,17 +2276,19 @@ pub fn build( profile.clone() }; + // Note that the contract ID value here is only Some if tests are enabled. let dep_namespace = match dependency_namespace( &lib_namespace_map, &compiled_contract_deps, plan.graph(), node, - constants, engines, + contract_id_value.clone(), ) { Ok(o) => o, Err(errs) => return fail(&[], &errs), }; + let mut compiled = compile( &descriptor, &profile, @@ -2506,14 +2477,13 @@ pub fn check( for &node in plan.compilation_order.iter() { let pkg = &plan.graph[node]; let manifest = &plan.manifest_map()[&pkg.id()]; - let constants = manifest.config_time_constants(); let dep_namespace = dependency_namespace( &lib_namespace_map, &compiled_contract_deps, &plan.graph, node, - constants, engines, + None, ) .expect("failed to create dependency namespace"); diff --git a/forc-plugins/forc-client/src/op/deploy.rs b/forc-plugins/forc-client/src/op/deploy.rs index 17cdbef12ca..349affad9eb 100644 --- a/forc-plugins/forc-client/src/op/deploy.rs +++ b/forc-plugins/forc-client/src/op/deploy.rs @@ -148,7 +148,6 @@ pub async fn deploy_pkg( } fn build_opts_from_cmd(cmd: &cmd::Deploy) -> pkg::BuildOpts { - let const_inject_map = std::collections::HashMap::new(); pkg::BuildOpts { pkg: pkg::PkgOpts { path: cmd.pkg.path.clone(), @@ -177,7 +176,6 @@ fn build_opts_from_cmd(cmd: &cmd::Deploy) -> pkg::BuildOpts { debug_outfile: cmd.build_output.debug_file.clone(), build_target: BuildTarget::default(), tests: false, - const_inject_map, member_filter: pkg::MemberFilter::only_contracts(), } } diff --git a/forc-plugins/forc-client/src/op/run.rs b/forc-plugins/forc-client/src/op/run.rs index fbc5ae13c62..c37f0357b3a 100644 --- a/forc-plugins/forc-client/src/op/run.rs +++ b/forc-plugins/forc-client/src/op/run.rs @@ -144,7 +144,6 @@ async fn send_tx( } fn build_opts_from_cmd(cmd: &cmd::Run) -> pkg::BuildOpts { - let const_inject_map = std::collections::HashMap::new(); pkg::BuildOpts { pkg: pkg::PkgOpts { path: cmd.pkg.path.clone(), @@ -173,7 +172,6 @@ fn build_opts_from_cmd(cmd: &cmd::Run) -> pkg::BuildOpts { binary_outfile: cmd.build_output.bin_file.clone(), debug_outfile: cmd.build_output.debug_file.clone(), tests: false, - const_inject_map, member_filter: pkg::MemberFilter::only_scripts(), } } diff --git a/forc-test/src/lib.rs b/forc-test/src/lib.rs index 273faff5f51..a990aae78fa 100644 --- a/forc-test/src/lib.rs +++ b/forc-test/src/lib.rs @@ -347,7 +347,6 @@ impl<'a> PackageTests { impl Opts { /// Convert this set of test options into a set of build options. pub fn into_build_opts(self) -> pkg::BuildOpts { - let const_inject_map = std::collections::HashMap::new(); pkg::BuildOpts { pkg: self.pkg, print: self.print, @@ -360,7 +359,6 @@ impl Opts { error_on_warnings: self.error_on_warnings, time_phases: self.time_phases, tests: true, - const_inject_map, member_filter: Default::default(), } } diff --git a/forc/src/ops/forc_build.rs b/forc/src/ops/forc_build.rs index d593d078cac..4fcd58914f0 100644 --- a/forc/src/ops/forc_build.rs +++ b/forc/src/ops/forc_build.rs @@ -9,7 +9,6 @@ pub fn build(cmd: BuildCommand) -> Result { } fn opts_from_cmd(cmd: BuildCommand) -> pkg::BuildOpts { - let const_inject_map = std::collections::HashMap::new(); pkg::BuildOpts { pkg: pkg::PkgOpts { path: cmd.build.pkg.path, @@ -38,7 +37,6 @@ fn opts_from_cmd(cmd: BuildCommand) -> pkg::BuildOpts { debug_outfile: cmd.build.output.debug_file, build_target: cmd.build.build_target, tests: cmd.tests, - const_inject_map, member_filter: Default::default(), } } diff --git a/sway-core/src/semantic_analysis/namespace/module.rs b/sway-core/src/semantic_analysis/namespace/module.rs index 2164d69c413..d0ecf5260fc 100644 --- a/sway-core/src/semantic_analysis/namespace/module.rs +++ b/sway-core/src/semantic_analysis/namespace/module.rs @@ -14,12 +14,11 @@ use super::{ ModuleName, Path, }; -use std::collections::BTreeMap; use sway_ast::ItemConst; use sway_error::handler::Handler; use sway_error::{error::CompileError, handler::ErrorEmitted}; use sway_parse::{lex, Parser}; -use sway_types::{span::Span, ConfigTimeConstant, Spanned}; +use sway_types::{span::Span, Spanned}; /// A single `Module` within a Sway project. /// @@ -52,110 +51,102 @@ pub struct Module { } impl Module { - pub fn default_with_constants( + /// `contract_id_value` is injected here via forc-pkg when producing the `dependency_namespace` for a contract which has tests enabled. + /// This allows us to provide a contract's `CONTRACT_ID` constant to its own unit tests. + /// + /// This will eventually be refactored out of `sway-core` in favor of creating temporary package dependencies for providing these + /// `CONTRACT_ID`-containing modules: https://github.com/FuelLabs/sway/issues/3077 + pub fn default_with_contract_id( engines: Engines<'_>, - constants: BTreeMap, name: Option, + contract_id_value: String, ) -> Result> { let handler = <_>::default(); - Module::default_with_constants_inner(&handler, engines, constants, name).map_err(|_| { - let (errors, warnings) = handler.consume(); - assert!(warnings.is_empty()); + Module::default_with_contract_id_inner(&handler, engines, name, contract_id_value).map_err( + |_| { + let (errors, warnings) = handler.consume(); + assert!(warnings.is_empty()); - // Invariant: `.value == None` => `!errors.is_empty()`. - vec1::Vec1::try_from_vec(errors).unwrap() - }) + // Invariant: `.value == None` => `!errors.is_empty()`. + vec1::Vec1::try_from_vec(errors).unwrap() + }, + ) } - fn default_with_constants_inner( + fn default_with_contract_id_inner( handler: &Handler, engines: Engines<'_>, - constants: BTreeMap, ns_name: Option, + contract_id_value: String, ) -> Result { // it would be nice to one day maintain a span from the manifest file, but // we don't keep that around so we just use the span from the generated const decl instead. let mut compiled_constants: SymbolMap = Default::default(); // this for loop performs a miniature compilation of each const item in the config - for ( - name, - ConfigTimeConstant { - r#type, - value, - public, - }, - ) in constants.into_iter() - { - // FIXME(Centril): Stop parsing. Construct AST directly instead! - // parser config - let const_item = match public { - true => format!("pub const {name}: {type} = {value};"), - false => format!("const {name}: {type} = {value};"), - }; - let const_item_len = const_item.len(); - let input_arc = std::sync::Arc::from(const_item); - let token_stream = lex(handler, &input_arc, 0, const_item_len, None).unwrap(); - let mut parser = Parser::new(handler, &token_stream); - // perform the parse - let const_item: ItemConst = parser.parse()?; - let const_item_span = const_item.span().clone(); - - // perform the conversions from parser code to parse tree types - let name = const_item.name.clone(); - let attributes = Default::default(); - // convert to const decl - let const_decl = to_parsed_lang::item_const_to_constant_declaration( - &mut to_parsed_lang::Context::default(), - handler, - engines, - const_item, - attributes, - true, - )?; - - // Temporarily disallow non-literals. See https://github.com/FuelLabs/sway/issues/2647. - let has_literal = match &const_decl.value { - Some(value) => { - matches!(value.kind, ExpressionKind::Literal(_)) - } - None => false, - }; + // FIXME(Centril): Stop parsing. Construct AST directly instead! + // parser config + let const_item = format!("pub const CONTRACT_ID: b256 = {contract_id_value};"); + let const_item_len = const_item.len(); + let input_arc = std::sync::Arc::from(const_item); + let token_stream = lex(handler, &input_arc, 0, const_item_len, None).unwrap(); + let mut parser = Parser::new(handler, &token_stream); + // perform the parse + let const_item: ItemConst = parser.parse()?; + let const_item_span = const_item.span(); + + // perform the conversions from parser code to parse tree types + let name = const_item.name.clone(); + let attributes = Default::default(); + // convert to const decl + let const_decl = to_parsed_lang::item_const_to_constant_declaration( + &mut to_parsed_lang::Context::default(), + handler, + engines, + const_item, + attributes, + true, + )?; + + // Temporarily disallow non-literals. See https://github.com/FuelLabs/sway/issues/2647. + let has_literal = match &const_decl.value { + Some(value) => { + matches!(value.kind, ExpressionKind::Literal(_)) + } + None => false, + }; + + if !has_literal { + return Err(handler.emit_err(CompileError::ContractIdValueNotALiteral { + span: const_item_span, + })); + } - if !has_literal { + let ast_node = AstNode { + content: AstNodeContent::Declaration(Declaration::ConstantDeclaration(const_decl)), + span: const_item_span.clone(), + }; + let mut ns = Namespace::init_root(Default::default()); + // This is pretty hacky but that's okay because of this code is being removed pretty soon + ns.root.module.name = ns_name; + ns.root.module.is_external = true; + let type_check_ctx = TypeCheckContext::from_root(&mut ns, engines); + let typed_node = + ty::TyAstNode::type_check(type_check_ctx, ast_node).unwrap(&mut vec![], &mut vec![]); + // get the decl out of the typed node: + // we know as an invariant this must be a const decl, as we hardcoded a const decl in + // the above `format!`. if it isn't we report an + // error that only constant items are alowed, defensive programming etc... + let typed_decl = match typed_node.content { + ty::TyAstNodeContent::Declaration(decl) => decl, + _ => { return Err( - handler.emit_err(CompileError::ConfigTimeConstantNotALiteral { + handler.emit_err(CompileError::ContractIdConstantNotAConstDecl { span: const_item_span, }), ); } - - let ast_node = AstNode { - content: AstNodeContent::Declaration(Declaration::ConstantDeclaration(const_decl)), - span: const_item_span.clone(), - }; - let mut ns = Namespace::init_root(Default::default()); - // This is pretty hacky but that's okay because of this code is being removed pretty soon - ns.root.module.name = ns_name.clone(); - ns.root.module.is_external = true; - let type_check_ctx = TypeCheckContext::from_root(&mut ns, engines); - let typed_node = ty::TyAstNode::type_check(type_check_ctx, ast_node) - .unwrap(&mut vec![], &mut vec![]); - // get the decl out of the typed node: - // we know as an invariant this must be a const decl, as we hardcoded a const decl in - // the above `format!`. if it isn't we report an - // error that only constant items are alowed, defensive programming etc... - let typed_decl = match typed_node.content { - ty::TyAstNodeContent::Declaration(decl) => decl, - _ => { - return Err( - handler.emit_err(CompileError::ConfigTimeConstantNotAConstDecl { - span: const_item_span, - }), - ); - } - }; - compiled_constants.insert(name, typed_decl); - } + }; + compiled_constants.insert(name, typed_decl); let mut ret = Self::default(); ret.items.symbols = compiled_constants; diff --git a/sway-error/src/error.rs b/sway-error/src/error.rs index 7364390eb7a..4d0c2485a09 100644 --- a/sway-error/src/error.rs +++ b/sway-error/src/error.rs @@ -582,10 +582,14 @@ pub enum CompileError { BreakOutsideLoop { span: Span }, #[error("\"continue\" used outside of a loop")] ContinueOutsideLoop { span: Span }, - #[error("Configuration-time constant value is not a constant item.")] - ConfigTimeConstantNotAConstDecl { span: Span }, - #[error("Configuration-time constant value is not a literal.")] - ConfigTimeConstantNotALiteral { span: Span }, + /// This will be removed once loading contract IDs in a dependency namespace is refactored and no longer manual: + /// https://github.com/FuelLabs/sway/issues/3077 + #[error("Contract ID is not a constant item.")] + ContractIdConstantNotAConstDecl { span: Span }, + /// This will be removed once loading contract IDs in a dependency namespace is refactored and no longer manual: + /// https://github.com/FuelLabs/sway/issues/3077 + #[error("Contract ID value is not a literal.")] + ContractIdValueNotALiteral { span: Span }, #[error("The type \"{ty}\" is not allowed in storage.")] TypeNotAllowedInContractStorage { ty: String, span: Span }, #[error("ref mut parameter not allowed for main()")] @@ -785,8 +789,8 @@ impl Spanned for CompileError { IntrinsicIncorrectNumTArgs { span, .. } => span.clone(), BreakOutsideLoop { span } => span.clone(), ContinueOutsideLoop { span } => span.clone(), - ConfigTimeConstantNotAConstDecl { span } => span.clone(), - ConfigTimeConstantNotALiteral { span } => span.clone(), + ContractIdConstantNotAConstDecl { span } => span.clone(), + ContractIdValueNotALiteral { span } => span.clone(), TypeNotAllowedInContractStorage { span, .. } => span.clone(), RefMutableNotAllowedInMain { span, .. } => span.clone(), PointerReturnNotAllowedInMain { span } => span.clone(), diff --git a/sway-types/src/lib.rs b/sway-types/src/lib.rs index 264a71e45c7..daf70ae6aff 100644 --- a/sway-types/src/lib.rs +++ b/sway-types/src/lib.rs @@ -98,13 +98,6 @@ where } } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct ConfigTimeConstant { - pub r#type: String, - pub value: String, - #[serde(default)] - pub public: bool, -} impl AsRef for Source { fn as_ref(&self) -> &PathBuf { &self.path diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/Forc.lock deleted file mode 100644 index e86f3d60cdf..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/Forc.lock +++ /dev/null @@ -1,3 +0,0 @@ -[[package]] -name = 'config_time_constants' -source = 'member' diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/Forc.toml deleted file mode 100644 index 29976097474..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/Forc.toml +++ /dev/null @@ -1,11 +0,0 @@ -[project] -authors = ["Fuel Labs "] -license = "Apache-2.0" -name = "config_time_constants" -entry = "main.sw" -implicit-std = false - - -[constants] -# should fail because this is an invalid b256 -some_contract_addr = { type = "b256", value = "0x58cb6ee759d9be0c0f78d3ef24e1b59300c625b3c61999967366dbbebad31c" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/json_abi_oracle.json deleted file mode 100644 index 1bb99b0c14b..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/json_abi_oracle.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "attributes": null, - "inputs": [], - "name": "main", - "outputs": [ - { - "components": null, - "name": "", - "type": "u64", - "typeArguments": null - } - ], - "type": "function" - } -] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/src/main.sw deleted file mode 100644 index ebbb73de716..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/src/main.sw +++ /dev/null @@ -1,7 +0,0 @@ -script; - -fn main() -> u64 { - let addr = some_contract_addr; - - return 0; -} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/test.toml deleted file mode 100644 index a43910b8d11..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants/test.toml +++ /dev/null @@ -1,3 +0,0 @@ -category = "fail" - -# check: $()hex literals must have 1..16 or 64 digits diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/Forc.lock deleted file mode 100644 index 3777552627d..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/Forc.lock +++ /dev/null @@ -1,3 +0,0 @@ -[[package]] -name = 'config_time_constants_non_literal' -source = 'member' diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/Forc.toml deleted file mode 100644 index e1563152159..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/Forc.toml +++ /dev/null @@ -1,10 +0,0 @@ -[project] -authors = ["Fuel Labs "] -entry = "main.sw" -implicit-std = false -license = "Apache-2.0" -name = "config_time_constants_non_literal" - - -[constants] -some_contract_addr = { type = "S", value = "S { x:0 }" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/json_abi_oracle.json deleted file mode 100644 index 1bb99b0c14b..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/json_abi_oracle.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "attributes": null, - "inputs": [], - "name": "main", - "outputs": [ - { - "components": null, - "name": "", - "type": "u64", - "typeArguments": null - } - ], - "type": "function" - } -] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/src/main.sw deleted file mode 100644 index 8aabc097e89..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/src/main.sw +++ /dev/null @@ -1,9 +0,0 @@ -script; - -struct S { - x: u64, -} - -fn main() -> S { - s -} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/test.toml deleted file mode 100644 index f076360dd5a..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_fail/config_time_constants_non_literal/test.toml +++ /dev/null @@ -1,3 +0,0 @@ -category = "fail" - -# check: $()Configuration-time constant value is not a literal. diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/Forc.lock deleted file mode 100644 index e86f3d60cdf..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/Forc.lock +++ /dev/null @@ -1,3 +0,0 @@ -[[package]] -name = 'config_time_constants' -source = 'member' diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/Forc.toml deleted file mode 100644 index 8659937e3b6..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/Forc.toml +++ /dev/null @@ -1,12 +0,0 @@ -[project] -authors = ["Fuel Labs "] -license = "Apache-2.0" -name = "config_time_constants" -entry = "main.sw" -implicit-std = false - - -[constants] -some_contract_addr = { type = "b256", value = "0x580acb6ee759d9be0c0f78d3ef24e1b59300c625b3c61999967366dbbebad31c" } -some_num = { type = "u64", value = "42" } -true_bool = { type = "bool", value = "true" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/json_abi_oracle.json deleted file mode 100644 index ad50b55d54c..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/json_abi_oracle.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "configurables": [], - "functions": [ - { - "attributes": null, - "inputs": [], - "name": "main", - "output": { - "name": "", - "type": 0, - "typeArguments": null - } - } - ], - "loggedTypes": [], - "messagesTypes": [], - "types": [ - { - "components": null, - "type": "u64", - "typeId": 0, - "typeParameters": null - } - ] -} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/src/main.sw deleted file mode 100644 index c263e97a829..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/src/main.sw +++ /dev/null @@ -1,7 +0,0 @@ -script; - -fn main() -> u64 { - let addr = some_contract_addr; - - return if true_bool { some_num } else { 0 } ; -} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/test.toml deleted file mode 100644 index b7a79f9a8c0..00000000000 --- a/test/src/e2e_vm_tests/test_programs/should_pass/language/config_time_constants/test.toml +++ /dev/null @@ -1,3 +0,0 @@ -category = "run" -expected_result = { action = "return", value = 42 } -validate_abi = true